I'm trying to find a clean way to handle fatal and critical errors (i.e. without output buffering), and I read that using HTTP headers in register_shutdown_function is impossible.
The thing is, I'd like to redirect to a generic static error page when a critical error occurred (e.g.: service unavailable).
How should I do ?
Display a or using Javascript do not seem satisfactory solutions.
Thanks for your help !
There is a Solution to this (that does detect parse errors), contrary to what you have read:
I run a website on a production server and it is critical that we not display any errors nor show any whitepages if indeed there is a fatal error. At the current time, we do not have a testing server, so it was a pain to figure out.
Production-Ready PHP Error Handling
Each PHP file that gets displayed on our website includes a file base.php located one step above the public_html/ directory, so the idea was to set an error handler at the very top of base.php before anything else:
base.php -- insert this at the top of your code:
//DO NOT DISPLAY ERRORS TO USER
ini_set("display_errors", 0);
ini_set("log_errors", 1);
//Define where do you want the log to go, syslog or a file of your liking with
ini_set("error_log", dirname(__FILE__).'/php_errors.log');
register_shutdown_function(function(){
$last_error = error_get_last();
if ( !empty($last_error) &&
$last_error['type'] & (E_ERROR | E_COMPILE_ERROR | E_PARSE | E_CORE_ERROR | E_USER_ERROR)
)
{
require_once(dirname(__FILE__).'/public_html/maintenance.php');
exit(1);
}
});
Now the idea of base.php is not to include much code at all, no functions, only other included or required files for the site to run.
In testing my example, i had something like
include_once(dirname(__FILE__).'/public_html/lib/foobar.php');
So i went to foobar.php and made a syntax error, turning function... into fun ction.
Normally an error would display or a whitepage would display, but because of register_shutdown_function(), now the public_html/maintenance.php page shows up with a message with something like:
Sorry, we are currently experiencing technical difficulties. Please refresh this page in a few minutes to see if we have resolved the issue.
And of course the user has no idea that this is "maintenance.php"
Cheers!
and I read that using HTTP headers in register_shutdown_function
Where did you read that? It's wrong. Anything which happens in register_shutdown_function should not write back to the browser. In most cases the output stream will no longer be available.
I'm trying to find a clean to handle fatal errors
Then you can't do it with PHP code - fatal means your PHP has died - it can't do anything after the error.
Fatal errors are caused by
- bugs in your code
- bugs in PHP
- bugs in the webserver
The latter 2 are very uncommon - the first is your responsibility to identify and fix. While as greOire suggests, you should have your own, branded errorDocument page(s) (but do read the note about MSIE) this is not going to help when the error occurs after your PHP code has started executing. And at that point the webserver assumes tat the response code will be 200 OK unless PHP tells it something different.
There should never be fatal errors in your code at runtime which cannot be replicated at development time - as long as your testing has full code coverage. But I admit that's not always practical - you need to ensure that your error logging is set up correctly and that you check your logs for fatal errors in PHP.
C.
symcbean's answer is correct by the book, but not always in practice. Even though you shouldn't create output in a shutdown handler, you can do so under select circumstances.
Check out headers_sent()
. In your shutdown function, check it. If headers have not been sent yet, then you can echo new headers and actual content if needed. You can use error_get_last() to determine if the shutdown is due to an error or not. The following error types are uncatchable and will kill the script and call shutdown functions:
- E_ERROR
- E_PARSE
- E_CORE_ERROR
- E_COMPILE_ERROR
If the error type is one of those, and headers haven't been sent, then your shutdown handler can create output, including headers.
You must not create output from a shutdown handler if headers have been sent. Those headers could include Content-length, and sending more content than you said you would is bad. Even then, if headers have been sent, any output you create may have nowhere to go, depending on the version of PHP being used, the underlying web server software, and whether or not it's FastCGI.
In fact, this answer may be totally bogus outside of mod_php and FastCGI on Apache 2.2.x. YMMV, but good luck.
You could simply replace apache default error page, using the ErrorDocument directive : http://httpd.apache.org/docs/2.0/mod/core.html#errordocument