Внеочередное перенаправление 301/302 с PHP

Я столкнулся с случайным использованием заголовка Status для FastCGI. Есть ли плюсы/минусы использования этого в сценариях, не зависящих от среды?

header('Location: ' . $url, true, 301);

самостоятельно не вызывает проблем для меня на Apache 2.2 (согласно phpinfo(), сервер использует FastCGI).

script предназначен для Apache и nginx (mod_php и FastCGI). Как выглядело бы неуверенное решение?

Ответ 1

Код состояния HTTP испускается как часть первой строки ответа HTTP. Согласно Fast CGI FAQ заголовок состояния - это специальный заголовок, распознаваемый сервером, который контролирует эту строку и не отправляется клиенту. Однако, если он используется с адаптером сервера FastCGI, значение игнорируется сервером, и заголовок может быть отправлен.

Решение, которое у вас уже есть, является наиболее безопасным для окружающей среды способом. Единственным добавлением будет оператор exit сразу после перенаправления, чтобы убедиться, что script завершается.

Посмотрите, что происходит под капотом, ближе.

Следующий код перенаправления PHP

header('Location: ' . $url, true, 301);
exit;

Вызвать код C в ext/standard/head.c

PHP_FUNCTION(header)
{
    [ code that just parses the arguments omitted ]

    sapi_header_op(rep ? SAPI_HEADER_REPLACE:SAPI_HEADER_ADD, &ctr);
}

Что в свою очередь вызовет функцию sapi_header_op в main/SAPI.c

[ ... ]

switch (op) {

    [ ... ]

    case SAPI_HEADER_ADD:
    case SAPI_HEADER_REPLACE:
    case SAPI_HEADER_DELETE: {
            sapi_header_line *p = arg;

            if (!p->line || !p->line_len) {
                return FAILURE;
            }
            header_line = p->line;
            header_line_len = p->line_len;
            http_response_code = p->response_code;
            break;
        }

[ code that splits header line by colon, trims whitespace etc ]

[ special headers handling code, including setting 302 if Location  ]

if (http_response_code) {
    sapi_update_response_code(http_response_code);
}

sapi_header_add_op(op, &sapi_header);
return SUCCESS;

Если используется back-end FastCGI, добавленные заголовки будут в конечном итоге отправлены функцией sapi_cgi_send_headers в sapi/cgi/cgi_main.c

[ ... ]
if (CGIG(nph) || SG(sapi_headers).http_response_code != 200)
{
    [ emit status line if cgi.rfc2616-headers is set ]

    [ Handle a case where there is a user supplied status line ]

    [ Handle a case where there is already a user supplied status header ]

    [ if none of the above ]

        if (err->str) {
            len = slprintf(buf, sizeof(buf), "Status: %d %s\r\n", SG(sapi_headers).http_response_code, err->str);
        } else {
            len = slprintf(buf, sizeof(buf), "Status: %d\r\n", SG(sapi_headers).http_response_code);
        }
     [ ... ]
}
[ ... ]

Обратите внимание, что функция php_apache_sapi_send_headers в sapi/apache2handler/sapi_apache2.c не имеет специальной обработки заголовка Status, потому что она не используется для связи с модулем.

Итак, выполнив код PHP выше

  • Код ответа в строке состояния HTTP вынужден 301
  • Заголовок местоположения либо добавлен, либо заменен существующий.
  • script завершается, поэтому последующий код не может изменять статус или заголовки

Все манипуляции выполняются на уровне SAPI, который является абстракционным слоем поверх HTTP-серверных адаптеров (FastCGI, Apache module и т.д.). Это как кросс-среда и надежность, как она становится.

Исторически в FastCGI были ошибки, которые помешали 301 ответам работать корректно, однако это были в реализации веб-сервера, и для устранения этой проблемы не было ничего, что могло бы быть сделано из кода PHP.

См. также: