PHP documentation for the header()
function tells us:
There are two special-case header calls... The second special case is the "Location:" header. Not only does it send this header back to the browser, but it also returns a REDIRECT (302) status code to the browser unless the 201 or a 3xx status code has already been set.
However, I want to return a 200 status code with a Location header. Testing on PHP's built-in web server with this code worked fine:
header('Location: https://example.com/foo', true, 200);
header('Content-Type: application/json');
echo '{"test":"testing"}';
But once I moved to the production PHP-FPM server it stopped working. I tried many variations on this code with no luck:
header('Location: https://example.com/foo', true, 200);
http_response_code(200);
header('HTTP/1.1 200 OK', true, 200);
header('Content-Type: application/json');
echo '{"test":"testing"}';
How can I do this, if at all?
According to my understanding of the PHP source, the first line should do it because of the explicitly specified status code:
if ((SG(sapi_headers).http_response_code < 300 ||
SG(sapi_headers).http_response_code > 399) &&
SG(sapi_headers).http_response_code != 201) {
/* Return a Found Redirect if one is not already specified */
if (http_response_code) { /* user specified redirect code */
sapi_update_response_code(http_response_code);
} else if (SG(request_info).proto_num > 1000 &&
SG(request_info).request_method &&
strcmp(SG(request_info).request_method, "HEAD") &&
strcmp(SG(request_info).request_method, "GET")) {
sapi_update_response_code(303);
} else {
sapi_update_response_code(302);
}
}
By default, the CGI SAPI doesn't send the status code when it is equal to 200.
Test script:
<?php
header('Location: https://example.com/foo', true, 200);
?>
Execution from the command line:
php-cgi.exe test.php
Output:
X-Powered-By: PHP/8.4.12
Location: https://example.com/foo
Content-type: text/html; charset=UTF-8
Now we enable the cgi.nph
flag to always send the status:
<?php
ini_set('cgi.nph', '1');
header('Location: https://example.com/foo', true, 200);
?>
Output:
Status: 200 OK
X-Powered-By: PHP/8.4.12
Location: https://example.com/foo
Content-type: text/html; charset=UTF-8
The Status
header is now sent.