我有一个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

3rd标头函数的参数(PHP> = 4.3)

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

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

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


我推荐第二个。第一个在我测试过的所有浏览器上都可以使用,但是某些次要浏览器或Web爬网程序可能会出现标题行仅包含冒号的问题。标头字段名称在第二位。当然,变体没有经过任何标准化,可以修改,我只是选择了一个描述性的名称。

http_response_code函数(PHP> = 5.4)

http_response_code()函数是


http_response_code(404);


就这么简单。

兼容性

当我需要低于5.4的兼容性但想要“新的” http_response_code功能的功能时,这是我准备的功能。我相信PHP 4.3足够向后兼容,但您永远不知道...

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


评论


我可以确认标头(“ X-PHP-Response-Code:404”,是,是404);可以在PHP-FPM(FastCGI)下正常工作

–乔什
13年5月23日在16:36



@dualed(1)在调用header()之后,headers_sent()不会始终为true吗? (2)在5.4世界中找到过类似http_response_text()的东西吗?至少旧的header()会影响状态代码后的文本。

–鲍勃·斯坦(Bob Stein)
13年8月18日在20:39

@ BobStein-VisiBone(1)headers_sent()为true,如果您因为已经发送了内容而不能再添加任何标头,则不是,如果您添加了标头,则为true。 (2)对不起,没有。其他语言虽然有更好的支持

–已对偶
13年8月19日在5:39



@Perry我不建议这样做的原因与我不建议仅使用冒号的原因相同。 PHP在整个版本中可能处理不同的问题,因为未定义此类“标头”会发生什么,它可能会完全失败-不设置标头或状态,或者可能添加无效的标头(http 1.1协议标准要求使用冒号) )

–已对偶
14年2月16日在10:37

我花了几个小时才意识到在您回声之后,http_response_code(也许更一般地修改标头)不再起作用。希望能帮助到你。

– Neptilo
14-10-24在18:33

#2 楼

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


使用substr($sapi_type, 0, 3) == 'cgi'不足以检测快速CGI。当使用PHP-FPM FastCGI Process Manager时,php_sapi_name()返回fpm而不是cgi
Fasctcgi和php-fpm暴露了@Josh提到的另一个错误-使用header('X-PHP-Response-Code: 404', true, 404);在PHP-FPM(FastCGI)下可以正常工作
header("HTTP/1.1 404 Not Found");可能会失败当协议不是HTTP / 1.1(即“ HTTP / 1.0”)时。当前协议必须使用$_SERVER['SERVER_PROTOCOL']进行检测(自PHP 4.1.0起可用。

至少有2种情况,调用http_response_code()会导致意外行为:


当PHP时遇到无法理解的HTTP响应代码,PHP将用同一组中已知的HTTP响应代码替换该代码。例如,“ 521 Web服务器已关闭”被替换为“ 500 Internal Server Error”。组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 Internal Server Error” 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。必须检测到当前协议。

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

#3 楼

从PHP 5.4开始,您可以使用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中的函数:

http_response_code

评论


以我的经验,这是最好的答案。

– S
18 Jun 9'在23:32



为什么要使用var_dump()?

–托马斯·冈萨雷斯(Tomas Gonzalez)
1月24日,3:24

但是为什么用var_dump()代替echo?结果可能不适合简单的回声吗?甚至是print_r()。 var_dump()似乎不足以用于生产代码...

–托马斯·冈萨雷斯(Tomas Gonzalez)
1月29日16:12

@TomasGonzalez没什么大不了的,我只是想通过使用var_dump()打印所有内容来向您展示其中的内容,而对它们并不重要

–眼神阿里·罗山(Ali Roshan)
1月31日18:53

好的我明白了。引起我注意的是,在官方文档中,该示例还使用了var_dump()。所以我很好奇这样做的原因。可能是我想念的东西。 php.net/manual/en/function.http-response-code.php

–托马斯·冈萨雷斯(Tomas Gonzalez)
2月1日14:56

#4 楼

如果您不使用输出缓冲,请在主体的任何输出之前添加此行。

header("HTTP/1.1 200 OK");


用适当的位置替换消息部分(“确定”)消息,以及包含您的代码的状态代码(如404、501等)

评论


我们发布的消息(可以替换为OK)可以是什么吗?

–FMaz008
2011年10月7日18:02



这对我有用。我正在使用PHP 5.3处理网站上的联系表。这个解决方案对我有用。它将为AJAX请求完成失败功能提供响应文本和此HTTP代码。这就是我想要的。

– Surjith S M
2月20日13:14



#5 楼

如果您在这里是因为Wordpress在加载环境时提供404,则应该解决此问题:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
status_header( 200 );
//$wp_query->is_404=false; // if necessary


问题是由于它发送状态:404未找到标头。您必须重写它。
这也将起作用:

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”); //工作

– alpc
19年8月7日在22:35



#6 楼

具有标题功能。本节中有一个示例,介绍了它需要使用的第一个参数。

#7 楼

如果您的PHP版本不包含此功能:

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


#8 楼

我们可以通过两个不同的环境从http_response_code获得不同的返回值:


Web服务器环境
CLI环境

在Web服务器环境中,返回先前的响应代码(如果您提供了响应代码)或未提供任何响应代码,则将打印当前值。默认值为200(确定)。

在CLI Environment中,如果提供了响应代码,则返回true;如果不提供任何response_code,则返回false。

Response_code返回值的Web服务器环境示例:

var_dump(http_respone_code(500)); // int(200)
var_dump(http_response_code()); // int(500)


Response_code返回值的CLI环境示例:

var_dump(http_response_code()); // bool(false)
var_dump(http_response_code(501)); // bool(true)
var_dump(http_response_code()); // int(501)


#9 楼

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/