提醒:
這裏討論的終止性錯誤指導致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) |