为什么要做错误处理
- 页面报太多错误信息,用户会觉得你的网站特别不专业、不权威
- 会暴露别人攻击系统的有效信息.譬如数据库信息、项目目录
- 项目开发的过程中快速准确地定位到异常、错误
一、PHP错误级别
Parse error
> Fatal Error
> Waning
> Notice
> Deprecated
1、deprecated 最低级别的错误
使用一些过期函数的时候会出现,程序继续执行
$pattern = '[0-9]+';
$subject = 100;
//$int = preg_match($pattern,$subject);
$int = eregi($pattern,$subject);
var_dump($int);
//PHP官方指出,PHP5.3不推荐使用eregi函数,建议使用preg_match函数代替。
Deprecated
关于 性能测试 问题
$date = date('Y-m-d');
$start = microtime(true);
for ($i = 0; $i < 10000; $i++)
{
if ( eregi ( "([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})" , $date , $regs )) {
//echo " $regs[3] . $regs[2] . $regs[1] " ;
} else {
//echo "Invalid date format: $date " ;
}
}
$end = microtime(true);
echo $end - $start.'<hr/>';
############################################################
$start = microtime(true);
for ($i = 0; $i < 10000; $i++)
{
if ( preg_match( "/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/" , $date , $regs )) {
//echo " $regs[3] . $regs[2] . $regs[1] " ;
} else {
//echo "Invalid date format: $date " ;
}
}
$end = microtime(true);
echo $end - $start.'<hr/>';
2、notice 通知级别的错误
使用一些未定义变量、常量或者数组key没有加引号的时候出现,不影响程序继续执行
echo $a; //打印一个未定义
echo string; //string 会把当成常量
echo $array[name]; //name 会把当成常量
3、Warning 警告级别的错误
程序出问题,需要修改代码!也不影响程序继续执行
settype($var, 'init');
//Warning: settype(): Invalid type in
4、致命错误
【后面程序不执行】
4.1、fatal-error 致命级别的错误
程序直接报错,需要修改代码。
test('123');// 调用致命的错误。运行中
//Fatal error: Call to undefined function test()
4.2、parse error 语法解析错误
语法检查阶段报错,需要修改代码 属于高级的error错误,代码检查阶段中发现
echo 'nie ge'
//Parse error: syntax error, unexpected
5、E_USER相关的相关错误
用户自定义的错误,用户手动抛出错误。由用户自己在代码中使用PHP函数 trigger_error() 来产生的。
header('content-type:text/html;charset=utf-8');
if(!defined('JACK')){
trigger_error('系统遇到意想不到的惊喜!');
}
二、错误处理
项目上线后 务必关闭所有可能出现的错误,使用抑制符
@
来屏蔽敏感的错误信息,利用日志程序生成运行日志的详细信息。
1、显示或关闭错误信息
-
修改php.ini 开启 display_errors
display_errors = On
- 使用ini_set()函数 允许脚本临时覆盖PHP配置文件中的设置
ini_set ('display_errors', 1);
2、设置报告
值 | 常量 | 说明 |
---|---|---|
1 | E_ERROR | 报告导致脚本终止运行的致命错误 |
2 | E_WARNING | 报告运行时的警告类错误(脚本不会终止运行) |
4 | E_PARSE | 报告编译时的语法解析错误 |
8 | E_NOTICE | 报告通知类错误,脚本可能会产生错误 |
2048 | E_STRICT | PHP5+,代码可以运行,但是php不建议这样写 |
32767 | E_ALL | 报告所有的可能出现的错误(不同的PHP版本,常量E_ALL的值也可能不同) |
function change(&$var){
$var += 10;
}
$var = 1;
change(++$var);
-
在php.ini配置文件里设置error_reporting级别
; Default Value: E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED ; Development Value: E_ALL ; Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT 生产环境 ; http://php.net/error-reporting error_reporting = E_ALL & ~E_NOTICE
- 使用error_reporting()函数
error_reporting (0); //不需要报告任何错误 error_reporting (E_ALL); //报告所有错误 error_reporting (E_ALL & ~E_NOTICE); //除了notice以外报告所有
3、使用 die() 函数处理
- 在设计工具类和工具函数时,
die()
/exit()
应该严令禁止,因为它们无权决定整个程序的生死。 - 确实确定业务已经结束的情况下使用,其他情况,最好禁止使用
if(!file_exists("jack.txt")) { die("文件不存在");//也可以exit,只是名字不同,效果都是一样的 }else{ $file=fopen("jack.txt","r"); }
4、使用trigger_error函数触发PHP错误
trigger_error()
产生一个用户级别的 error/warning/notice 信息,
$num1 = 123;
$num2 = '2a';
if( !is_numeric($num1) || !is_numeric($num2) ){
echo trigger_error('两个值必须都是数值',E_USER_NOTICE);
}
function getCommandObject($cmd) {
$path = "{$cmd}.php";
if (!file_exists($path)) {
trigger_error("Cannot find $path", E_USER_ERROR);
}
require_once $path;
if (!class_exists($cmd)) {
trigger_error("class $cmd does not exist", E_USER_ERROR);
}
$ret = new $cmd();
if (!is_a($ret, 'Command')) {
trigger_error("$cmd is not a Command", E_USER_ERROR);
}
return $ret;
}
getCommandObject('user');
5、函数set_error_handler()
该函数是指定出现报错的时候,指向我们自定义的错误处理函数;
代码参考:
ini_set('display_errors',0);
$debug = 1;
// 自定义错误处理函数
function myErrorHandler($e_number, $e_message, $e_file, $e_line, $e_vars)
{
global $debug;
$message = "脚本 <strong>{$e_file}</strong> 中出现错误在第<span style=\"color:red;\">{$e_line}</span>行: $e_message";
if ($debug) {
echo '<div style="width:90%;padding:10px;border:1px solid green;">' . $message . '</div>';
}
}
set_error_handler('myErrorHandler');
6、函数error_log
error_log函数:专门用于日记记录。
- 0:通过PHP标准的错误处理机制来记录;
- 1:邮件发生到指定的地方;
- 3:使用指定的文件记录错误报告日志
如果使用自己指定的文件记录错误日志,一定要确保将这个文 件存放在文档根目录之外,以减少遭到攻击的可能。并且该文件一定要让PHP脚本的执行用户(Web服务器进程所有者)具有写权限
php.ini配置:
//将会向PHP报告发生的每个错误
error_reporting = E_ALL;
//不显示满足上条 指令所定义规则的所有错误报告
display_errors = Off;
//开关
log_errors = On;
//设置每个日志项的最大长度
log_errors_max_len = 1024 ;
//指定产生的 错误报告写入的日志文件位置
error_log = /usr/local/errors.log;
7、register_shutdown_function函数
register_shutdown_function(function (){
var_dump(error_get_last());
});
#demo();
if( 1 ){
exit('hehe');
}
register_shutdown_function
捕获PHP的错误:fatal error,Parse Error等,这个方法是PHP脚本执行结束的最后调用的函数,比如脚本错误die(),exit(),异常、正常结束都会调用。
通过这个函数就可以在脚本结束前判断这次执行是否有错误产生。这时就要借助于一个函数:error_get_last()
;这个函数可以拿到本次执行产生的所有的错误
array (size=4)
'type' => int 1
'message' => string 'Call to undefined function demo()' (length=33)
'file' => string 'D:\study\error\demo.php' (length=23)
'line' => int 14
demo.php
register_shutdown_function(function (){
$error = error_get_last();
var_dump($error);
if($error!==null){
$logInfo = date('Y-m-d H:i:s');
$logInfo .= "文件:{$error['file']} ,在页面的第{$error['line']},报了一个{$error['type']},具体错误信息是:{$error['message']}";
$dir = MESSAGE.DS.date('Y').DS.date('m').DS.date('d');
var_dump(file_exists($dir));
var_dump($dir);
var_dump(getcwd());
var_dump(__DIR__);
if(!file_exists($dir)){
mkdir($dir,0777,true);
}
file_put_contents($dir.DS.'error.log', $logInfo.PHP_EOL,FILE_APPEND);
}
});
include_once 'other.php';//出现语法错误