Well. I have a problem with http_response_code()
, and I can't find an explanations.
If I use header()
before http_response_code()
, PHP returns HTTP-status which was set by header()
and ignores any http_response_code()
.
For example, I have a file:
<?php
header('HTTP/1.1 404 Not Found');
file_put_contents('./log',http_response_code(501).PHP_EOL,FILE_APPEND);
file_put_contents('./log',http_response_code(502).PHP_EOL,FILE_APPEND);
file_put_contents('./log',http_response_code(503).PHP_EOL,FILE_APPEND);
(I used file_put_contents()
for preventing any output, because somebody can say, that it is the answer to this question)
I used default php-server (but the problem can be reproduced with NGINX):
php -S localhost:9985
There is request:
curl -D - http://localhost:9985
There is response:
HTTP/1.1 404 Not Found
Host: localhost:9958
Date: Wed, 15 Sep 2021 17:20:05 GMT
Connection: close
X-Powered-By: PHP/8.0.10
Content-type: text/html; charset=UTF-8
And there is log:
404
501
502
The response includes first line:
HTTP/1.1 404 Not Found
but I was waiting for HTTP/1.1 503 Service Unavailable
.
The log file includes an expected data and it shows that http_response_code
returned statuses correctly. But it didn't affect for HTTP response code.
I thought that a reason is some data which could have been sent to OUTPUT because I used header()
.
But if I use header()
twice, it doesn't create problems.
I changed my file:
<?php
header('HTTP/1.1 404 Not Found');
header('HTTP/1.1 503 Service Unavailable');
And repeated request:
curl -I http://localhost:9958
There was response:
HTTP/1.1 503 Service Unavailable
Host: localhost:9958
Date: Wed, 15 Sep 2021 17:26:08 GMT
Connection: close
X-Powered-By: PHP/8.0.10
Content-type: text/html; charset=UTF-8
This works great! ðŸ˜
The problem can be reproduced on PHP 7.2, PHP 7.4, PHP 8. I found a comment https://www.php.net/manual/ru/function.http-response-code.php#125538 where it is. But there is apache. I should say that with if I use Apache, the problem is not reproducible for me.
Please, describe, why the function (http_response_code) doesn't work how expect.
Please, don't advise not to use the function because I would want to know true reason for the behavior of the function (the sacred meaning).
Update: Bug report https://bugs.php.net/bug.php?id=81451&edit=2
It's because the status line passed to header()
is prioritized over http_response_code()
in some (all?) PHP SAPI implementations.
PHP tracks the status line and HTTP response code in two separate variables: SG(sapi_headers).http_status_line
and SG(sapi_headers).http_response_code
.
header('HTTP/1.1 404 Not Found')
sets http_status_line
to "HTTP/1.1 404 Not Found" here and updates SG(sapi_headers).http_response_code
a few lines earlier, while http_response_code(503)
only sets SG(sapi_headers).http_response_code
to 503 here.
The code that PHP's builtin server uses for sending the headers can be found in the sapi_cli_server_send_headers
function (php_cli_server.c). In that function, we see that SG(sapi_headers).http_response_code
is ignored when SG(sapi_headers).http_status_line
is set. The sapi_cgi_send_headers
function used by PHP-FPM shows a similar story. The apache2handler SAPI uses both http_status_line and http_response_code. Theoretically, they could point to different statuses!
Maybe. But changing/fixing this behaviour after who knows how many years breaks backwards compatibility, so it should probably be left alone. It's probably best to avoid this situation altogether by sticking to either header() or http_response_code().