Reputation: 1810
Due to development needs, I want to display PHP errors loud and clear to the browser. So I set my php.ini
:
display_errors = on
This works as expected.
But this messes up the Nginx status code if there is an error. As commented here https://www.php.net/manual/en/errorfunc.configuration.php#126734 :
It's important to note that when display_errors is "on", PHP will send a HTTP 200 OK status code even when there is an error.
I already tried to set fastcgi_intercept_errors on
(or off
) as reccomended somewhere else, but it doesn't seem to make any difference.
So, the question is: how can I have both display_errors = on
and HTTP 500 on errors?
My relevant Nginx config is:
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
I created a PHP file with a missing semicolon for testing. The PHP error is
Parse error: syntax error, unexpected end of file in test.php on line 2
Nginx returns 200 eve if there is an error:
192.168.0.1 - - [27/Sep/2022:08:50:49 +0200] "GET /test.php HTTP/2.0" 200 304 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
Nginx returns 500:
192.168.0.1 - - [27/Sep/2022:08:53:52 +0200] "GET /test.php HTTP/2.0" 500 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
Upvotes: 2
Views: 2420
Reputation: 1307
In fact, in the example you give, nothing surprises me :
I created a PHP file with a missing semicolon for testing. The PHP error is Parse error: syntax error, unexpected end of file in test.php on line 2
PHP error with display_errors = on Nginx returns 200 eve if there is an error
The preprocessor fails to evaluate your php file because of the syntax error, nothing is done by your script (because it's not a runtime error).
With display_error = Off
(default and production suggested value) in php.ini, PHP alerts via the protocol (500
). With display_error = On
it outputs something in the browser, so a 200
response is absolutely legitimate.
You don't explain why you want be able to generate both a protocol error and a regular error message, so I assume it could be to do a mix between a test and a production site. If I'm not wrong, the only way I know is to create a separate PHP pool on another port.
It means :
Keep display_errors = off
default value in your php.ini
Copy /etc/php/7.x/fpm/pool.d/www.conf
with another name (test.conf for example)
In this file, change the [www] name to [test]
; pool name ('www' here)
[test]
Change the listen directive with this name
listen = /run/php/test.sock
[Edit] Uncomment and modify the following line :
php_flag[display_errors] = on
Adapt your nginx.conf, creating a new server
section, listening on another port :
server {
listen 8098;
root /path/to/root;
index index.html index.htm index.php;
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_pass unix:/run/php/test.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
This way, the regular access to your website gives error 500, and the :8098 "super user" access shows the errors, as much as we can hope ^^
(credits to french resource https://www.skyminds.net/php-configurer-un-pool-php-pour-chaque-site/)
Upvotes: 0
Reputation: 18122
Here is a solution based on auto-prepend.
You will need to set the auto_prepend_file
directive:
auto_prepend_file = "/path/to/prepend.php"
The prepended script calls register_shutdown_function()
to
install a handler that will be executed when the main script ends. The handler checks whether an error has occurred;
when it is the case, the HTTP status is set to 500.
This technique is effective even for parse errors.
Remark: to ensure that headers have not already been sent when the status is set, output buffering is enabled.
Content of prepend.php:
<?php
ini_set('display_errors', 'On');
ob_start();
register_shutdown_function('shutdown');
function shutdown()
{
$err = error_get_last();
if($err && in_array($err['type'], [E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR]))
http_response_code(500);
}
?>
Upvotes: 3
Reputation: 112
You should set the default status to 500
.
At the beginning of the code put http_response_code(500);
At the end of the code put http_response_code(200);
May be like this
http_response_code( 500);
ini_set('display_errors', 'on');
http_response_code( 200);
Upvotes: 0
Reputation: 52
Have you tried to put:
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
on top of you`re php page?
Upvotes: 0