簡體   English   中英

PHP:如何發送 HTTP 響應代碼?

[英]PHP: How to send HTTP response code?

我有一個 PHP 腳本,需要使用 HTTP 響應代碼(狀態代碼)做出響應,比如 HTTP 200 OK,或者一些 4XX 或 5XX 代碼。

我怎樣才能在 PHP 中做到這一點?

我剛剛發現了這個問題,並認為它需要一個更全面的答案:

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 開始, header函數有第三個參數,可以讓您輕松地設置響應代碼,但使用它需要第一個參數是非空字符串。 這里有兩個選項:

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

我推薦第二個 第一個確實適用於我測試過的所有瀏覽器,但一些較小的瀏覽器或網絡爬蟲可能會遇到標題行僅包含冒號的問題。 標題字段名稱在 2 中。 變體當然沒有以任何方式標准化並且可以修改,我只是選擇了一個有希望的描述性名稱。

http_response_code 函數(PHP >= 5.4)

http_response_code()函數在PHP 5.4引入的,它使事情更容易。

http_response_code(404);

就這樣。

兼容性

這是我在需要低於 5.4 的兼容性但想要“新” http_response_code函數的功能時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;
    }
}

不幸的是,我發現@dualed 提出的解決方案存在各種缺陷。

  1. 使用substr($sapi_type, 0, 3) == 'cgi'不足以檢測快速 CGI。 使用 PHP-FPM FastCGI 進程管理器時, php_sapi_name()返回 fpm 而不是 cgi

  2. Fasctcgi 和 php-fpm 暴露了@Josh 提到的另一個錯誤 - using header('X-PHP-Response-Code: 404', true, 404); 在 PHP-FPM (FastCGI) 下正常工作

  3. header("HTTP/1.1 404 Not Found"); 當協議不是 HTTP/1.1(即“HTTP/1.0”)時可能會失敗。 必須使用$_SERVER['SERVER_PROTOCOL']檢測當前協議(自 PHP 4.1.0 起可用

  4. 調用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);

服務器將發送“500 Internal Server Error”HTTP 響應代碼,導致意外錯誤,例如,如果您有一個自定義客戶端應用程序調用您的服務器並期待一些額外的 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。 必須檢測當前協議。

任何測試和評論表示贊賞。

自 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

如果您不使用輸出緩沖,請在正文的任何​​輸出之前添加此行。

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

問題是由於它發送了一個 Status: 404 Not Found 標頭。 你必須覆蓋它。 這也將起作用:

define('WP_USE_THEMES', false);
require('../wp-blog-header.php');
header("HTTP/1.1 200 OK");
header("Status: 200 All rosy");

標題功能。 在它采用的第一個參數的部分中有一個示例。

如果您的 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;
    }
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腳本,需要使用HTTP響應代碼(狀態代碼)進行響應,例如HTTP 200 OK,或一些4XX或5XX代碼。

如何在PHP中做到這一點?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM