Xpoint
   [напомнить пароль]

location(Status|HTTP 1.x) и версия PHP

2006-09-02 05:03:07 [обр] Eugene Efremov [досье]

Как известно, передать HTTP status code в PHP можно двумя способами:

  1. header("Status: 403 Forbidden")
  2. header("HTTP/1.1 403 Forbidden")

Проблема в том, что эти способы, кажется, могут работать или не работать в зависимости от разных факторов, прежде всего от того, установлен ли PHP как модуль апача или же как CGI.

Четко я установил следующее:

  1. PHP5 (любой версии, проверено многократно), установленый как CGI-приложение, нормально работает со Status:....
  2. PHP 4.4.0, установленный как модуль аппача, нормальмо работает с HTTP/..., на Status:... — возвращает 200 и добавляет заголовок Status в неизменном виде.
  3. PHP 5.1.4 CGI на HTTP/1.1 403 Forbidden выдает ответ HTTP/1.х 403 Ok.

Интересует, прежде всего, как себя поведет PHP5, установленый как модуль апача. Кто-нибудь тут может это проверить?

А также — от каких еще факторов (версия апача, опрерационка, температура за окном, etc) зависит такое поведение PHP. Сам тестил под видной, Apache/1.3.33.

спустя 6 часов [обр] Thomas [досье]
А под Linux не пробовал ? Windows sucks.
спустя 3 часа 9 минут [обр] Eugene Efremov [досье]

Проверил на PHP 5.1.4/CGI под FreeBSD, Apache 1.3.37. Результат совершенно аналогичен испытаниям под виндой. Так что, по-видимому, от операционки не зависит.

Главный вопрос остается в силе: как поведет себя PHP5, установленый как модуль апача, с каждым из этих заголовков? У меня самого его сейчас нет, к сожалению, под рукой.

спустя 41 минуту [обр] Давид Мзареулян [досье]

Status: — это (более-менее) стандартный способ выдачи статусного заголовка для CGI-скриптов. Т.е. не только PHP, но и любая другая программа в CGI-режиме может выдать эту строку, и Апач сам из неё сделает правильный статус. Так что в CGI-mode Status: гарантированно должен работать.

Что касается PHP как модуля, то тут уже надо смотреть. Но вообще, Status: в модуле работать не обязан.

спустя 53 минуты [обр] Владимир Михайленко [досье]
как поведет себя PHP5, установленый как модуль апача, с каждым из этих заголовков?
  1. header("Status: 403 Forbidden");
HTTP/1.0 200 OK
Date: Sat, 02 Sep 2006 11:54:40 GMT
Server: Apache/1.3.33 (Win32) PHP/5.0.4
X-Powered-By: PHP/5.0.4
Status: 403 Forbidden
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html
  1. header("HTTP/1.1 403 Forbidden");
HTTP/1.0 403 Forbidden
Date: Sat, 02 Sep 2006 11:56:39 GMT
Server: Apache/1.3.33 (Win32) PHP/5.0.4
X-Powered-By: PHP/5.0.4
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html
спустя 48 минут [обр] Eugene Efremov [досье]

Владимир Михайленко[досье], спасибо.

Правда, за это время я успел поставить себе другой аппач, на него mod_php5, и проверить на нем. PHP 5.1.2, результат тот же. Окончательный вывод: такое поведение не зависит от версии PHP.

Таблица установки заголовков

header()"Status: 403 Forbidden""HTTP/1.1 403 Forbidden"
mod_phpHTTP/1.0 200 OKHTTP/1.x 403 Forbidden
Status: 403 Forbidden
CGIHTTP/1.x 403 ForbiddenHTTP/1.x 403 Ok

Вывод: Для CGI используем Status, для модуля — HTTP.

P.S. Кстати, существует ли оффициальный способ отличить одно от другого изнутри скрипта? Я сам пока использую function_exists('apache_get_version'). Если нету — значит это CGI. У этого способа тот недостаток, что существует, хотя и очень маленькая, вероятность того, что юзер вздумает для CGI-версии проэмулировать apache_get_version своими силами...

