С этой ошибкой ко мне постоянно обращаются и спрашивают: " Где ошибка? ". Подобных писем за всё время я получил где-то штук 500 , не меньше. Пора с ошибкой " Cannot modify header information - headers already sent " уже заканчивать. В этом материале я расскажу о причинах возникновения данной ошибки, а также о том, к...

Cannot modify header information - headers already sent

С этой ошибкой ко мне постоянно обращаются и спрашивают: "Где ошибка?". Подобных писем за всё время я получил где-то штук 500, не меньше. Пора с ошибкой "Cannot modify header information - headers already sent" уже заканчивать. В этом материале я расскажу о причинах возникновения данной ошибки, а также о том, как её решить.

Если перевести данную ошибку на русский язык, то получится примерно следующее: "Нельзя изменить заголовок, поскольку они уже отправлены". Что это за "заголовки"? Давайте разберёмся.

Когда сервер возвращает ответ клиенту, помимо тела (например, HTML-кода страницы), идут ещё и заголовки. В них содержится код ответа сервера, cookie, кодировка и множество других служебных параметров. Может ли PHP-скрипт отправить заголовок? Конечно, может. Для этого существует функция header().

Данная функция, например, постоянно используется при редиректе. Также данная функция регулярно используется при генерации изображении в PHP.

Также заголовки модифицируются при отправке cookie и при начале сессии (функция session_start()).

А теперь о том, почему же всё-таки возникает ошибка? Сервер всегда сначала отдаёт серверу заголовки, а потом тело. Если сервер уже вернул заголовки, потом пошло тело, и тут он встречает какой-нибудь session_start(). Оказывается горе-программист забыл отправить заголовки до начала тела, и теперь хочет догнать уже ушедший поезд.

Вот код с ошибкой "Cannot modify header information - headers already sent":

<html>
<?php
  session_start(); // А давайте начнём сессию
?>

Разумеется, такой бред PHP не прощает. И надо было писать так:

<?php
  session_start(); // А давайте начнём сессию
?>
<html>

Вот этот скрипт уже не вызовет никаких ошибок, потому что сначала отправляются все заголовки, а уже потом идёт генерация тела ответа сервера.

Другой пример кода с ошибкой:

<?php
  echo "Hello!"; // Что-нибудь выведем
  session_start(); // А давайте начнём сессию
?>

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

Как будет правильно переписать данный код, подумайте сами.

Ещё пример:

<?php
  $error = true; // Были ли ошибки?
  if ($error) echo "Произошла ошибка";
  header("Location: ".$_SERVER["HTTP_REFERER"]); // Делаем редирект обратно
  exit;
?>

Когда у автора такого кода, ничего не получается, он удивляется от этой ошибки и говорит: "Очень странное совпадение, когда операция проходит успешно, всё хорошо, а когда какая-то ошибка, мне сообщают Cannot modify header information - headers already sent". Не дословно, но смысл именно в этом.

Проблема та же самая, и правильно писать так:

<?php
  $error = true; // Были ли ошибки?
  if ($error) echo "Произошла ошибка";
  else header("Location: ".$_SERVER["HTTP_REFERER"]); // Делаем редирект обратно
  exit;
?>

Есть и труднозаметные ошибки:

 <?php
  header("Location: ".$_SERVER["HTTP_REFERER"]); // Делаем редирект обратно
  exit;
?>

Ошибка в данном коде возникает из-за пробела, который присутствует перед <?php. Пробел - это обычный символ, и он является частью тела ответа. И когда сервер его видит, он делает вывод о том, что заголовков больше не будет и пора выводить тело.

Бывают и следующие ошибки, имеющие всё ту же природу. Допустим есть файл a.html:

<?php echo "Hello"; ?>

Далее есть другой файл с таким кодом:

<?php
  require_once "a.html";
  header("Location: ".$_SERVER["HTTP_REFERER"]); // Делаем редирект обратно
  exit;
?>

И человек искренне удивляется, откуда ошибка, если он ничего не выводил? Поэтому смотреть надо не конкретно 1 файл, а все файлы, которые подключаются в нём. И в тех, что подключаются у подключаемых, тоже надо смотреть, чтобы не было вывода.

И последний момент, но уже более сложный. Оказывается, что иногда эта ошибка происходит и при правильном коде. Тогда всё дело в кодировке. Убедитесь, что кодировка файла "UTF-8 без BOM", причём именно "без BOM", а не просто "UTF-8". Поскольку BOM - это байты, идущие в самом начале файла, и они являются выводом.

Очень надеюсь, что этот материал поможет решить абсолютно все проблемы, связанные с ошибкой "Cannot modify header information - headers already sent", поскольку я постарался осветить все возникающие проблемы. А дальше надо включить голову, и подумать, а что в Вашем коде не так?