遇到致命异常时如何让 php 返回 500?

Posted

技术标签:

【中文标题】遇到致命异常时如何让 php 返回 500?【英文标题】:How can I get php to return 500 upon encountering a fatal exception? 【发布时间】:2010-12-06 01:35:04 【问题描述】:

php 致命错误以状态码 200 的形式返回给 HTTP 客户端。如何让它返回状态码 500(内部服务器错误)?

【问题讨论】:

php 返回的错误与您在浏览器中获得的 html 标头无关。如果您从命令行运行该脚本,您将不会收到任何 200 错误代码 请参阅***.com/questions/2331582/catch-php-fatal-error 以获得解决方案。 我需要完全相反的。我设置了一个关闭函数,使用auto_prepend_file 捕获所有致命错误。但是,我还希望在调用该函数时发送status code 200。但我不断收到status code 500 【参考方案1】:
header("HTTP/1.1 500 Internal Server Error");

【讨论】:

您必须手动指定 HTTP 版本才能发出状态码,这很愚蠢。 @DrewSears 我不认为你“必须”这样做;您可以像在 CGI 中一样使用 Status 标头字段。但必须说,对于不熟悉 CGI 的 PHP 程序员,“HTTP/1.1”语法更容易阅读,因为它模仿了 HTTP 响应。 由于 PHP >= 5.4 有 http_response_code([int $responseCode]) 函数。【参考方案2】:

这正是我昨天遇到的问题,我找到了解决方案如下:

1) 首先,您需要捕获PHP 致命错误,即错误类型E_ERROR。发生此错误时,脚本将存储错误并终止执行。您可以通过调用函数 error_get_last() 来获取存储的错误。

2) 在脚本终止之前,回调函数 register_shutdown_function() 将始终被调用。所以你需要通过这个函数注册一个错误处理程序来做你想做的事情,在这种情况下,返回标题 500 和自定义的内部错误页面(可选)。

function my_error_handler()

  $last_error = error_get_last();
  if ($last_error && $last_error['type']==E_ERROR)
      
        header("HTTP/1.1 500 Internal Server Error");
        echo '...';//html for 500 page
      

register_shutdown_function('my_error_handler');

注意:如果你想捕获以 E_USER* 开头的自定义错误类型,你可以使用函数 set_error_handler() 注册错误处理程序,并通过函数 trigger_error 触发错误,但是这个错误处理程序不能处理 E_ERROR 错误类型。请参阅 php.net 上关于 error handler 的说明

【讨论】:

一定要在生产环境中也使用ini_set("display_errors", "off");,否则致命错误信息会被发回客户端。 我建议也检查 E_PARSE - 这也可以通过这种方式捕获,前提是在包含解析错误的文件之前设置了关闭功能。【参考方案3】:

标准 PHP 配置在发生错误时返回 500!只需确保您的 display_errors = off。你可以模拟它:

ini_set('display_errors', 0); 
noFunction();

生产时 display_errors 指令默认关闭。

【讨论】:

这应该更高。这实际上是设置服务器以在致命错误时返回 500 的正确方法。如果您需要查看错误消息,您应该使用错误日志。【参考方案4】:

我使用“set_exception_handler”来处理未捕获的异常。

function handleException($ex) 
      error_log("Uncaught exception class=" . get_class($ex) . " message=" . $ex->getMessage() . " line=" . $ex->getLine());
      ob_end_clean(); # try to purge content sent so far
      header('HTTP/1.1 500 Internal Server Error');
      echo 'Internal error';
    

set_exception_handler('handleException');

【讨论】:

如果你想处理致命错误可以这样做:***.com/questions/277224/… 同时使用 set_error_handler 和 set_exception_handler。第一个用于旧式致命错误,第二个用于面向对象的异常。【参考方案5】:

自 PHP >= 5.4

http_response_code(500);
echo json_encode( [ 'success' => false , 'message' => 'Crazy thing just happened!' ]);
exit();

请在echo之前设置httpCode。

【讨论】:

【参考方案6】:

根据 PHP 文档,无法以任何方式处理 PHP E_ERROR: http://www.php.net/manual/en/function.set-error-handler.php

根据该链接,也无法处理“E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING 和大部分 E_STRICT”。

