PHP: как отправить код ответа HTTP?

У меня есть PHP-скрипт, который должен отправлять ответы с кодами ответа HTTP (кодами состояния), такими как HTTP 200 OK или какой-то код 4XX или 5XX.

Как я могу сделать это в PHP?


person Paulo Coghi    schedule 15.07.2010    source источник
comment
Ни в одном из ответов не сказано, что делать после вызова header () для ошибки 404, обнаруженной в PHP-коде. Выход () в порядке?   -  person David Spector    schedule 04.07.2021


Ответы (9)


Я только что нашел этот вопрос и подумал, что на него нужен более исчерпывающий ответ:

Начиная с 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 или веб-сервером и плохо документирован.

Начиная с 4.3, функция header имеет 3-й аргумент, который позволяет вам довольно удобно установить код ответа, но для его использования требуется, чтобы первый аргумент был непустой строкой. Вот два варианта:

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

Я рекомендую второй. Первый действительно работает во всех браузерах, которые я тестировал, но у некоторых второстепенных браузеров или поисковых роботов могут возникнуть проблемы со строкой заголовка, содержащей только двоеточие. Имя поля заголовка во втором. вариант, конечно, не стандартизирован и может быть изменен, я просто выбрал, надеюсь, информативное имя.

функция http_response_code (PHP> = 5.4)

Функция http_response_code() была представлена ​​в PHP 5.4, и она сделала вещи намного проще.

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;
    }
}
person dualed    schedule 18.08.2012
comment
@dualed (1) не будет headers_sent() всегда верно сразу после вызова header()? (2) найти что-нибудь вроде http_response_text () в мире 5.4? По крайней мере, старый header () может повлиять на текст после кода состояния. - person Bob Stein; 19.08.2013
comment
@ BobStein-VisiBone (1) headers_sent() верно, если вы не можете добавить больше заголовков, потому что контент уже был отправлен, а не если вы добавили заголовок. (2) К сожалению, нет. Однако другие языки имеют лучшую поддержку - person dualed; 19.08.2013
comment
Что-то, что я делаю, о чем я не упоминал, - это указать строку для заголовка, которая не содержит двоеточия header('none', false, $response);, что приводит к желаемому коду ответа и без дополнительного заголовка. - person Perry; 14.02.2014
comment
@Perry, причина, по которой я не предлагаю этого делать, та же, почему я не предлагаю только двоеточие. PHP может обрабатывать это по-разному во всех версиях, так как не определено, что происходит с таким заголовком, он может полностью выйти из строя - не устанавливая ни заголовок, ни статус, или он может добавить недопустимый заголовок (стандарт протокола http 1.1 требует < / b> двоеточие) - person dualed; 16.02.2014
comment
чтобы быть еще более общим, можно было бы использовать: header ($ _ SERVER ['SERVER_PROTOCOL']. '404 Not Found', true, 404); - person Bill'o; 28.02.2014
comment
Я часами понимал, что http_response_code (и, возможно, в более общем плане изменение заголовка) больше не работает после того, как вы что-то echo. Надеюсь, это поможет. - person Neptilo; 24.10.2014
comment
Добавление header_remove () (для ›php 5.3) даже удалит заголовок мусора. Кроме того, обратите внимание, что исходный код должен возвращаться в случае установки нового кода ответа. - person user23127; 02.01.2015
comment
@Josh, не могли бы вы подтвердить, имели ли вы в виду, что работает должным образом или не работает должным образом для PHP-FPM? Ответ Григоре Мадалина подразумевает, что вы предполагаете наличие ошибки, но и вы, и он используете действительно работает. - person icc97; 15.11.2015
comment
@ icc97: Я могу подтвердить, что форма: header('Status: 301 Moved Permanently'); header("Location: $url", true, 301); отправляет HTTP/1.1 301 Moved Permanently и новое местоположение. Также работает для 404 (очевидно, без заголовка местоположения) - person Josh; 15.11.2015
comment
Для 404 я использую: header('Status: 404 Not Found',true,404); под PHP-FPM - person Josh; 15.11.2015
comment
http_response_code() нельзя использовать для создания пользовательских кодов ошибок. Например, http_response_code(930) приведет к тому, что файл журнала apache будет правильно отображать 930, но на самом деле клиенту будет отправлена ​​ошибка 500. Вместо этого используйте метод header() для этого, по общему признанию, странного варианта использования. - person jlh; 31.08.2016

