PHP:如何发送HTTP响应代码?

2022-08-30 06:04:01

我有一个PHP脚本,需要使用HTTP响应代码(状态代码)进行响应,例如HTTP 200 OK,或一些4XX或5XX代码。

如何在 PHP 中执行此操作?


答案 1

我刚刚发现了这个问题,并认为它需要一个更全面的答案:

PHP 5.4 开始,有三种方法可以实现此目的:

自行组装响应代码 (PHP >= 4.0)

header() 函数有一个特殊的用例,可以检测 HTTP 响应行,并允许你将其替换为自定义响应行。

header("HTTP/1.1 200 OK");

但是,这需要对(Fast)CGI PHP进行特殊处理:

$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原因短语可以是任何自定义字符串(符合标准),但为了客户端兼容性,我不建议在那里放置随机字符串。

注意:php_sapi_name() 需要 PHP 4.0.1

标头函数的第三个参数 (PHP > = 4.3)

使用第一个变体时显然存在一些问题。我认为其中最大的一点是,它部分是由PHP或Web服务器解析的,并且记录得很差。

从 4.3 开始,该函数具有第 3 个参数,可让您稍微轻松地设置响应代码,但使用它需要第一个参数是非空字符串。以下是两个选项:header

header(':', true, 404);
header('X-PHP-Response-Code: 404', true, 404);

我推荐第二个。第一个确实适用于我测试过的所有浏览器,但是一些次要浏览器或Web爬虫可能在仅包含冒号的标题行方面存在问题。第 2 个中的标头字段名称。变体当然没有以任何方式标准化,可以修改,我只是选择了一个希望描述性的名称。

http_response_code函数 (PHP >= 5.4)

http_response_code() 函数是在 PHP 5.4 中引入的,它使事情变得容易得多

http_response_code(404);

就这样。

兼容性

这是我在需要低于5.4的兼容性但想要“新”功能的功能时编写的一个功能。我相信PHP 4.3的向后兼容性绰绰有余,但你永远不知道...http_response_code

// 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;
    }
}

答案 2

不幸的是,我发现@dualed提出的解决方案有各种缺陷。

  1. 使用 不是检测快速 CGI。使用 PHP-FPM FastCGI 进程管理器时,返回 fpm 而不是 cgisubstr($sapi_type, 0, 3) == 'cgi'php_sapi_name()

  2. Fasctcgi 和 php-fpm 暴露了 @Josh 提到的另一个错误 - 在 PHP-FPM (FastCGI) 下使用确实可以正常工作header('X-PHP-Response-Code: 404', true, 404);

  3. header("HTTP/1.1 404 Not Found");当协议不是 HTTP/1.1(即 'HTTP/1.0')时,可能会失败。必须使用(自 PHP 4.1.0 起可用)检测当前协议$_SERVER['SERVER_PROTOCOL']

  4. 至少有 2 种情况下,呼叫会导致意外行为:http_response_code()

  • 当PHP遇到它不理解的HTTP响应代码时,PHP会用它从同一组中知道的代码替换该代码。例如,“521 Web 服务器已关闭”被替换为“500 内部服务器错误”。来自其他组 2xx、3xx、4xx 的许多其他不常见响应代码都以这种方式处理。
  • 在具有php-fpm和nginx的服务器上,http_response_code()函数可能会按预期更改代码,但不能更改消息。例如,这可能会导致一个奇怪的“404 OK”标头。PHP网站上的用户评论也提到了这个问题 http://www.php.net/manual/en/function.http-response-code.php#112423

此处有 HTTP 响应状态代码的完整列表供您参考(此列表包括来自 IETF 互联网标准以及其他 IETF RFC 的代码。PHP http_response_code函数)目前不支持其中许多功能):http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

您可以通过调用以下命令轻松测试此错误:

http_response_code(521);

如果您有一个自定义客户端应用程序需要其他 HTTP 代码,则服务器将发送“500 内部服务器错误”HTTP 响应代码,从而导致错误。


我的解决方案(适用于自4.1.0以来的所有PHP版本):

$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。必须检测当前协议。

任何测试和评论都是值得赞赏的。


推荐