您可以为包括 E_USER_ERROR 在内的其他错误、警告和通知提供处理程序,但这实际上并没有听起来那么有用,因为此错误只是由程序员使用 trigger_error() 故意抛出的。

当然,您可以捕获任何异常(甚至是原生 PHP 函数抛出的异常)。

我同意这是一个问题。当应用程序代码崩溃和烧毁时,服务器不应返回 200 OK。

【讨论】:

在这里回复超级旧的答案...但是从 php 5.2 开始...您可以在关闭函数中使用error_get_last().. 如果最后一个错误是致命的.. tada【参考方案7】:

可以使用php错误处理

http://www.w3schools.com/php/php_error.asp

【讨论】:

好的答案不仅仅是链接到其他页面。例如,您可以很快参考该页面。当目标站点关闭或他们移动该内容时会发生什么?此外,w3schools 也不是很好的来源。【参考方案8】:

您必须使用 try/catch 捕获抛出的错误,然后使用该 catch 块发送带有 500 错误的 header()。

try 
    ...badcode...
    throw new Exception('error');

 catch (Exception $e) 

    header("Status: 500 Server Error");
    var_dump($e->getMessage());

如果致命异常没有被 try catch 块包围,那么您必须注册一个全局处理程序并使用register_shutdown_function() 在脚本结束时检查错误。

【讨论】:

这将捕获异常,但不会捕获 PHP 致命错误,这些错误是在异常范围之外处理的。 据我所知,无法通过错误处理或异常处理来捕获致命/语法错误 @ChrisRamakers:我读过一些关于使用输出处理程序捕获 PHP 致命错误的内容。 取决于,语法错误是在编译时触发的,因此处理输出或异常处理简单的逻辑永远不会发生,因为页面根本没有执行,因为我无法编译。但同样,我不是绝对的专家,所以我可能不知道你在谈论的输出处理程序 其实你是用register_shutdown_function()来捕捉E_FATAL错误的。【参考方案9】:

永远不要忘记将header("HTTP/1.1 200 OK", true, 200); 设置为任何执行路径的最后一行:

//first things first:
header("HTTP/1.1 500 Internal Server Error", true, 500);


//Application code, includes, requires, etc. [...]


//somewhere something happens
//die();
throw new Exception("Uncaught exception!");


//last things last, only reached if code execution was not stopped by uncaught exception or some fatal error
header("HTTP/1.1 200 OK", true, 200);

PHP 5.4 中,您可以将上面的header 函数替换为更好的http_response_code(200)http_response_code(500)

【讨论】:

如果在第一次和最后一次header() 调用之间生成任何输出,那将不起作用,因为那时标头已经发送。工作页面可能会以状态 500 交付。这种方法风险太大。 使用输出缓冲并在头部之后输出。这是显而易见的。如果输出缓冲以任何方式失败,那不是一个工作页面,它是一个有问题的页面。【参考方案10】:

处理致命错误(编译错误,例如缺少分号)时的困难在于脚本不会被执行,因此在该脚本中设置状态码无济于事。但是,当您包含或需要脚本时,将执行调用脚本,而不管包含的脚本中是否有错误。有了这个,我得出了这个解决方案:

rock-solid-script.php:

// minimize changes to this script to keep it rock-solid
http_response_code(500); // PHP >= 5.4
require_once("script-i-want-to-guard-for-errors.php");

script-i-want-to-guard-for-errors.php:

// do all the processsing
// don't produce any output
// you might want to use output buffering

http_response_code(200); // PHP >= 5.4

// here you can produce the output

将您的调用指向 rock-solid-script.php,然后您就可以开始了。

我希望在 .htaccess 中将默认状态代码设置为 500 会更好。这对我来说似乎更优雅,但我找不到办法把它拉下来。我尝试了 RewriteRule R-flag,但这完全阻止了 php 的执行,所以没有用。

【讨论】:

以上是关于遇到致命异常时如何让 php 返回 500?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复wordpress中的php致命错误和http错误500

如何捕获致命错误:PHP 中的最大执行时间超过了 30 秒

HTTP 500 / 配置错误? [复制]

php返回500错误但没有错误日志

PHP 异常处理 总出现致命错误 无法捕获异常

PHP:异常和可捕获的致命错误有啥区别?