抓住PHP致命错误

时间:2010-02-25 04:11:45

标签: php http-status-codes

我有一个启用了restful的Web服务站点,因此其他网站/ ajax脚本可以调用该站点来获取/设置数据。但是,每当Web服务站点以某种方式返回PHP致命错误时,返回的HTTP状态为200而不是500.是否有办法修复它,以便每当发生致命错误时,返回500而不是200?或者,如果不可能,我如何更改我的客户端以识别Web服务返回的致命错误?

6 个答案:

答案 0 :(得分:31)

PHP 发送致命错误的HTTP 500 让我引用this PHP bug-report中的注释(xdebug bug可以防止这种行为):

  

确实发生了。它要求:

     

1)display_errors = off
  2)错误发生时尚未发送标题   3)当时状态为200。

<?
    ini_set('display_errors', 0); 
    foobar();
    // This will return a http 500
?>

您可以使用shutdown functionerror_get_last

来捕捉致命错误
register_shutdown_function(function() {
    $lastError = error_get_last();

    if (!empty($lastError) && $lastError['type'] == E_ERROR) {
        header('Status: 500 Internal Server Error');
        header('HTTP/1.0 500 Internal Server Error');
    }
});

答案 1 :(得分:13)

一种可能的方法是将默认响应设置为500,如果一切成功执行,则将响应设置为200:

http_response_code(500);
render_my_page();
http_response_code(200);

答案 2 :(得分:3)

创建自定义错误处理程序(set_error_handler)并调用header("HTTP/1.0 500 Service not available");

编辑:

根据我的回答的第一条评论,你无法捕获真正的致命错误。但是,如果禁用输出缓冲并且错误未显示在屏幕上,PHP将默认为致命错误设置500错误代码。

<?php
        $x = y();
?>

如果没有任何内容发送到屏幕,上面的代码将返回500错误代码。

因此,如果您想要这种错误来设置正确的代码,请执行自己的缓冲:

<?php
        $buffer = 'blah';
        $x = y();  // will trigger 500 error
        echo $buffer;
?>

答案 3 :(得分:3)

function fatal_error_handler() {

  if (@is_array($e = @error_get_last())) {
    if (isset($e['type']) && $e['type']==1) {
      header("Status: 500 Internal Server Error");
      header("HTTP/1.0 500 Internal Server Error");
      }
    }

}
register_shutdown_function('fatal_error_handler');

答案 4 :(得分:2)

我开发了一种方法来捕获PHP中的所有错误类型(几乎所有)!我不确定E_CORE_ERROR(我认为它不适用于该错误)!但是,对于其他致命错误(E_ERROR,E_PARSE,E_COMPILE ...)只使用一个错误处理函数正常工作!有我的解决方案:

将以下代码放在主文件(index.php)上:

<?php

define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR | 
        E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

define('ENV', 'dev');

//Custom error handling vars
define('DISPLAY_ERRORS', TRUE);
define('ERROR_REPORTING', E_ALL | E_STRICT);
define('LOG_ERRORS', TRUE);

register_shutdown_function('shut');

set_error_handler('handler');

//Function to catch no user error handler function errors...
function shut(){

    $error = error_get_last();

    if($error && ($error['type'] & E_FATAL)){
        handler($error['type'], $error['message'], $error['file'], $error['line']);
    }

}

function handler( $errno, $errstr, $errfile, $errline ) {

    switch ($errno){

        case E_ERROR: // 1 //
            $typestr = 'E_ERROR'; break;
        case E_WARNING: // 2 //
            $typestr = 'E_WARNING'; break;
        case E_PARSE: // 4 //
            $typestr = 'E_PARSE'; break;
        case E_NOTICE: // 8 //
            $typestr = 'E_NOTICE'; break;
        case E_CORE_ERROR: // 16 //
            $typestr = 'E_CORE_ERROR'; break;
        case E_CORE_WARNING: // 32 //
            $typestr = 'E_CORE_WARNING'; break;
        case E_COMPILE_ERROR: // 64 //
            $typestr = 'E_COMPILE_ERROR'; break;
        case E_CORE_WARNING: // 128 //
            $typestr = 'E_COMPILE_WARNING'; break;
        case E_USER_ERROR: // 256 //
            $typestr = 'E_USER_ERROR'; break;
        case E_USER_WARNING: // 512 //
            $typestr = 'E_USER_WARNING'; break;
        case E_USER_NOTICE: // 1024 //
            $typestr = 'E_USER_NOTICE'; break;
        case E_STRICT: // 2048 //
            $typestr = 'E_STRICT'; break;
        case E_RECOVERABLE_ERROR: // 4096 //
            $typestr = 'E_RECOVERABLE_ERROR'; break;
        case E_DEPRECATED: // 8192 //
            $typestr = 'E_DEPRECATED'; break;
        case E_USER_DEPRECATED: // 16384 //
            $typestr = 'E_USER_DEPRECATED'; break;

    }

    $message = '<b>'.$typestr.': </b>'.$errstr.' in <b>'.$errfile.'</b> on line <b>'.$errline.'</b><br/>';

    if(($errno & E_FATAL) && ENV === 'production'){

        header('Location: 500.html');
        header('Status: 500 Internal Server Error');

    }

    if(!($errno & ERROR_REPORTING))
        return;

    if(DISPLAY_ERRORS)
        printf('%s', $message);

    //Logging error on php file error log...
    if(LOG_ERRORS)
        error_log(strip_tags($message), 0);

}

ob_start();

@include 'content.php';

ob_end_flush();

?>

我希望这可以帮助很多人!

答案 5 :(得分:-5)

我认为您希望在部署应用程序之前捕获并修复所有致命错误,因为其中许多是代码错误,缺少包含,不存在的对象,这些都是开发错误。即使是内存不足的错误也可以通过节省内存的编码技术来最小化(最大的胜利之一是使用无缓冲的查询并处理数据并在返回结果集时发出输出,而不是抛出巨大的数组)。 / p>