提醒:
- 这里讨论的终止性错误指导致php执行失败的错误,例如E_Error,像E_NOTICE、E_WARNING这样的报错Codeigniter框架本身可以完美的捕获,因此不在讨论范围内。
- 本文已Codeigniter 2.2为例,Codeigniter 2.x 都可以使用本文的方案,大家尽管参考。
- 本文的环境是lnmp,Apache同学可做参考。
- 如果你比较着急获得结果可以直接跳到“解决方案”处。
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('_exception_handler');
Codeigniter 2.2 system/core/Common.php line:446
if ( ! function_exists('_exception_handler'))
{
function _exception_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('_uncatched_exception_handler');
register_shutdown_function('_shutdown_handler');
在system/core/CodeIgniter.php line:495行添加下面两个函数:
if ( ! function_exists('_exception_exception_handler'))
{
function _exception_exception_handler($exception)
{
log_message('error', "Exception:" . var_export($exception, true));
}
}
if ( ! function_exists('_shutdown_handler'))
{
function _shutdown_handler()
{
$error = error_get_last();
$fatalErrors = array(
E_ERROR,
E_PARSE,
E_CORE_ERROR,
E_CORE_WARNING,
E_COMPILE_ERROR,
E_COMPILE_WARNING
);
if (isset($error['type']) && in_array($error['type'], $fatalErrors)) {
$err_msg = sprintf('Severity: Error --> %s %s %s %s %s',$error['message'], $error['type'], $error['type'], $error['file'], $error['line']);
log_message('error', $err_msg);
}
}
}
重启你的php-fpm,注意:不能以Kill -USR2发送信号量的方式重启。
最好的方式就是直接杀死进程,再重新开启运行php-fpm进程。