PHP:自定义错误处理程序 - 处理解析和致命错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1900208/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 04:14:06  来源:igfitidea点击:

PHP : Custom error handler - handling parse & fatal errors

phperror-handlingfatal-errorparse-error

提问by A.N.M. Saiful Islam

How can i handle parse& fatalerrors using a customerror handler?

如何使用自定义错误处理程序处理解析致命错误?

采纳答案by Dan Soap

Simple Answer: You can't. See the 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.

用户定义的函数无法处理以下错误类型:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING,以及在调用 set_error_handler() 的文件中引发的大部分 E_STRICT。

For every other error, you can use set_error_handler()

对于每个其他错误,您可以使用 set_error_handler()

EDIT:

编辑:

Since it seems, that there are some discussions on this topic, with regards to using register_shutdown_function, we should take a look at the definition of handling: To me, handling an error means catching the error and reacting in a way that is "nice" for the user andthe underlying data (databases, files, web services, etc.).

既然似乎有一些关于这个话题的讨论,关于使用register_shutdown_function,我们应该看看处理的定义:对我来说,处理错误意味着捕捉错误并以一种“很好”的方式做出反应用户底层数据(数据库、文件、网络服务等)。

Using register_shutdown_functionyou cannot handle an error from within the code where it was called, meaning the code would still stop working at the point where the error occurs. You can, however, present the user with an error message instead of a white page, but you cannot, for example, roll back anything that your code did prior to failing.

使用register_shutdown_function您无法从调用它的代码中处理错误,这意味着代码仍会在发生错误的地方停止工作。但是,您可以向用户显示错误消息而不是白页,但是例如,您不能回滚您的代码在失败之前所做的任何事情。

回答by jdias

Actually you can handle parse and fatal errors. It is true that the error handler function you defined with set_error_handler() will not be called. The way to do it is by defining a shutdown function with register_shutdown_function(). Here is what I have working in my website:

实际上,您可以处理解析错误和致命错误。确实不会调用您使用 set_error_handler() 定义的错误处理程序函数。实现方法是使用 register_shutdown_function() 定义关闭函数。这是我在我的网站上工作的内容:

File prepend.php(this file will be prepended to all php scripts automatically). See below for tips on prepending files to PHP.

文件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 will call function errorHandler() if he catches an error in any of the scripts. If the error forces the script to shutdown immediately, the error is handled by function shutdownHandler().

如果 PHP 在任何脚本中发现错误,它就会调用函数 errorHandler()。如果错误强制脚本立即关闭,则错误由函数 shutdownHandler() 处理。

This is working on the site I have under development. I haven't yet tested it in production. But it is currently catching all errors I find while developing it.

这是在我正在开发的网站上工作的。我还没有在生产中测试它。但它目前正在捕获我在开发它时发现的所有错误。

I believe there is a risk of catching the same error twice, once by each function. This could happen if an error that I am handling in the function shutdownHandler() was also caught by function errorHandler().

我相信存在两次捕获相同错误的风险,每个函数一次。如果我在函数 shutdownHandler() 中处理的错误也被函数 errorHandler() 捕获,则可能会发生这种情况。

TODO's:

待办事项:

1 - I need to work on a better log() function to handle errors gracefully. Because I am still in development, I am basically logging the error to a database and echoing it to the screen.

1 - 我需要使用更好的 log() 函数来优雅地处理错误。因为我仍在开发中,我基本上是将错误记录到数据库并将其回显到屏幕上。

2 - Implement error handling for all MySQL calls.

2 - 为所有 MySQL 调用实现错误处理。

3 - Implement error handling for my javascript code.

3 - 为我的 javascript 代码实现错误处理。

IMPORTANT NOTES:

重要笔记:

1 - I am using the following line in my php.ini to automatically prepend the above script to all php scripts:

1 - 我在 php.ini 中使用以下行自动将上述脚本添加到所有 php 脚本中:

auto_prepend_file = "/homepages/45/d301354504/htdocs/hmsee/cgi-bin/errorhandling.php"

it works well.

它运作良好。

2 - I am logging and resolving all errors, including E_STRICT errors. I believe in developing a clean code. During development, my php.ini file has the following lines:

2 - 我正在记录并解决所有错误,包括 E_STRICT 错误。我相信开发一个干净的代码。在开发过程中,我的 php.ini 文件有以下几行:

track_errors = 1
display_errors = 1
error_reporting = 2147483647
html_errors = 0

When I go live, I will change display_errors to 0 to reduce the risk of my users seeing ugly PHP error messages.

当我上线时,我会将 display_errors 更改为 0 以降低我的用户看到丑陋的 PHP 错误消息的风险。

I hope this helps someone.

我希望这可以帮助别人。

回答by Deniss Kozlovs

You can track these errors using code like this:

您可以使用如下代码跟踪这些错误:

(Parse errors can only be caught if they occur in otherscript files via include()or require(), or by putting this code into an auto_prepend_fileas other answers have mentioned.)

(解析错误只有在通过或出现在其他脚本文件中时才能被捕获,或者像其他答案提到的那样将此代码放入 an中。)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');

回答by Creativehavoc

From the PHP.net comments on the page http://www.php.net/manual/en/function.set-error-handler.php

来自页面http://www.php.net/manual/en/function.set-error-handler.php上的 PHP.net 评论

I have realized that a few people here mentioned that you cannot capture parse errors (type 4, E_PARSE). This is not true. Here is how I do. I hope this helps someone.