К сожалению, я обнаружил, что решения, представленные @dualed, имеют различные недостатки.

  1. Использование substr($sapi_type, 0, 3) == 'cgi' недостаточно для обнаружения быстрого CGI. При использовании PHP-FPM FastCGI Process Manager php_sapi_name() возвращает fpm, а не cgi

  2. Fasctcgi и php-fpm обнаруживают еще одну ошибку, упомянутую @Josh - использование 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. Существует как минимум 2 случая, когда вызов http_response_code() приводит к неожиданному поведению:

    • When PHP encounter an HTTP response code it does not understand, PHP will replace the code with one it knows from the same group. For example "521 Web server is down" is replaced by "500 Internal Server Error". Many other uncommon response codes from other groups 2xx, 3xx, 4xx are handled this way.
    • На сервере с php-fpm и nginx функция http_response_code () МОЖЕТ изменить код, как ожидалось, но не сообщение. Например, это может привести к появлению странного заголовка «404 OK». Эта проблема также упоминается на веб-сайте PHP в комментарии пользователя http://www.php.net/manual/en/function.http-response-code.php#112423

Для справки здесь приведен полный список кодов состояния ответа HTTP (этот список включает коды из интернет-стандартов IETF, а также других RFC IETF. Многие из них в настоящее время НЕ поддерживаются функцией PHP http_response_code): http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

Вы можете легко проверить эту ошибку, позвонив:

http_response_code(521);

Сервер отправит HTTP-код ответа «500 Internal Server Error», что приведет к неожиданным ошибкам, если, например, у вас есть пользовательское клиентское приложение, вызывающее ваш сервер и ожидающее некоторых дополнительных кодов HTTP.


Мое решение (для всех версий PHP, начиная с 4.1.0):

$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. Текущий протокол должен быть обнаружен.

Любые тесты и комментарии приветствуются.

person Grigore Madalin    schedule 21.04.2014

начиная с 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://php.net/manual/en/function.http-response-code.php

person Seyed Ali Roshan    schedule 06.01.2017
comment
По моему опыту, это лучший ответ. - person Scruffy; 10.06.2018
comment
Зачем использовать var_dump ()? - person Tomas Gonzalez; 24.01.2020
comment
Но почему var_dump () вместо echo? Может результат не подходит для простого эха? Или даже print_r (). var_dump () кажется не подходящим для производственного кода ... - person Tomas Gonzalez; 29.01.2020
comment
@TomasGonzalez, это не имеет большого значения, я просто хотел показать вам, что в нем, распечатав все с помощью var_dump (), и ур, верно, они не важны - person Seyed Ali Roshan; 31.01.2020
comment
Да я вижу. Мое внимание привлекло то, что в официальной документации в примере также используется var_dump (). Поэтому мне было любопытно, почему это произошло. Могло быть что-то, чего мне не хватало. https://www.php.net/manual/en/function.http-response-code.php - person Tomas Gonzalez; 01.02.2020
comment
@TomasGonzalez Если вы проверите раздел «Возвращаемые значения» на только что упомянутой вами странице, вы увидите, как http_response_code будет возвращать значения. И по причине использования var_dump, а не чего-то вроде echo, вы можете проверить, как работают эти функции. echo может получать только строки в качестве входных данных, var_dump может использовать все, что вы ему даете, и выводит не только переменную, но и ее тип. - person Morteza Sadri; 07.03.2020

Добавьте эту строку перед любым выводом тела, если вы не используете буферизацию вывода.

header("HTTP/1.1 200 OK");

Замените часть сообщения («ОК») соответствующим сообщением, а код состояния - соответствующим кодом (404, 501 и т. Д.).

person sparkey0    schedule 15.07.2010
comment
Может ли сообщение, которое мы помещаем (заменить ОК), может быть чем угодно? - person FMaz008; 07.10.2011
comment
Это сработало для меня. Я работал над контактной формой на веб-сайте с PHP 5.3. И это решение сработало для меня. Он предоставит текст ответа и этот HTTP-код для функции сбоя запроса AJAX. Это все, что я хотел. - person Surjith S M; 20.02.2020

Если вы здесь из-за того, что 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");
person jaggedsoft    schedule 13.08.2013
comment
заголовок (HTTP / 1.1 200 OK); http_response_code (201); заголовок (Статус: 200 Все радужно); // Работа - person alpc; 08.08.2019

С помощью функции заголовка. В разделе есть пример первого параметра.

person Quentin    schedule 15.07.2010

Если ваша версия 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;
    }
person Abdo-Host    schedule 18.12.2019

Мы можем получить другое возвращаемое значение из http_response_code через две разные среды:

  1. Среда веб-сервера
  2. Среда CLI

В среде веб-сервера верните предыдущий код ответа, если вы предоставили код ответа или если вы не предоставили никакого кода ответа, тогда будет напечатано текущее значение. Значение по умолчанию - 200 (ОК).

В среде CLI будет возвращено true, если вы указали код ответа, и false, если вы не укажете response_code.

Пример среды веб-сервера для возвращаемого значения Response_code:

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

Пример среды CLI для возвращаемого значения Response_code:

var_dump(http_response_code()); // bool(false)
var_dump(http_response_code(501)); // bool(true)
var_dump(http_response_code()); // int(501)
person GaziAnis    schedule 17.03.2019

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/

person alpc    schedule 07.04.2016