I've run across accidental usage of Status
header for FastCGI. Are there pros/cons of using it in environment-independent scripts?
header('Location: ' . $url, true, 301);
alone causes no issues for me on Apache 2.2 (according to phpinfo()
, the server uses FastCGI).
The script is aimed at Apache and nginx (mod_php and FastCGI). What would fail-proof solution look like?
HTTP Status code is emitted as part of the first line of the HTTP response. According to Fast CGI FAQ the Status header is a special header recognized by the server which controls this line and it is not sent to the client. However if it is used with a non FastCGI server adapter, the value is ignored by the server and the header can be sent out.
The solution you already have is the most environment-independent way possible. The only addition would be an exit
statement immediately after redirect to make sure the script terminates.
Let's look what happens under the hood more closely.
The following PHP redirection code
header('Location: ' . $url, true, 301);
exit;
Will call the C code in ext/standard/head.c
PHP_FUNCTION(header)
{
[ code that just parses the arguments omitted ]
sapi_header_op(rep ? SAPI_HEADER_REPLACE:SAPI_HEADER_ADD, &ctr);
}
Which will in turn call the sapi_header_op
function in main/SAPI.c
[ ... ]
switch (op) {
[ ... ]
case SAPI_HEADER_ADD:
case SAPI_HEADER_REPLACE:
case SAPI_HEADER_DELETE: {
sapi_header_line *p = arg;
if (!p->line || !p->line_len) {
return FAILURE;
}
header_line = p->line;
header_line_len = p->line_len;
http_response_code = p->response_code;
break;
}
[ code that splits header line by colon, trims whitespace etc ]
[ special headers handling code, including setting 302 if Location ]
if (http_response_code) {
sapi_update_response_code(http_response_code);
}
sapi_header_add_op(op, &sapi_header);
return SUCCESS;
If FastCGI back-end is in use, the added headers will eventually be sent out by sapi_cgi_send_headers
function in sapi/cgi/cgi_main.c
[ ... ]
if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
{
[ emit status line if cgi.rfc2616-headers is set ]
[ Handle a case where there is a user supplied status line ]
[ Handle a case where there is already a user supplied status header ]
[ if none of the above ]
if (err->str) {
len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->str);
} else {
len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
}
[ ... ]
}
[ ... ]
Note that php_apache_sapi_send_headers
function in sapi/apache2handler/sapi_apache2.c
does not have any special handling of the Status
header because it is not used for module communication.
So by executing the PHP code above
All manipulations are performed in the SAPI layer which is an abstraction layer on top of HTTP server adapters (FastCGI, Apache module etc). This is as cross-environment and reliable as it gets.
Historically there have been bugs in FastCGI which prevented 301 responses from working correctly, however these were in the web server implementation and there was nothing that could of been done from PHP code to work around the issue.
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With