【问题标题】:Displaying custom error page in PHP for errors which can't be caught by set_error_handler在 PHP 中为 set_error_handler 无法捕获的错误显示自定义错误页面
【发布时间】:2010-07-15 06:46:32
【问题描述】:

我希望能够丢弃部分呈现的页面并在 PHP 中显示错误页面。

我已经知道set_error_handler(),但它只能捕获某些类型的错误。我想知道当出现set_error_handler() 无法捕获的错误类型时如何显示错误页面。

不幸的是,以下代码在 Apache 2.2 上使用 PHP 5.3.2 运行时,似乎并没有达到我的预期:

<?php

// Start the output buffer
ob_start();

// Output something into the buffer.
// I only want this to be displayed if I call one of the 
// ob_flush functions or echo the buffer myself later.
echo "yep";

// Call a function I know not to exist in order to raise 
// an error which cannot be trapped by set_error_handler() 
// and would, if display_errors was On, output "Fatal 
// error: Call to undefined function fwee()..." 
function_which_does_not_exist();

// This will never be executed.
$out = ob_get_clean();

脚本的输出是:

yep

而我希望它不输出任何内容(或者如果 display_errors() 开启,则只输出错误信息和错误信息)。

我已经使用 LiveHTTPHeaders 确认 PHP 5.3.2 使用 MacPorts 提供的 apache 版本在 display_errors 关闭时会向浏览器发送 500 错误(打开时会发送 200),但在使用时它只会吐出 200 秒XAMPP 上的 PHP 5.3.1。

我尝试在 apache 配置中设置 ErrorDocument 500 “test”(通过对 404 执行相同操作确认可以正常工作),但 PHP 从不显示自定义错误,即使脚本的全部内容只是 header('HTTP/1.1 500 Internal Server Error');

我不确定还有什么方法可以确保部分呈现的页面被替换为一个简单的错误。

我也可以确认这发生在 Yii 框架中。如果我在博客演示中编辑“关于”页面的视图以显示&lt;?php echo function_which_does_not_exist() ?&gt; 的行,我会得到一个部分呈现的页面。

【问题讨论】:

    标签: php apache apache2


    【解决方案1】:

    您可以传递 ob_start 回调函数的名称,该函数在 ob_get_clean() 上刷新输出之前执行。

    即使页面发生错误,这个回调函数也会被执行。

    这样你可以做这样的事情:

    <?php
    $endReached = 0;
    
    function outpu_cb($buffer) {
      global $endReached;
    
      if ($endReached) return $buffer;
      else return 'Your error message';
    }
    
    // Start the output buffer
    ob_start('outpu_cb');
    
    // Output something into the buffer.
    // I only want this to be displayed if I call one of the
    // ob_flush functions or echo the buffer myself later.
    echo "yep";
    
    // Call a function I know not to exist in order to raise
    // an error which cannot be trapped by set_error_handler()
    // and would, if display_errors was On, output "Fatal
    // error: Call to undefined function fwee()..."
    function_which_does_not_exist();
    
    // This will never be executed.
    $endReached = 1;
    echo ob_get_clean();
    ?>
    

    【讨论】:

    • 这正是我想要的。精彩的。非常感谢。我觉得 PHP 不通过更直观的方式支持这种东西真的很奇怪。
    【解决方案2】:

    我认为唯一正确的方法是使用正确的输出缓冲,而不必依赖特定的网络服务器或浏览器行为。

    最好使用 MVC 框架来为您处理这个问题。所有输出都被缓冲,直到所有系统都运行完毕,因此当发生错误时,您可以采取另一条路线,清除当前缓冲区并显示一些不错的错误消息。

    您还可以使用 ob_*() 系列函数。

    • 您必须调用 ob_start() 作为脚本中的第一件事(嗯,在生成 任何 输出之前)
    • 安装 error_handler 以获取错误
    • 发生错误时,清理缓冲区并重新路由您的应用逻辑,以显示一些友好的用户友好错误消息

    【讨论】:

    • 我的问题中的代码示例使用了输出缓冲。我还能如何使用输出缓冲来防止这种情况发生?还应该注意的是,Yii 框架也遇到了这个问题 - 打开 Yii 博客演示,将 推到其中一个模板的某个位置,你会看到你得到了部分无论输出缓冲的状态如何,都进行渲染。
    • 这个答案没有考虑问题的内容。我已经更新了这个问题,试图让它更清楚。
    • 看来你想做的事情是完全不可能的。当调用未定义的函数时,会引发致命错误,这是不可恢复的,会立即停止脚本的执行。没有什么可以阻止这种情况的发生。
    【解决方案3】:

    如果您谈论的是 E_FATAL 或其他此类错误,您可以使用 set_error_handler() 使用自定义错误处理程序捕获它们。

    您只需要添加一个关闭功能。

    // Set the error handler
    set_error_handler(array('error', 'handler'));
    
    // Catch E_FATAL errors too!
    register_shutdown_function(array('error', 'catch_fatal'));
    
    // Set the exception handler
    set_exception_handler(array('error', 'exception'));
    
    // Manually return a new exception 
    function catch_fatal()
    {
        if($e=error_get_last())Error::exception(new ErrorException($e['message'],$e['type'],0,$e['file'],$e['line']));
    }
    

    看看http://micromvc.comhttp://kohanaphp.com/ 看看它是如何完成的。

    【讨论】:

    • 我试图再次为我工作,但它仍然会在运行 register_shutdown_function 之前刷新输出缓冲区。在以下示例中,仍会打印“squeak”。根据问题,这是不可取的。
    • 伙计,这个例子中的哪些文本部分是应该被替换的东西,哪些是实际可用的字符串,这令人困惑......
    【解决方案4】:

    一个老问题,但为了记录,我建议避免这个问题而不是处理它。

    我自己的方法是在响应对象中构建响应,而不是在执行过程中对其进行回显,并且仅在完整响应被正确处理后才回显输出。这需要一个模板系统来解析您的模板并将您的响应构建为字符串,这与从占位符回显输出的经典 PHP 模板不同。

    这样你就完全避免了 PHP 在错误状态下对输出缓存的粗暴管理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-09
      • 1970-01-01
      • 2015-07-05
      相关资源
      最近更新 更多