PHP:自定义error handling程序 – 处理分析和致命错误
我怎样才能处理parsing和致命错误使用自定义error handling程序?
简单的答案:你不能。 看手册 :
用户定义的函数无法处理以下错误types:调用set_error_handler()的文件中引发的E_ERROR,E_PARSE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,E_COMPILE_WARNING和E_STRICT的大部分内容。
对于其他每一个错误,你可以使用set_error_handler()
编辑:
既然看来这个话题有一些讨论,关于使用register_shutdown_function
,我们应该看看处理的定义:对我来说,处理一个错误意味着捕捉错误并以一种“好”的方式作出反应,为用户和底层数据(数据库,文件,networking服务等)。
使用register_shutdown_function
你不能在被调用的代码中处理错误,这意味着代码在发生错误的时候仍然会停止工作。 但是,您可以向用户显示一条错误消息而不是白页,但不能在代码失败之前回滚代码所做的任何事情。
其实你可以处理parsing和致命的错误。 确实,使用set_error_handler()定义的error handling函数不会被调用。 做这件事的方法是用register_shutdown_function()定义一个closures函数。 以下是我在我的网站上工作的内容:
文件prepend.php (该文件将被自动添加到所有的PHP脚本)。 请参阅下面有关将文件预先添加到PHP的提示。
set_error_handler("errorHandler"); register_shutdown_function("shutdownHandler"); function errorHandler($error_level, $error_message, $error_file, $error_line, $error_context) { $error = "lvl: " . $error_level . " | msg:" . $error_message . " | file:" . $error_file . " | ln:" . $error_line; switch ($error_level) { case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_PARSE: mylog($error, "fatal"); break; case E_USER_ERROR: case E_RECOVERABLE_ERROR: mylog($error, "error"); break; case E_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: case E_USER_WARNING: mylog($error, "warn"); break; case E_NOTICE: case E_USER_NOTICE: mylog($error, "info"); break; case E_STRICT: mylog($error, "debug"); break; default: mylog($error, "warn"); } } function shutdownHandler() //will be called when php script ends. { $lasterror = error_get_last(); switch ($lasterror['type']) { case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: case E_RECOVERABLE_ERROR: case E_CORE_WARNING: case E_COMPILE_WARNING: case E_PARSE: $error = "[SHUTDOWN] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line']; mylog($error, "fatal"); } } function mylog($error, $errlvl) { ...do whatever you want... }
如果PHP在任何脚本中发现错误,PHP将调用函数errorHandler()。 如果错误强制脚本立即closures,则错误由函数shutdownHandler()处理。
这正在我正在开发的网站上工作。 我还没有testing它在生产。 但是它正在捕捉我在开发过程中遇到的所有错误。
我相信有两次发生同样的错误的风险,一次是每个function。 如果我在函数shutdownHandler()中处理的错误也被函数errorHandler()捕获到,则可能发生这种情况。
TODO的:
1 – 我需要更好地处理log()函数来处理错误。 因为我还在开发中,所以我基本上是将错误logging到数据库并将其回显到屏幕上。
2 – 为所有MySQL调用实现error handling。
3 – 为我的JavaScript代码实现error handling。
重要笔记:
1 – 我在我的php.ini中使用以下行来自动将上述脚本预先添加到所有PHP脚本中:
auto_prepend_file = "/homepages/45/d301354504/htdocs/hmsee/cgi-bin/errorhandling.php"
它运作良好。
2 – 我正在logging并解决所有错误,包括E_STRICT错误。 我相信在开发一个干净的代码。 在开发过程中,我的php.ini文件有以下几行:
track_errors = 1 display_errors = 1 error_reporting = 2147483647 html_errors = 0
当我上线时,我会将display_errors更改为0,以降低用户看到难看的PHP错误消息的风险。
我希望这可以帮助别人。
您可以使用如下代码来追踪这些错误:
(parsing错误只有在其他脚本文件通过include()
或require()
发生时才能被捕获,或者像其他答案中提到的那样将此代码放入auto_prepend_file
)。
function shutdown() { $isError = false; if ($error = error_get_last()){ switch($error['type']){ case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: $isError = true; break; } } if ($isError){ var_dump ($error);//do whatever you need with it } } register_shutdown_function('shutdown');
从PHP.net的评论页面http://www.php.net/manual/en/function.set-error-handler.php
我已经意识到这里有几个人提到你不能捕获parsing错误(types4,E_PARSE)。 这不是真的。 这是我的方式。 我希望这可以帮助别人。
1)在web根目录下创build一个“auto_prepend.php”文件并添加:
<?php register_shutdown_function('error_alert'); function error_alert() { if(is_null($e = error_get_last()) === false) { mail('your.email@example.com', 'Error from auto_prepend', print_r($e, true)); } } ?>
2)然后将这个“php_value auto_prepend_file /www/auto_prepend.php”添加到Web根目录中的.htaccess文件中。
- 请确保您更改电子邮件地址和文件的path。
parsing错误的脚本总是被中断,不能被处理。 所以如果脚本直接被调用或者被include / require调用,那么你就无能为力了。 但是,如果它是由AJAX调用,闪存或任何其他方式,有一个解决方法如何检测parsing错误。
我需要这个来处理swfupload脚本。 Swfupload是一个处理file upload的Flash,每次上传文件,它都会调用PHP处理脚本来处理filedata – 但是没有浏览器输出,所以PHP处理脚本需要这些设置来进行debugging:
- 警告和通知 ob_start(); 在开始时通过ob_get_contents()将内容存储到会话中; 在处理脚本的末尾:这可以通过另一个脚本显示在浏览器中
- 致命错误 register_shutdown_function()使用与上面相同的技巧设置会话
- 如果ob_get_contents()位于处理脚本的末尾并parsing错误,则会话未被填充(为空),则parsing错误。 debugging脚本可以这样处理:
if(!isset($_SESSION["swfupload"])) echo "parse error";
注1 null
表示is not set
为isset()
根据我的经验,您可以捕获所有types的错误,隐藏默认错误信息并显示您自己的错误信息(如果您喜欢)。 下面列出你需要的东西。
1)初始/顶层脚本,让我们把它叫做index.php
,在那里存储你自定义的error handling函数。 自定义错误函数处理程序必须停留在顶部,以便在下面捕获错误,“下面”我的意思是包含文件。
2)这个顶级脚本是无错误的假设必须是真的! 这是非常重要的,当您在index.php
find自定义error handling函数时,您不能在index.php
捕获致命错误。
3)PHP指令(也必须在index.php
find) set_error_handler("myNonFatalErrorHandler");
#为了捕获非致命错误register_shutdown_function('myShutdown');
#为了捕捉致命错误ini_set('display_errors', false);
#为了隐藏php显示给用户的错误ini_set('log_errors',FALSE);
#假设我们自己logging错误ini_set('error_reporting', E_ALL);
#我们想报告所有错误
而在生产(如果我没有错),我们可以离开ini_set('error_reporting', E_ALL);
至于为了能够logging错误,同时ini_set('display_errors', false);
将确保没有错误显示给用户。
至于我所说的两个函数的实际内容, myNonFatalErrorHandler
和myShutdown
,为了保持简单,我没有在这里提供详细的内容。 另外其他参观者也举了很多例子。 我只是performance出一个非常普通的想法。
function myNonFatalErrorHandler($v, $m, $f, $l, $c){ $some_logging_var_arr1[]="format $v, $m, $f, ".$err_lvl[$l].", $c the way you like"; //You can display the content of $some_logging_var_arr1 at the end of execution too. } function myShutdown() { if( ($e=error_get_last())!==null ){ $some_logging_var_arr2= "Format the way you like:". $err_level[$e['type']].$e['message'].$e['file'].$e['line']; } //display $some_logging_var_arr2 now or later, eg from a custom session close function }
至于$ err_lvl,它可以是:
$err_lvl = array(E_ERROR=>'E_ERROR', E_CORE_ERROR=>'E_CORE_ERROR', E_COMPILE_ERROR=>'E_COMPILE_ERROR', E_USER_ERROR=>'E_USER_ERROR', E_PARSE=>'E_PARSE', E_RECOVERABLE_ERROR=>'E_RECOVERABLE_ERROR', E_WARNING=>'E_WARNING', E_CORE_WARNING=>'E_CORE_WARNING', E_COMPILE_WARNING=>'E_COMPILE_WARNING', E_USER_WARNING=>'E_USER_WARNING', E_NOTICE=>'E_NOTICE', E_USER_NOTICE=>'E_USER_NOTICE',E_STRICT=>'E_STRICT');