前言
在PHP中,如果代码发生错误,PHP默认会把错误信息直接输出到页面,如下图:
这样会将敏感信息暴露给用户,十分不安全,因此通常会使用set_error_handler设置一个自定义的错误处理函数,在此函数中我们可以对发生的错误做出统一处理,例如将错误信息记录到日志、结束脚本运行等等:
set_error_handler(function($errno, $errstr, $errfile, $errline) {
$errInfo = [$errno, $errstr, $errfile, $errline];
// 记录错误信息到日志文件
file_put_contents('/path/to/file.log', json_encode($errInfo), FILE_APPEND);
// 结束脚本运行
exit();
});
// 使用一个未定义的变量,会触发E_NOTICE级别错误
echo $bar;
设置了错误处理函数后,PHP会将错误交由此函数处理,而且这些错误都不会显示在页面上,即使error_reporting设置为了E_ALL
。
注1:除了设置error_handler函数这种方法外,还可以通过配置php.ini的display_erros、log_errors、error_log参数来屏蔽网页中显示的错误信息。
注2:如果在代码中使用了 @ 错误抑制符,发生的错误仍然会被传递给error_handler函数处理,且在PHP 8(不含)之前的版本中,使用了 @ 抑制符后,在error_handler中调用error_reporting()函数获取到的值将会是0
注3:在error_handler中返回false会重新把此错误抛回给PHP标准错误处理程序做处理
但是这样就足够了吗?答案是不足够。因为有部分错误PHP并不会交给error_handler
函数处理,例如E_ERROR
级别的错误,下面见一个例子:
set_error_handler(function($errno, $errstr, $errfile, $errline) {
echo "Caught an error in error handler function!";
exit();
});
// 调用未定义的函数,会触发E_ERROR级别错误
call_undefined_func();
执行上述代码后:
因为E_ERROR
级别的错误没有交给error_handler
函数处理,所以PHP又把它显示在了页面上,那这时候可以怎样处理呢?
如果你使用的是PHP 5.x版本,那么可以结合使用register_shutdown_function和error_get_last函数来捕获这个错误,但这函数只能捕获错误,并不能把错误信息从页面上隐藏,我们可以使用@
错误抑制符或关闭error_reporting
或ini_set('display_errors', 'Off')
来隐藏错误信息,代码如下:
register_shutdown_function(function() {
$lastErr = error_get_last();
if ($lastErr !== null) {
echo "Caught error in shutdown function!";
exit();
}
});
// 方法1:关闭error_reporting
error_reporting(0);
// 方法2:关闭display_errors
// ini_set('display_errors', 'Off');
// 调用未定义的函数,会触发E_ERROR级别错误
call_undefined_func();
如果你使用的是PHP 7.x版本,那么可以使用set_exception_handler来捕获E_ERROR
错误:
set_exception_handler(function($e) {
echo "Caught error in exception handler function!";
exit();
});
// 调用未定义的函数,会触发E_ERROR级别错误
call_undefined_func();
结论
建议同时set_error_handler
、set_exception_handler
、register_shutdown_function
来捕获错误和异常。