php Почему не работает редирект Warning: Cannot modify header information - headers already sent by... Ошибка Решение

[продолжение этого вопроса]

Описание частной проблемы

После нажатия на кнопку выводится ошибка:

Warning: Cannot modify header information
 - headers already sent by (output started at C:\OpenServer\domains\testsite\WEB\5_phpRedirect.php:10)
 in C:\OpenServer\domains\testsite\WEB\5_phpRedirect.php on line 12

Код аналогичен приведённому в данной теме:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <title>
            Экспериментальный Web
        </title>
    </head>
    <body>
        <H1> Выберите скрипт для загрузки </H1>
        <form name="form1" method="post" action="5_phpRedirect.php">
            <input type="submit" name="button" value="0_elementsOfHTML">
        </form>
        <form name="form2" method="post" action="5_phpRedirect.php">
            <input type="submit" name="button" value="3_phpServer">
        </form>
    </body>
</html>

Скрипт-обработчик:

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <title>
            Перенаправление пользователя
        </title>
    </head>
    <body>
        <?php
        $redirect = "Location: ". $_REQUEST["button"]. ".html";
        echo header($redirect);
        ?>
    </body>
</html>

Когда это бывает

Ошибка (предупреждение) типа:

Warning: Cannot modify header information - headers already sent by

Возникает, если вы уже сделали что-то что требует установки заголовков браузера, а теперь хотите переписать их новыми. Например, если вы уже вывели текст - то php выставляет заголовки (в частности заголовок Location -- которые показывает оставаться ли на запрошенной странице или же нужно нужно перейти на другую страницу и уже там получить ответ на запрос), чтобы показаться браузеру клиента (в своём ответе) как себя вести.

Корень проблемы

Скорее всего, проблема в вашем случае состоит в том, что вы уже отдаёте контент (html-тэги которые перемешаны в файле со скриптом) до команды:

echo header($redirect);

цитата:

Помните, что функцию header() можно вызывать только если клиенту еще не передавались данные. То есть она должна идти первой в выводе, перед ее вызовом не должно быть никаких HTML тэгов, пустых строк и т.п. Довольно часто возникает ошибка, когда при чтении кода файловыми функциями, вроде include или require, в этом коде попадаются пробелы или пустые строки, которые выводятся до вызова header(). Те же проблемы могут возникать и при использовании одиночного PHP/HTML файла.

-- то есть необходимо избавить скрипт-обработчик от html -- ведь он по сути сам ничего не выводит а просто перебрасывает на другой адрес -- это первое.

Далее, на самом деле заголовок Location следует менять так:

header($redirect);

А не так:

echo header($redirect);

Эксперимент

Так как echo() вообще-то пишет в тело http ответа, а не в заголовки, а header возвращается void (то есть не возвращает значений), о чём было сказано выше, то смысла в использовании echo() нет, но
-- тем не менее, предлагаю провести эксперимент:

  1. уберите html
  2. не убирайте echo

-- так как header() вызывается у вас по сути до echo() (так как header() является аргументом echo()) а значит возврат -- заодно проверим если функция возвращает null -- будет ли это интерпретироваться как пустая строка или же (что вернее) echo даже не начнёт работать как уже произойдёт редирект.

Ещё раз уточним причину

Т.е. перед вызовом header() не должен выводиться никакой контент ( о чем написано к описанию функции: http://php.net/manual/ru/function.header...)

То есть:

  • 1) ни с помощью echo
  • 2) ни с помощью обычного вываливания в браузер html-текста.

В нашем случае судя по всему echo не влияет ни на что, а вот html в обработчике очень даже влияет.

melisa's picture

По Вашему совету были удалены теги HTML. Теперь переадресация происходит корректно, скрипт-обработчик выглядит так:

<?php
header("Location: ". $_REQUEST["button"]. ".php");
?>

Функция echo действительно не влияет на работу, т.е . можно оставить и как у С. Хольцнера:

<?php
$redirect = "Location: ". $_REQUEST["button"]. ".php";
echo header($redirect);
?> 

Также при оформлении кода для редиректа следует обратить внимание на расширение файла, на который производится переход: при предложенном синтаксисе, оно должно быть указано в аргументе header.

Но можно заставить работать и предыдущий обработчик

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <title>
            Перенаправление пользователя
        </title>
    </head>
    <body>
        <?php
        $redirect = "Location: ". $_REQUEST["button"]. ".html";
        echo header($redirect);
        ?>
    </body>
</html>

если выставить в файле php.ini опцию

output_buffering = 4096
vedro-compota's picture

Вот тут хорошо объяснён механизм работы:

По - умолчанию никакой буферизации вывода нет ( если, конечно вы не нашаманили в файле php.ini и не присвоили директиве output_buffering значение On ) и PHP отсылает данные юзеру, сразу, как только они готовы. Согласно протоколу HTTP, сервер в ответ на запрос пользователя, должен сначала отправить ему служебные заголовки, а уже после, тело страницы. А тут внезапно, в коде вы опять пытаетесь заставить его отправить HTTP - заголовки, вызывая, скажем функцию session_start() - после удачной авторизации... Ясен пень - повторная отправка заголовков запрещена, HTTP - протокол так не работает! Но что ж делать то? Если после вывода на странице, нужно ещё и сессию стартануть и кУку поставить? - Вспоминаем про буферизацию вывода.

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

И получается, что мы хотим изменить заголовки, которые уже "улетели" по сети клиенту (а значит, исправить их уже невозможно -- в частности заголовок Location, который указывает оставаться ли на запрошенной странице, или запросить другую -- ответ скрипта-"перенаправителя" (у нас это обработчик формы) как раз говорит о том, что надо запросить другую страницу), о чем php нас и предупреждает.

Но: решать проблему таким способом конечно нельзя (не сильно корректно, точнее).

_____________
матфак вгу и остальная классика =)