开发者

Displaying custom error page in PHP for errors which can't be caught by set_error_handler

I would like to be able to discard a partially rendered page and show an error page in PHP.

I already know about set_error_handler(), but it can only trap certain types of errors. I would like to know how to show an error page when an error type which can't be trapped by set_error_handler() is raised.

Unfortunately, it seems that the following code, when run with PHP 5.3.2 on Apache 2.2, doesn't do what I would expect it to do:

<?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();

The output of the script is:

yep

Whereas I would expect it to output nothing (or spew error info and only error info if display_errors() is on).

I have confirmed using LiveHTTPHeaders that PHP 5.3.2 does send a 500 error to the browser when display_errors is off (and a 200 when it's on) using the version of apache supplied by MacPorts, but it only ever spits 200s when using PHP 5.3.1 on XAMPP.

I tried setting ErrorDocument 500 "test" in the apache configuration (confirmed to be working by doing the same for 404) but PHP never shows the custom error, even when the entire contents of the script is just header('HTTP/1.1 500 Internal Server Error');

I'm not sure what else to do to make sure a partially rendered page is replaced with a simple error.

I can also confirm that this ha开发者_开发问答ppens in the Yii framework. If I edit the view for the "about" page in the blog demo to have a line which reads <?php echo function_which_does_not_exist() ?>, I get a partially rendered page.


You could pass ob_start the name of a callback function, that is executed before the output is flushed on ob_get_clean().

This callback function seams to be executed even if an error occured on the page.

This way you could do something like this:

<?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();
?>


I think the only right way to do this is by using correct output buffering, than you don't have to rely on specific webserver or browser behaviour.

Best you'd use a MVC framework to handle this for you. All output is buffered until all systems are go, so when an error occurs you can take another route, clear the current buffer and display some nice error message.

You can also use the ob_*() family of functions.

  • You have to call ob_start() as the very first thing in your script (well, before any output is generated)
  • Install an error_handler to fetch errors
  • When an error occured, clean the buffer and re-route your app logic to display some nice userfriendly error message


If your talking about E_FATAL or other such errors yes you can catch them with a custom error handler using set_error_handler().

All you need to add is a shutdown function.

// 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']));
}

Take a look at http://micromvc.com or http://kohanaphp.com/ to see how it's done.


An old question, but for the record I'd suggest avoiding this issue rather than handling it.

My own approach is to build the response in a response object rather than echoing it as you go along, and only echo the output once the full response has been processed without error. This requires a template system that parses your template and builds your response into a string, in contrast to a classic PHP template which echoes output from your placeholders.

This way you entirely avoid PHP's crufty management of the output cache in error states.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