P.P.S. А вообще — для верности надо бы еще все это дело под Apache 2 проверить...

спустя 6 часов [обр] Александр Лукьянов [досье]

Eugene Efremov[досье]
Юзайте php_sapi_name()

define(
  'STATUS',
  (php_sapi_name() == 'cgi')? "Status: " : "HTTP/1.1 "
);
...
header(STATUS . "403 Forbidden");

и будет Вам щастье :)

Что касается последнего:

CGI HTTP/1.x 403 Forbidden => HTTP/1.x 403 Ok

Насколько я понимаю, главное, что возвращается правильный числовой статус, reason phrase ("Forbidden", "OK" и т.п.) вроде всегда просто для информации, и особого значения не имеет. Хотя некрасиво, конечно. Похожее обсуждение — http://bugs.php.net/bug.php?id=27345

спустя 13 часов [обр] Eugene Efremov [досье]

Александр Лукьянов[досье], спасибо!

В завершенее дискуссии — небольшая библиотечка для этого дела:

class XHttpStatus
{
  protected static $status = array
  (
    100 => '100 Continue',
    101 => '101 Switching Protocols',
    102 => '102 Processing',
    200 => '200 OK',
    201 => '201 Created',
    202 => '202 Accepted',
    203 => '203 Non-Authoritative Information',
    204 => '204 No Content',
    205 => '205 Reset Content',
    206 => '206 Partial Content',
    207 => '207 Multi Status',
    226 => '226 IM Used',
    300 => '300 Multiple Choices',
    301 => '301 Moved Permanently',
    302 => '302 Found',
    303 => '303 See Other',
    304 => '304 Not Modified',
    305 => '305 Use Proxy',
    306 => '306 (Unused)',
    307 => '307 Temporary Redirect',
    400 => '400 Bad Request',
    401 => '401 Unauthorized',
    402 => '402 Payment Required',
    403 => '403 Forbidden',
    404 => '404 Not Found',
    405 => '405 Method Not Allowed',
    406 => '406 Not Acceptable',
    407 => '407 Proxy Authentication Required',
    408 => '408 Request Timeout',
    409 => '409 Conflict',
    410 => '410 Gone',
    411 => '411 Length Required',
    412 => '412 Precondition Failed',
    413 => '413 Request Entity Too Large',
    414 => '414 Request-URI Too Long',
    415 => '415 Unsupported Media Type',
    416 => '416 Requested Range Not Satisfiable',
    417 => '417 Expectation Failed',
    420 => '420 Policy Not Fulfilled',
    421 => '421 Bad Mapping',
    422 => '422 Unprocessable Entity',
    423 => '423 Locked',
    424 => '424 Failed Dependency',
    426 => '426 Upgrade Required',
    449 => '449 Retry With',
    500 => '500 Internal Server Error',
    501 => '501 Not Implemented',
    502 => '502 Bad Gateway',
    503 => '503 Service Unavailable',
    504 => '504 Gateway Timeout',
    505 => '505 HTTP Version Not Supported',
    506 => '506 Variant Also Varies',
    507 => '507 Insufficient Storage',
    509 => '509 Bandwidth Limit Exceeded',
    510 => '510 Not Extended'
  );
  
  
  static public function get_str($code)
  {
    return self::$status[$code];
  }
  
  static public function set($code)
  {
    // CGI or mod_php ?
    $header = (php_sapi_name() == 'cgi') ? 'HTTP/1.1 ' : 'Status: ';
    header($header.self::$status[$code]);
  }
}

Думаю, этот список заголовков может быть кому-нибудь полезным :-)

P.S. Единственное, что осталось проверить — это то, как это дело ведет себя под вторым апачем. Хотя, думаю, там особых отличий не будет...

Powered by POEM™ Engine Copyright © 2002-2005