Как исправить "Headers already sent" в PHP: полный гайд

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: "Вы что-то уже отправили на экран, а я не могу"

Если вы когда-нибудь видели на своём сайте вместо красивой страницы белый экран с пугающим сообщением Warning: Cannot modify header information - headers already sent — вы не одиноки. Это, пожалуй, одна из самых популярных ошибок среди начинающих (и не только) PHP-разработчиков. На Stack Overflow этот вопрос набрал сотни тысяч просмотров, а количество копий неправильного кода в мире измеряется терабайтами.

Но хорошая новость в том, что ошибка «Headers already sent» — это не проклятие, а просто строгое напоминание от PHP: «Эй, ты уже начал отправлять HTML-код, а теперь пытаешься изменить HTTP-заголовки. Так нельзя!».

В этой статье мы разберём, почему возникает ошибка headers already sent в PHP, как её найти и, самое главное, как исправить раз и навсегда. Поехали!

1. Что такое HTTP-заголовки и почему они "уже отправлены"?

Прежде чем лезть в код, давайте на пальцах разберёмся, что происходит «под капотом». Когда PHP-скрипт выполняется, он сначала отправляет браузеру HTTP-заголовки (header). В них содержится служебная информация: тип контента (Content-Type), куки (Set-Cookie), редиректы (Location), статус ответа (200, 404, 301) и так далее.

И только после всех заголовков начинается отправка тела документа — того самого HTML, который вы видите на странице. PHP позволяет изменять заголовки только до того момента, как был отправлен первый байт контента.

Как только вы выводите что-то на экран (через echo, print, var_dump или даже просто пробел до <?php), PHP считает, что заголовки уже отправлены. Любая попытка вызвать header(), setcookie() или session_start() после этого приводит к фатальной ошибке.

1.1. Классический пример ошибки

<?php
echo "Привет, мир!";
// Ой! Мы уже что-то вывели.
header("Location: https://example.com");
// Warning: Cannot modify header information - headers already sent
?>

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

2. Топ-5 причин возникновения "Headers already sent"

Ошибка может быть вызвана не только явным echo. Вот самые частые сценарии, которые ловят даже опытных разработчиков:

  • Пробел или пустая строка перед <?php — самый популярный "баг". Если в файле до открывающего тега есть хотя бы один пробел, он будет отправлен в вывод.
  • Невидимые символы BOM (Byte Order Mark) — файл сохранён в кодировке UTF-8 with BOM. Первые 3 байта (EF BB BF) считаются выводом.
  • Вывод из подключаемых файлов — в файле config.php есть лишний пробел после ?>.
  • Ошибки и предупреждения — если PHP выводит предупреждение (например, об использовании неопределённой переменной), это тоже считается отправкой контента.
  • Функции print, printf, var_dump до header() — любая функция вывода ломает заголовки.

3. Как найти источник проблемы: 3 метода

Прежде чем исправлять, нужно найти, откуда берётся «лишний» вывод. Используйте один из этих способов.

3.1. Включаем отображение всех ошибок

Добавьте в начало скрипта (до любого вывода):

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
?>

PHP часто показывает точную строку, где произошёл вывод. Ищите сообщение вроде Output started at /path/to/file.php:12.

3.2. Используем функцию error_get_last()

Можно перехватить последнюю ошибку:

<?php
header("Location: /");
$error = error_get_last();
if ($error) {
    echo "Ошибка: " . $error['message'] . " в строке " . $error['line'];
}
?>

3.3. Проверяем файлы на BOM и лишние пробелы

Откройте все подключаемые файлы (include, require) в вашем редакторе кода. Включите отображение непечатаемых символов. Если видите точки или знаки до <?php или после ?> — удалите их.

Совет: Многие современные редакторы (VS Code, PhpStorm) подсвечивают лишние пробелы. В VS Code включите настройку editor.renderWhitespace: "all".

4. 4 проверенных способа исправить ошибку

Теперь перейдём к практике. Выберите подходящий метод в зависимости от ситуации.

4.1. Удаляем лишний вывод (чистый код)

Это самый правильный способ. Проверьте все файлы на наличие:

  • Пробелов или пустых строк до <?php.
  • Закрывающего тега ?> в конце файла (если после него нет HTML). PHP-файлы могут быть без закрывающего тега — это хорошая практика.
  • Лишних пробелов после ?>.

Пример правильного файла:

<?php
// Нет пробелов до этой строки
$title = "Мой сайт";
// Закрывающий тег не ставим

Если после PHP-кода идёт чистый HTML, то закрывающий тег нужен, но убедитесь, что нет лишних пробелов после него.

4.2. Включаем буферизацию вывода (ob_start)

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

<?php
ob_start(); // Включаем буферизацию в самом начале

// ... ваш код с header() и setcookie() ...

header("Location: https://example.com");
ob_end_flush(); // Отправляем буфер и отключаем буферизацию
?>

Важно: ob_start() должен быть вызван до любого вывода. Лучше всего разместить его в самом начале главного файла (index.php).

4.3. Использу

Блоги

Рекомендаций по книгам