目录
0x00 错误与异常
错误:语法错误,编译错误
异常:逻辑上的错误,即按照我们的逻辑不应该出现,但是仍然出现的错误。
错误级别:
E_ALL:所有的错误值
E_ERROR:致命的运行时错误 1 Fatal Error 例如重复定义函数。
E_PARSE:编译时的解析错误
E_WARNING:警告,例如引入了一个不存在的文件。
E_NOTICE:运行时的提醒,通常是逻辑上的错误。例如,使用了一个未定义的变量
E_USER_EROOR:用户自定义的致命错误
E_USER_WARING:用户自定义的警告
E_USER_NOTICE:用户自定义的提醒
deprecated:废弃的,表示你用了比较老的,已经废弃的东西。
0x01 用户自定义错误
<?php
set_error_handler('Produce_Error',E_ALL);
function Produce_Error($a,$b,$c,$d){
echo '这是我定义的错误处理函数';
echo '<br/>';
echo '错误级别'.$a;
echo '<br/>';
echo '错误信息:'.$b;
echo '<br/>';
echo '发生错误的脚本的绝对路径'.$c;
echo '<br/>';
echo '错误行号:'.$d;
echo '<br/>';
}
echo $a;
?>
trigger_error(“自定义错误提示”,错误提示类型)
错误提示类型:E_USER_ERROR,E_USER_NOTICE(默认),E_USER_PARSE,E_USER_WARNING
trigger_error(“我是用户自定义的错误”,);
E_USER_NOTICE错误之后的代码仍然可以执行。
注册错误处理函数:
set_error_handler(”错误处理函数名“,E_ALL);
例如:
上线前需要错误显示,来修改代码,上线后则必须屏蔽掉错误的显示,屏蔽错误显示的方法有以下几种:
第一种:错误抑制符@
可以控制notice 和warning的错误
不推荐这样用。最好的方法就是不要出现错误
1.脚本中
在哪个脚本中设置,只在哪个脚本中生效。
脚本中的配置优先于配置文件中的配置。
Ini_set(‘display_errors’,true);//true或者1表示展示错误
Ini_set(‘display_errors’,false);//false 或者0表示不展示错误
例如:
修改错误级别:
首先打开错误显示,然后限定只报告ERROR错误和NOTICE错误。
在所有php脚本中都生效。
打开php.ini,修改:
Development Value:On//开发环境中打开
Production Value:Off//生产环境即线上环境关闭。
display error = On
error_reporting = E_ALL表示报告所有错误,前提是display error打开。可以修改此选项,只报告特定的错误。
然后重启
0x02 错误的显示控制:
<?php
echo @$a;
@include_once 'lalala.php';
?>
第二种修改错误的级别
<?php
ini_set('display_errors',false);
echo $a;
include_once 'lalala.php';
?>
注意:这个不能屏蔽解析错误,因为解析错误是在代码执行之前,解析时报的错误,这个时候代码还没有执行,所以屏蔽错误的语句还没有生效。
<?php
ini_set('display_errors',true);
error_reporting(E_ERROR|E_NOTICE);
echo $a;
include_once 'lalala.php';
?>
2.修改配置文件
<?php
try{
echo 'before','<br/>';
throw new Exception('我是一个异常信息');//Exception是一个内置的类。throw关键字用于抛出异常
//改变执行流程
echo 'after'.'<br/>';
}catch(Exception $e){//Exception用于限定$e的类型,即限定$e必须是Exception的一个对象
echo $e->getMessage();//打印收到的异常信息。
echo '执行流程已改变';
}
?>
0x03 记录错误日志
在php.ini中配置:
log_errors = On;
Error_log = php_error.log //表示错误日志存储到php_error.log这个文件中,可以修改该文件名称。
默认在脚本的同源文件夹中保存该文件。
在脚本中可以向错误日志中写入自定义的错误。
error_log(‘自定义的错误信息,自动发送到错误日志’,0); //0默认向系统日志中写。系统日志就是上文中提到的那个日志
Error_log('自定义错误信息’,3,’xxx.txt’);3表示向自定义的xxx.txt中写入错误信息。
0x04 异常
自定义的异常类必须继承系统的异常类
一次请求一次响应就是一个会话
0x05自定义异常类
<?php
class MyException extends Exception{
public function test(){
echo '这是自定义的异常类';
}
}
try{
throw new MyException('这是自定义的异常类');
}catch(MyException $mye){
echo $mye->test();
}
?>
0x06 会话
其中path限定了cookie什么情况下被发送。
如果设置为true,那么只能通过http请求的方式获得cookie,例如:js的document.cookie这种方式就不能输出httponly属性为true的cookie行了。
<?php
setcookie('only','189',time()+3600,"/","",false,true);
?>
<?php
var_dump($_COOKIE);
echo '<script>alert(document.cookie);</script>'
?>
删除cookie
0x07 Cookie
1.cookie的原理
cookie存储在客户端(浏览器)
但是cookie是服务器生成的一小段ASCII文本,然后将cookie存到http响应的set-cookie键值对发给浏览器,设置浏览器的cookie
当浏览器收到这段文本后,会以键值对的形式将cookie存在本地的一个目录下。
当浏览器下一次向同一个服务器发送请求的时候,就会将本地存储的cookie加入http请求的cookie键值对发给服务器。
Cookie值会自动存入服务器的php脚本的$_COOKIE数组中。
注意:$_COOKIE数组只有当请求中有cookie键值对的时候,才会被填充数据。也就是说如果在同一个脚本中setcookie和var_dump($COOKIE)。
那么第一次请求这个页面的时候,是不会打印出$COOKIE的。因为第一次请求中并没有cookie键值对。
2.cookie的使用
setcookie(name,value)设置cookie的键和值,如果没有指定第三个参数(删除cookie的时间),默认为当关闭浏览器后自动删除cookie
setcookie(’name’,’xiaoming’,time()+60*60) 第三个参数的单位为s
设置cookie的过期时间(expires)为设置成功之后的1个小时后,即便是关闭浏览器,只要没有到cookie的过期时间,cookie还会存在我们的客户端。
time()返回的当前时间的时间戳,
即请求/Company目录下的任何一个php文件时,该cookie(number:189)都会被包在请求中发送
请求/(服务器公开根目录)下的任何一个php文件时,该cookie(name:xiaoming)都会被包在请求中发送
也就是说
在setcookie函数中,如果不设置path参数,那么默认cookie的发送范围就是当前文件夹。
设置path:
Setcookie(’name’,’dahua’,time()+7*24*3600,’\’);设置cookie的path属性为公开根目录,也就是说,不论请求公开目录(及其子目录)下那个php文件,这个cookie都会被带在请求中发过去。
setcookie函数的第五个参数是域名Domain,建议设置为”“,表示当前域名
第六个参数设置https,如果设置为1或者true,表示该cookie只能以https的方式来设置。如果不是https,那么就会设置失败。0表示关闭
第七个参数设置httponly,默认为false或者空,
3.删除cookie的方法
方法一:将值设置为空
setcookie(要删除的cookie名,’’,time()-1,以前在哪个路径下设置的就要在哪个路径下删)
或者setcookie(要删除的cookie名.null,time()-1,path)
方法二:
unset($_COOKIE['name'])这种方式最好不要用,有坑。
0x08 SESSION
1.session原理:
session值 == 超市门前储物柜里存放的东西 >>打印出来一个条形码session_id
将session_id以cookie的形式存起来
即 session的存取依靠于cookie
session值存在服务器上。
session_id以cookie的形式存在客户端。
2.session使用
setSession.php
step1.先启动session:
<?php
session_start();
?>
启动session时服务器会做两个操作:
1.在服务器端生成文件sess(存在公开目录下的tmp文件夹中),大小为0KB,里面是空的,将来要存我们设置的session值。该文件的文件名由sess_'sessionID'组成。例如:sess_snrkjg35mrt0fmtt7a37uqdavn
2.在客户端设置cookie,即响应报文的set-cookie字段 :PHPSESSID = snrkjg35mrt0fmtt7a37uqdavn
step2.赋值
<?php
//setSession.php
session_start();
$_SESSION['username'] = 'xiaoming';
?>
该session值将会被存入sess文件中
step3.访问
例如:
可以在同一个文件访问它,也可以在另一文件比如printSession.php来访问它。同样,在访问前也必须session_start()
<?php
//printSession.php
session_start();
echo $_SESSION['username'];
?>
当浏览器请求printSession.php的时候,请求头中cookie字段中便存有session_id。服务器接到请求后,根据session_id去寻找服务器上对应的sess文件。然后将sess文件中存储的值响应给浏览器。
一旦session_id被删除,那么请求printSesson.php时,cookie字段中就没有session_id。服务器收到请求后更无法找到对应的sess文件。也无法将值返回给浏览器。
session_id被删除后,再次请求setSession.php文件,将重新设置session_id;
同一台终端的不同浏览器,请求setSession.php文件,在服务器端将为每个浏览器生成各自的sess文件。并且返回各自的session_id存在各个浏览器上。
3.删除session
deleteSession.php
<?php
session_start();
session_destroy();
?>
这种方式直接删除了整个sess的文件(并不会删除客户端的存储session_id的cookie,要删除此cookie,需要我们自己手动删除)。但是如果我们只想删除sess文件中的一个键值对呢?
<?php
session_start();
unset($_SESSION['user']);
?>
这种方式只删除session文件中,索引为user的session值,不会删除其他的数据。
4.如何在php脚本中输出session_id的cookie键值对呢?
<?php
session_start();
echo session_name();//key
echo '<br/>';
echo session_id();//value
echo '<br/>';
?>
0x09 关闭Cookie怎么办?
关闭cookie的方法:
FireFox 首选项>>隐私与安全>>Cookie>>权限管理>>输入网址,可以禁止访问该网址时使用cookie
关闭cookie,只是禁止在请求头中发送cookie字段。并没有禁止响应头中set-Cookie字段。也就是说服务器仍然可以设置浏览器上的cookie,但是浏览器不能向服务器发送cookie
当浏览器关闭cookie后,session还能用吗?
能!
当关闭cookie后,setSession.php可以正常运行,设置浏览器上的cookie,向sess文件中存值。但是,如果反复请求setSession.php,将会更新浏览器上的cookie(即session_id),并在服务器上生成新的sess文件。
因为反复请求setSession时,本应该发送第一次设置好的session_id。这样服务器就知道session_id已经设置好了。但是,因为关闭了cookie。所以,不能成功发送。所以,服务器认为session_id并没有设置成功,所以生成了新的sess文件,并在set-cookie中存了新的session_id.
<?php
//setSession.php
session_start();
$_SESSION['username'] = 'xiaoming';
$_SESSION['pwd'] = '23141';
?>
解决方法:
getSession.php
<?php
//printSession.php
session_id('snrkjg35mrt0fmtt7a37uqdavn');//对应的session_id
session_start();
echo $_SESSION['username'];
?>
这样一来就不需要浏览器向服务器发送session_id了。直接请求该printSession脚本,脚本中就存了session_id.
完整版解决方案:
用get传参发送session_id.
<?php
//setSession.php
session_start();
$_SESSION['username'] = 'xiaoming';
$session_id = session_id();
echo "<a href = 'printSession.php?sid=".$session_id."'>发送session_id</a>";
?>
printSession.php
<?php
//printSession.php
session_id($_GET['sid']);//对应的session_id
session_start();
echo $_SESSION['username'];
?>
0x0A关于session的配置
php.ini中
session.save_handler = files
表示session值存在sess文件中。以后可以修改为Redis数据库。
session.save_path=‘C:\xxx\xxx\xxx’;
表示服务器上sess文件存储的位置,可以自定义;
session.name = PHPSESSID
表示session_id的cookie的键是PHPSESSID,可以修改
session.auto_start = 0
表示每次都需要手动输入session_start.可以修改为1.以后就不需要session_start了。但是不建议这样搞
0x0B session和cookie的区别:
session值存在服务端,cookie存在客户端
session存储的大小可以说没限制,cookie最大为4KB
session安全一些。cookie相对不安全
session的存取基于cookie。但是cookie关闭后,session照样可以用。
0x0C 用户登录实战
流程:
- 用户输入用户名,密码
- 用户名和密码正确,设置session,跳转到用户中心
- 如果错误,跳转到登录页面。
忘了说明你敲得说,敲个几百遍,绝对忘不了。
php中header("Location:路径")函数可以用来跳转页面。
login.html
<!DOCTYPE html>
<html>
<head>
<meta charset = 'utf-8'/>
</head>
<body>
<form action="login.php" method = "post">
用户名:<input type="text" name="username" id=""/><br/>
密码:<input type="password" name="password" id=""><br/>
<input type = "submit" value = "登录"/><br/>
</form>
</body>
</html>
login.php
<?php
//var_dump($_POST);
$user_name = $_POST['username'];
$password = $_POST['password'];
if($user_name == 'XDU' && $password == '123456'){
echo '登录成功';
session_start();
$_SESSION['username'] = $user_name;
header('Location:user.php?username='.$user_name);
}else{
echo '失败';
}
?>
user.php用户中心
为什么要先判断$_SESSION['username']是否存在呢?因为如果不判断,用户可以从url栏中输入用户中心的网址,直接跳过登录,访问用户中心。
凡是正常登录的用户,必然会存一个session值。我们只要判断有没有这个session值,就可以将正常登录用户和非正常访问用户中心的用户区分开。
<?php
session_start();
if(isset($_SESSION['username'])){
$user_name = $_GET['username'];
echo $user_name.',欢迎到用户中心!';
echo '<a href="logout.php">退出</a>';
}else{
header('Location:login.html');
}
?>
logout.php
<?php
session_start();
unset($_SESSION['username']);
header('Location:login.html');
?>