提醒:
这里讨论的终止性错误指导致php执行失败的错误,例如E_Error,像E_NOTICE、E_WARNING这样的报错Codeigniter框架本身可以完美的捕获,因此不在讨论范围内。
本文主要要说的是, 一些程序上的问题导致程序出现500错误,并捕获错误,记录到log日志中,如下图包含语法错误,和数据库连接导致的500程序中断错误,方便我们查找问题并解决
Codeigniter 2.x错误捕获机制
Codeigniter 2.x非常简单,通过“set_error_handler”这个函数将整体php运行过程中的错误捕获到框架本身的一个函数中。
Codeigniter 2.2 system/core/CodeIgniter.php line:73
/*
* ------------------------------------------------------
* Define a custom error handler so we can log PHP errors
* ------------------------------------------------------
*/
set_error_handler('_error_handler');
Codeigniter 2.2 system/core/Common.php line:446
if ( ! function_exists('_error_handler'))
{
function _error_handler($severity, $message, $filepath, $line)
{
// We don't bother with "strict" notices since they tend to fill up
// the log file with excess information that isn't normally very helpful.
if ($severity == E_STRICT)
{
return;
}
$_error =& load_class('Exceptions', 'core');
// Should we display the error? We'll get the current error_reporting
// level and add its bits with the severity bits to find out.
if (($severity & error_reporting()) == $severity)
{
$_error->show_php_error($severity, $message, $filepath, $line);
}
// Should we log the error? No? We're done...
if (config_item('log_threshold') == 0)
{
return;
}
$_error->log_exception($severity, $message, $filepath, $line);
}
}
然而set_error_handler无法记录终止性错误,这也是Codeigniter无法记录终止性错误的原因,请看php manual上关于这个函数的一个注解。
The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.
解决方案
通过“register_shutdown_function”和“set_exception_handler”两个函数分别捕获终止性错误和未捕获的异常错误。
第一步
在system/core/CodeIgniter.php line:73处增加两行代码:
set_exception_handler('_exception_handler');
register_shutdown_function('_shutdown_handler');
- 1
- 2
第二步
在system/core/CodeIgniter.php line:495行添加下面两个函数:
if ( ! function_exists('_exception_handler'))
{
/**
* Exception Handler
*
* Sends uncaught exceptions to the logger and displays them
* only if display_errors is On so that they don't show up in
* production environments.
*
* @param Exception $exception
* @return void
*/
function _exception_handler($exception)
{
$_error =& load_class('Exceptions', 'core');
$_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
// Should we display the error?
if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors'))) //这里还会遵循入口文件中的错误是否显示
{
$_error->show_exception($exception);
}
exit(1); // EXIT_ERROR
}
}
if ( ! function_exists('_shutdown_handler'))
{
/**
* Shutdown Handler
*
* This is the shutdown handler that is declared at the top
* of CodeIgniter.php. The main reason we use this is to simulate
* a complete custom exception handler.
*
* E_STRICT is purposivly neglected because such events may have
* been caught. Duplication or none? None is preferred for now.
*
* @link http://insomanic.me.uk/post/229851073/php-trick-catching-fatal-errors-e-error-with-a
* @return void
*/
function _shutdown_handler()
{
$last_error = error_get_last();
if (isset($last_error) &&
($last_error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING)))
{
error_reporting(E_ERROR|E_PARSE); //设置错误级别
_error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
}
}
}
第三步
语法错误造成的程序中断 500错误,也会记录到日志中哦!
打开日志看看吧
记录一下 error_reporting() 函数对应的错误级别
数字 | 常量 | 说明 |
1 | E_ERROR | 致命错误,脚本执行中断,就是脚本中有不可识别的东西出现 举例: Error:Invalid parameters. Invalid parameter name |
2 | E_WARNING | 部分代码出错,但不影响整体运行 举例: Warning: require_once(E:/include/config_base.php) |
4 | E_PARSE | 字符、变量或结束的地方写规范有误 举例: Parse error: syntax error, unexpected $end in |
8 | E_NOTICE | 一般通知,如变量未定义等 举例: Notice: Undefined variable: p in E:\web\index.php on line 17 |
16 | E_CORE_ERROR | PHP进程在启动时,发生了致命性错误 举例: 暂无 |
32 | E_CORE_WARNING | 在PHP启动时警告(非致命性错误) 举例: 暂无 |
64 | E_COMPILE_ERROR | 编译时致命性错误 举例: 暂无 |
128 | E_COMPILE_WARNING | 编译时警告级错误 举例: 暂无 |
256 | E_USER_ERROR | 用户自定义的错误消息 举例: 暂无 |
512 | E_USER_WARNING | 用户自定义的警告消息 举例: 暂无 |
1024 | E_USER_NOTICE | 用户自定义的提醒消息 举例: 暂无 |
2047 | E_ALL | 以上所有的报错信息,但不包括E_STRICT的报错信息 举例: 暂无 |
2048 | E_STRICT | 编码标准化警告,允许PHP建议如何修改代码以确保最佳的互操作性向前兼容性。 |
error_reporting 变量的默认值是 E_ALL & ~E_NOTICE
开发时,最佳的值为: E_ALL | E_STRICT
如果设置为:error_reporting(E_ALL | E_STRICT),则表示记录所有的错误信息
可能会导致网站出现一大堆的错误代码;但是对于程序员来说应该说是一件好事,可以把代码优化到最优; 一些非致命性错误虽然不影响程序的运行,但是会加重PHP的负担.
英文版
1 | E_ERROR | Fatal run-time errors. Errors that can not be recovered from. Execution of the script is halted |
2 | E_WARNING | Non-fatal run-time errors. Execution of the script is not halted |
4 | E_PARSE | Compile-time parse errors. Parse errors should only be generated by the parser |
8 | E_NOTICE | Run-time notices. The script found something that might be an error, but could also happen when running a script normally |
16 | E_CORE_ERROR | Fatal errors at PHP startup. This is like an E_ERROR in the PHP core |
32 | E_CORE_WARNING | Non-fatal errors at PHP startup. This is like an E_WARNING in the PHP core |
64 | E_COMPILE_ERROR | Fatal compile-time errors. This is like an E_ERROR generated by the Zend Scripting Engine |
128 | E_COMPILE_WARNING | Non-fatal compile-time errors. This is like an E_WARNING generated by the Zend Scripting Engine |
256 | E_USER_ERROR | Fatal user-generated error. This is like an E_ERROR set by the programmer using the PHP function trigger_error() |
512 | E_USER_WARNING | Non-fatal user-generated warning. This is like an E_WARNING set by the programmer using the PHP function trigger_error() |
1024 | E_USER_NOTICE | User-generated notice. This is like an E_NOTICE set by the programmer using the PHP function trigger_error() |
2048 | E_STRICT | Run-time notices. PHP suggest changes to your code to help interoperability and compatibility of the code |
4096 | E_RECOVERABLE_ERROR | Catchable fatal error. This is like an E_ERROR but can be caught by a user defined handle (see also set_error_handler()) |
8191 | E_ALL | All errors and warnings, except level E_STRICT (E_STRICT will be part of E_ALL as of PHP 6.0) |