我有一个PHP脚本需要使用HTTP响应码(状态码)来进行响应,例如HTTP 200 OK或一些4XX或5XX的代码。
我该如何在PHP中实现这个功能?
我有一个PHP脚本需要使用HTTP响应码(状态码)来进行响应,例如HTTP 200 OK或一些4XX或5XX的代码。
我该如何在PHP中实现这个功能?
我刚发现这个问题,认为它需要更全面的答案:
从PHP 5.4开始,有三种方法可以实现这个目标:
header()
函数有一个特殊的用例,可以检测到HTTP响应行,并让您替换为自定义的响应行。
header("HTTP/1.1 200 OK");
$sapi_type = php_sapi_name();
if (substr($sapi_type, 0, 3) == 'cgi')
header("Status: 404 Not Found");
else
header("HTTP/1.1 404 Not Found");
注意:根据HTTP RFC,reason phrase可以是任何符合标准的自定义字符串,但为了客户端兼容性,我不建议在那里放置随机字符串。
注意:php_sapi_name()
需要PHP 4.0.1
当使用第一种变体时,显然存在一些问题。其中最大的问题我认为是它部分由PHP或Web服务器解析并且文档说明不足。
从4.3开始,header
函数有一个第三个参数,让您相对轻松地设置响应代码,但使用它需要第一个参数是非空字符串。以下是两个选项:
header(':', true, 404);
header('X-PHP-Response-Code: 404', true, 404);
我推荐第二个。我已经测试过第一个在所有浏览器上都可以工作,但是一些小型浏览器或网络爬虫可能会对只包含冒号的标题行有问题。第二个变体中的标题字段名称当然没有任何标准化,并且可以进行修改,我只选择了一个希望具有描述性的名称。
http_response_code()
函数是在PHP 5.4中引入的,它使事情变得容易得多。
http_response_code(404);
我为您准备了一个函数,用于兼容低于5.4版本的PHP,但仍然想要“新”的http_response_code
功能。我认为PHP 4.3已经足够向后兼容,但是您永远不知道...
这里是一个函数,当我需要低于5.4的兼容性但又想要“新”的http_response_code
功能时,就会用到它。我相信PHP 4.3已经足够向后兼容,但您永远不知道...
That's all.
// For 4.3.0 <= PHP <= 5.4.0
if (!function_exists('http_response_code'))
{
function http_response_code($newcode = NULL)
{
static $code = 200;
if($newcode !== NULL)
{
header('X-PHP-Response-Code: '.$newcode, true, $newcode);
if(!headers_sent())
$code = $newcode;
}
return $code;
}
}
headers_sent()
为真,而不是你已经添加了头信息。 (2) 抱歉,不行。其他语言有更好的支持。 - dualedecho
输出内容后,http_response_code
(以及更一般地修改头部)不再起作用。希望这有所帮助。 - Neptilohttp_response_code()
不能用于自定义错误代码。例如,http_response_code(930)
将导致 Apache 日志文件正确显示 930,但实际上会向客户端发送错误 500。对于这种奇怪的用例,请改用 header()
方法。 - jlhhttp_response_code()
函数在读取状态码方面是不可靠的。使用header()
函数设置的头部信息优先级更高,并且HTTP/1.1 <code> <format>
格式优先于Status: <code> <msg>
格式 - 至少在FCGI和nginx上是如此。 - undefinedsubstr($sapi_type, 0, 3) == 'cgi'
无法足够检测到FastCGI。当使用PHP-FPM FastCGI进程管理器时,php_sapi_name()
返回的是fpm而不是cgi。header('X-PHP-Response-Code: 404', true, 404);
无法正常工作。header("HTTP/1.1 404 Not Found");
可能会失败。当前协议必须使用$_SERVER['SERVER_PROTOCOL']
来检测(自PHP 4.1.0起可用)。http_response_code()
时,至少有两种情况会导致意外行为:
- 当PHP遇到无法理解的HTTP响应代码时,PHP会用同一组中它了解的代码替换该代码。例如,"521 Web server is down"会被替换为"500 Internal Server Error"。许多其他来自2xx、3xx、4xx等其他组的不常见响应代码也会以这种方式处理。
- 在具有php-fpm和nginx的服务器上,http_response_code()函数可能会按预期更改代码,但不会更改消息。这可能导致出现奇怪的"404 OK"头。这个问题也在PHP网站上的Richard F.的用户评论中提到过。http_response_code(521);
$httpStatusCode = 521;
$httpStatusMsg = 'Web server is down';
$phpSapiName = substr(php_sapi_name(), 0, 3);
if ($phpSapiName == 'cgi' || $phpSapiName == 'fpm') {
header('Status: '.$httpStatusCode.' '.$httpStatusMsg);
} else {
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
header($protocol.' '.$httpStatusCode.' '.$httpStatusMsg);
}
结论
http_response_code() 的实现不支持所有的HTTP响应代码,并且可能会用同一组中的另一个代码覆盖指定的HTTP响应代码。
新的http_response_code() 函数并没有解决所有的问题,反而引入了新的错误。
@dualed 提供的“兼容性”解决方案并不能按预期工作,至少在PHP-FPM下不行。
@dualed 提供的其他解决方案也存在各种错误。快速CGI检测无法处理PHP-FPM。必须检测当前协议。
欢迎进行任何测试和评论。
http_response_code()
来获取和设置标头状态码。以下是一个示例:<?php
// Get the current response code and set a new one
var_dump(http_response_code(404));
// Get the new response code
var_dump(http_response_code());
?>
这里是php.net上关于该函数的文档:
如果您没有使用输出缓冲,请在任何body输出之前添加此行。
header("HTTP/1.1 200 OK");
将消息部分('OK')替换为适当的消息,状态码也根据情况替换为您的代码(404、501等)
如果您因为WordPress在加载环境时出现404错误而来到这里,这应该可以解决问题:
define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
status_header( 200 );
//$wp_query->is_404=false; // if necessary
define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");
header("HTTP/1.1 200 OK");
http_response_code(201);
header("Status: 200 All rosy");
http_response_code(200);不起作用,因为测试警告404。 https://developers.google.com/speed/pagespeed/insights/
<?php
function http_response_code($code = NULL) {
if ($code !== NULL) {
switch ($code) {
case 100: $text = 'Continue';
break;
case 101: $text = 'Switching Protocols';
break;
case 200: $text = 'OK';
break;
case 201: $text = 'Created';
break;
case 202: $text = 'Accepted';
break;
case 203: $text = 'Non-Authoritative Information';
break;
case 204: $text = 'No Content';
break;
case 205: $text = 'Reset Content';
break;
case 206: $text = 'Partial Content';
break;
case 300: $text = 'Multiple Choices';
break;
case 301: $text = 'Moved Permanently';
break;
case 302: $text = 'Moved Temporarily';
break;
case 303: $text = 'See Other';
break;
case 304: $text = 'Not Modified';
break;
case 305: $text = 'Use Proxy';
break;
case 400: $text = 'Bad Request';
break;
case 401: $text = 'Unauthorized';
break;
case 402: $text = 'Payment Required';
break;
case 403: $text = 'Forbidden';
break;
case 404: $text = 'Not Found';
break;
case 405: $text = 'Method Not Allowed';
break;
case 406: $text = 'Not Acceptable';
break;
case 407: $text = 'Proxy Authentication Required';
break;
case 408: $text = 'Request Time-out';
break;
case 409: $text = 'Conflict';
break;
case 410: $text = 'Gone';
break;
case 411: $text = 'Length Required';
break;
case 412: $text = 'Precondition Failed';
break;
case 413: $text = 'Request Entity Too Large';
break;
case 414: $text = 'Request-URI Too Large';
break;
case 415: $text = 'Unsupported Media Type';
break;
case 500: $text = 'Internal Server Error';
break;
case 501: $text = 'Not Implemented';
break;
case 502: $text = 'Bad Gateway';
break;
case 503: $text = 'Service Unavailable';
break;
case 504: $text = 'Gateway Time-out';
break;
case 505: $text = 'HTTP Version not supported';
break;
default:
exit('Unknown http status code "' . htmlentities($code) . '"');
break;
}
$protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0');
header($protocol . ' ' . $code . ' ' . $text);
$GLOBALS['http_response_code'] = $code;
} else {
$code = (isset($GLOBALS['http_response_code']) ? $GLOBALS['http_response_code'] : 200);
}
return $code;
}