1) Create a "auto_prepend.php" file in the web root and add this:

我意识到这里有几个人提到您无法捕获解析错误(类型 4,E_PARSE)。这不是真的。这是我的做法。我希望这可以帮助别人。

1) 在 web 根目录中创建一个“auto_prepend.php”文件并添加:

<?php 
register_shutdown_function('error_alert'); 

function error_alert() 
{ 
        if(is_null($e = error_get_last()) === false) 
        { 
                mail('[email protected]', 'Error from auto_prepend', print_r($e, true)); 
        } 
} 
?> 

2) Then add this "php_value auto_prepend_file /www/auto_prepend.php" to your .htaccess file in the web root.

  • make sure you change the email address and the path to the file.

2) 然后将此“php_value auto_prepend_file /www/auto_prepend.php”添加到您的 web 根目录中的 .htaccess 文件中。

  • 确保更改电子邮件地址和文件路径。

回答by Melsi

From my experience you can catch all type of errors, hide the default error message and display an error message of your own (if you like). Below are listed the things you need.

根据我的经验,您可以捕获所有类型的错误,隐藏默认错误消息并显示您自己的错误消息(如果您愿意)。下面列出了您需要的东西。

1) An initial/top level script, let us call it index.phpwhere you store you custom error handler functions. Custom error function handlers must stay at the top so they catch errors below them, by "below" I mean in inclued files.

1) 一个初始/顶级脚本,让我们index.php在您存储自定义错误处理函数的地方调用它。自定义错误函数处理程序必须保持在顶部,以便它们捕获低于它们的错误,“低于”我的意思是在包含的文件中。

2) The assumption that this top script is error free must be true! this is very important, you cannot catch fatal errors in index.phpwhen your custom error handler function is found in index.php.

2) 这个顶级脚本没有错误的假设一定是正确的!这非常重要,index.php当您的自定义错误处理函数在index.php.

3) Php directives (must also be found in index.php) set_error_handler("myNonFatalErrorHandler");#in order to catch non fatal errors register_shutdown_function('myShutdown');#in order to catch fatal errors ini_set('display_errors', false);#in order to hide errors shown to user by php ini_set('log_errors',FALSE);#assuming we log the errors our selves ini_set('error_reporting', E_ALL);#We like to report all errors

3) Php 指令(也必须在index.phpset_error_handler("myNonFatalErrorHandler");#in order to catch non fatal errors register_shutdown_function('myShutdown');#in order to catch fatal error ini_set('display_errors', false);#in order to hidden errors 通过 php 显示给用户 ini_set('log_errors',FALSE);#assuming 我们自己记录错误 ini_set('error_reporting', E_ALL);#We like to report所有错误

while in production (if I am not wrong) we can leave ini_set('error_reporting', E_ALL);as is in order to be able to log error, in the same time ini_set('display_errors', false);will make sure that no errors are displayed to the user.

在生产中(如果我没记错的话)我们可以保持ini_set('error_reporting', E_ALL);原样以便能够记录错误,同时ini_set('display_errors', false);将确保没有错误显示给用户。

As for the actual content of the two functions I am talking, myNonFatalErrorHandlerand myShutdown, I don't put detailed content here in order to keep things simple. In addition the other visitors have given alot of examples. I just show a very plain idea.

至于这两种功能的实际内容我说,myNonFatalErrorHandler而且myShutdown,我不把详细的内容在这里为了让事情变得简单。此外,其他参观者也举了很多例子。我只是展示了一个非常简单的想法。

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, e.g. from a custom session close function
}

as for $err_lvl it can be:

至于 $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');

回答by Jan Turoň

The script with parse error is always interrupted and it can not be handled. So if the script is called directly or by include/require, there is nothing you can do. But if it is called by AJAX, flash or any other way, there isa workaround how to detect parse errors.

解析错误的脚本总是被打断,无法处理。因此,如果直接调用脚本或通过 include/require 调用脚本,则您无能为力。但是如果它被 AJAX、flash 或任何其他方式调用,则一种解决方法如何检测解析错误。

I needed this to handle swfuploadscript. Swfupload is a flash that handles file uploads and everytime file is uploaded, it calls PHP handling script to handle filedata - but there is no browser output, so the PHP handling script needs these settings for debugging purposes:

我需要这个来处理swfupload脚本。Swfupload 是一个处理文件上传的 flash,每次上传文件时,它都会调用 PHP 处理脚本来处理文件数据 - 但没有浏览器输出,因此 PHP 处理脚本需要这些设置以进行调试:

  • warnings and noticesob_start(); at the beginning and store content into session by ob_get_contents(); at the end of the handling script: This can be displayed into browser by another script
  • fatal errorsregister_shutdown_function() to set the session with the same trick as above
  • parse errorsif the ob_get_contents() is located at the end of the handling script and parse error occured before, the session is not filled (it is null). The debugging script can handle it this way: if(!isset($_SESSION["swfupload"])) echo "parse error";
  • 警告和通知ob_start(); 在开始并通过 ob_get_contents() 将内容存储到会话中;在处理脚本的末尾:这可以通过另一个脚本显示到浏览器中
  • 致命错误register_shutdown_function() 使用与上述相同的技巧设置会话
  • 解析错误如果 ob_get_contents() 位于处理脚本的末尾并且之前发生解析错误,则会话未填充(为空)。调试脚本可以这样处理:if(!isset($_SESSION["swfupload"])) echo "parse error";

Note 1nullmeans is not setto isset()

注1种null手段is not setisset()