I'm developing a PHP application that uses HTTP response codes for communication as well as response bodies. So this is a typical scenario in the PHP code:
try {
doSomething();
}
catch (Exception $e) {
header('HTTP/1.1 500 Internal Server Error');
}
... and the typical code in clients looks like:
switch(responseCode) {
case 200 :
// all fine
// ....
case 500 :
// trouble!
}
This is cool, as long as every error is well caught in PHP code.
The problem: If, for any reason in the php code occures an uncaught error or an uncatchable error like syntax errors, Apache will send 200 OK. But I wan't apache to say 500 Internal Server Error. Maybe per .htaccess or so.
You can, of course, write your own error handler. However, not all PHP errors are catchable. For instance, a syntax error won't even allow your code to run, including your error handler.
To handle catchable errors, you can use the auto_append_file and auto_prepend_file directives to place your error handling code code.
Non-catchable errors are a different issue. If PHP runs as Fast CGI, it will automatically generate a 500 status code for you. However, you're probably running PHP through some other SAPI (such as Apache module). No idea about that, sorry. (I'll report back if I find something.)
Response headers are not sent until PHP echoes the first byte of response body. You can change headers (and the status code) in the mean time. Keeping that in mind, here is a solution:
Set your script to send a 500 response code at the beginning of script and 200 at the end. Here is an example:
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error');
if (rand(0, 1) == 1) {
die("Script terminated prematurely");
}
header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK');
echo "Success";
Just ensure that 200 response code is set at only one location in your code.
Note: you can use http_response_code (PHP >= 5.4) instead of header.
Nowadays it's no more a problem - since 5.3 PHP learned at last to send 503 on error, not 200
Err, it seems it was 5.2.4:
Changed error handler to send HTTP 500 instead of blank page on PHP errors.
You need to set display_errors = off to make it work
I have the exact behavior on my windows Apache 2.4 with PHP 5.4.5
Related
As a prelude, I know what a HTTP 500 is, and I know how to fix them.
On PHP 5.3, i'm running a production environment with show_errors off. When there are any fatal errors, the user gets a plain white 500 page in response. I'm trying to create a 500 error page just in case there any any errors; just so it is more user friendly.
I used to be able to do
ErrorDocument 500 500.html
It doesn't seem to be working anymore, however - even thought my 404
ErrorDocument 404 404.html
Works fine.
Curious to see solutions regarding this -
Thank you for your time.
Fatal errors don't produce 500 errors in and of themselves, they would return 200 with blank page typically (if no output had been flushed to browser at the point of the error) . Plus this will not help you anyway, as Apache would be no longer involved when PHP is having the error.
Maybe you could register a shutdown function to send 500 header (to get 500 result) and display the content you want to display.
I have a php script that uses a third party API that requests information using OAuth and then outputs JSON and then I parse the JSON and foreach JSON tree response insert the data into a database, pretty simple, works great but sometimes the API handshake fails for various reasons and gives me a 500 internal error in the console.
The 500 error seems to be out of my control as it's accessing a third party. Is there a way to force the php script to give a status of 200 OK?
I have tried various combinations of the following and still cannot get it to stop the random 500 error in the console:
header("HTTP/1.1 200 OK");
error_reporting(0);
ini_set('display_errors', 'off');
Is there away?
Regardless I would assume what I am trying to do is bad practice but for this scenario, when the 500 error comes up it completely halts my script!
Server:
Apache 2.4.16,
PHP 5.5.28
What your server replies is entirely in your control. If you get a 500 error it's because your code isn't handling the failure, you probably have an exception being raised somewhere.
Check your error log and figure out where the issue is occurring, then handle the error condition and return what you would like.
I came across an issue today, that my PHP script would send a server error 500 upon finishing (on apache). The code was something like:
//many stuff here that work
echo "It reached here";
exit;
and I was always reaching the point before the exit; command. Doing a google search, I came across this post, which suggested turning on display_errors. I did it and the 500 error went away.
So I wanted to ask, does anyone have an explanation on why this happens? This SO post describes a similar case, but there are no explanations.
As always, thanks in advance
It's pretty likely you get a 500 status code as well, but because PHP echoes something to the browser apache won't jump in and display it's standard status 500 error page.
You would need to verify the actual status code to verify that you won't still get a 500 error.
In case of a fatal error, PHP normally sends a 500 status code. As often the process has failed at that time (hence causing the fatal) and sometime no output is generated since then, the webserver jumps in and gives the user the standard 500-internal-server-error-page.
It appears that the code generated a parse error inside an eval() function in a loop. This kind of error does not break code execution but does produce a 500 error
My server is setup with Nginx + PHP + FastCGI. Whenever PHP throws a Fatal error, it gets logged inside of nginx/error.log, but the server reports HTTP Error 500 back to the browser instead of displaying the PHP Fatal error to the browser as is desired and typical in other setups. I've been searching for how to resolve this and keep coming up short. Anyone have anything helpful about this? Much appreciated!
Found it!
As of PHP 5.2.4, the default is now to cause a 500 error, because the alternative is an empty page.
Other discussions suggest that this behavior can not be changed for the "PHP Fatal" error type, which don't flow through the normal error handler routines and can not be caught or stopped.
You probably have php_errors off (or the displaying of them) in your php loader script... Try checking your php.ini settings...
I'm writing an error logging service that will be integrated into websites running on my server, that will email me error batches, etc.
So I've been trying to find out if there's a way to handle fatal and parse errors, however not using the tricks to handle it in PHP code (output buffer, shutdown function). I'm quite happy to write some C code or something to handle it outside of my PHP code. I would also like to issue a redirect if possible (my sites use output buffering so there shouldn't be any headers sent).
I'm pretty sure this could be done with a PHP module, but I've never written one and have no idea where to start.
There is no way to catch a fatal or parse error in PHP. But..
In 5.2, they added error_get_last(). You can call it inside a shutdown function and perform logging. An untested 5.3 example for firing off a mail when there was a fatal error:
<?php
register_shutdown_function(function(){
$err = error_get_last();
if(is_array($err) && array_key_exists('type', $err) $err['type'] > 0
&& ($err['type'] == E_ERROR || $err['type'] == E_PARSE) {
error_log("Oh noes, a fatal: " . var_export($err, true), 1, 'fatals#example.com');
}
});
(You'll need to use a callback if you aren't on 5.3 and can't do anonymous functions.)
Unfortunately because this is handled in a shutdown function, chances are that headers have already been emitted and you might not be able to provide anything useful to the user. This depends on the rest of the application, though, so it might work out for you. Try it and find out!
By default all errors are passed to web server error log but you can change it in php.ini by specifying path to your own file via error_log setting. So what is left to do is to write some separate script/app to parse / send data / truncate log file every day / whatever and run it as cron job.