PHP自定义错误处理程序,用于在发送标头时重定向或显示错误页面.这个代码是个坏主意吗


PHP custom error handler to redirect or display error page when headers allready sent. Is this code a bad idea?

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

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

该代码的工作原理是将一些"祈祷它能工作"的html黑客插入页面,试图迫使浏览器重定向,否则,在弹出的分区中显示一个漂亮的错误页面,以隐藏页面上已经存在的内容。

下面的代码是合理的还是荒谬的,或者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;
}

首先,您要解决的是效果,而不是问题的原因。第二,你会把这个代码放在哪里?在呈现页面之前?无法工作,因为此时没有发送标头。页面呈现后?无法工作,因为此时已发送所有标头

该代码的另一个缺点是,开发人员需要记住在每个页面中都包含它,这可能会导致繁琐的最终错误。

如果您真的想避免"headers already sended"错误,那么添加您的自定义my_header()函数,该函数将header()PHP封装为一个,并使headers_int()进行检查。并禁止其他人使用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(()的代码。如果你是项目中唯一的一个,那么事情就更简单了:)