0

我是一个新手,正在编写一个可移植的自定义错误处理程序,它会在需要时显示一个错误页面。问题是,如果标头或 html 已发送,该怎么办。您无法重定向,也无法预测浏览器中已经显示的内容。

我知道好的代码不会发生这种情况。这是那些发生的事情的最后手段。

该代码的工作原理是在页面中插入一些祈祷它的 html hack,试图强制浏览器重定向,或者失败,在弹出的分区中显示一个漂亮的错误页面以隐藏页面上已有的内容.

下面的代码是合理的还是荒谬的,还是 PHP 提供了更好的解决方案?另外,我还应该做更多的事情来使它坚固吗?

<?PHP
// oh crap! something bad happened but...
// yay, my custom error handler caught it.
// It now does some error handler stuff, records the error, sends me a nasty email, etc.
// Decides the error was fatal. Time to display an error page.
// But wait! Alas, what if headers were sent?
// What if a single empty space was already sent to the browser?
// "ominous music".


if (!headers_sent()) {
    // whew! no problem. display a pretty error page.
}else{
    // dammit! somebodies getting fired. 
    // lets see if we can salvage this and show the viewer something nice.

    $mySafeErrorPage = "http://root.com/somePage.html";

    // Step one: Stop as much HTML as possible.
    // Dump anything still in the buffers.
    while (ob_get_level() > 0 && ob_get_status() != false) {
        ob_end_clean();
    }
    // Step two: Make sure our hack isn't stuck inside a comment or script.
    echo'// -- > </script>';

    // Step three: Make sure the safe page exist and is really safe.
    // Insert two redirect hacks. One for JavaScript. The other if script is disabled.
    $headersArray = @get_headers($mySafeErrorPage);
    $headersString = (is_array($headersArray))?implode("\n",$headersArray):$headersArray;
    $validated = (bool)preg_match('#HTTP/.*\s+[(200|301|302)]+\s#i',$headersString);
    if ($validated) {
        echo'
        <script language="javascript" type="text/javascript">
            window.location.href="'.$mySafePage.'"
        </script>
        <meta http-equiv="refresh" content="0; url= '.$mySafeErrorPage.'" />';
    }

    // Step four: 
    // If we're still here, the redirect failed.
    // Display the error page in a giant pop-up block division 
    // to hide anything already sent to browser.
    echo'
    <div style = "z-index:9998;display:block;position:absolute;top:0px;left:0px;height:3000px;width:3000px;background-color:#FFF">
      <div style = "z-index:9999;display:block;position:absolute;top:0px;left:0px;width:300px;height:300px;background-color:#FFF;color:#000">
        MY HTTP 500 MESSAGE
      </div>     
    </div>';
    exit;
}
4

1 回答 1

1

首先,您正在尝试修复效果,而不是问题的原因。其次,您会将这段代码放在哪里?在页面呈现之前?不起作用,因为此时没有发送标头。页面渲染后?由于此时所有标头都已发送,因此无法正常工作。

此代码的另一个缺点是开发人员需要记住将其包含在每个页面中,这可能很麻烦,最终容易出错。

如果您真的想避免“标头已发送”错误,请添加您的自定义 my_header() 函数,该函数包含 header() PHP 之一并使 headers_sent() 检查。并禁止其他人使用 PHP 内置函数。

my_header 的示例(从原始 header() 函数复制的函数声明):

function my_header($string, $replace = true, $http_response_code) {
    if(headers_sent()) {
        throw new Exception("Headers were already sent");
    }
    header($string, $replace, $http_response_code);
}

您可以对项目施加一些规则,例如每个人都必须使用 my_header() 而不是 header(),并且在代码审查期间,您可以拒绝直接调用 header() 的代码。如果您是项目中唯一的人,那么事情就更简单了:)

于 2015-04-05T20:47:57.733 回答