W3docs

Функция headers_sent() в PHP: всё, что нужно знать

Узнайте, как использовать функцию headers_sent() в PHP, чтобы проверить, были ли уже отправлены HTTP-заголовки клиенту, и избежать распространённых ошибок.

Каждый HTTP-ответ состоит из двух частей: блока заголовков (код состояния, Content-Type, куки, редиректы) и тела ответа. Важно помнить, что заголовки должны быть отправлены до любого вывода тела. Как только PHP выводит хотя бы один байт тела, заголовки отправляются и блокируются — любой последующий вызов header(), setcookie() или session_start() вызовет печально известное предупреждение Cannot modify header information - headers already sent.

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

Что делает headers_sent()

headers_sent() возвращает булево значение:

  • true — заголовки уже отправлены (вывод начался). Любой последующий вызов header() / setcookie() завершится неудачей.
  • false — вывод ещё не начался, поэтому заголовки можно устанавливать.

Защита логики заголовков с помощью headers_sent() позволяет избежать предупреждения и корректно обработать ситуацию (например, записать проблему в лог или выполнить JavaScript-редирект вместо HTTP) вместо того, чтобы страница «упала».

Синтаксис

headers_sent(string &$filename = null, int &$line = null): bool

Оба параметра необязательны и передаются по ссылке. Если заголовки уже отправлены, PHP заполняет их данными о том, где начался вывод:

  • $filename — имя исходного файла, в котором вывод начался впервые.
  • $line — номер строки в этом файле.

Именно это делает headers_sent() такой полезной для отладки: она указывает прямо на источник проблемы.

Базовое использование

Проверьте возвращаемое значение перед отправкой заголовка:

<?php

if (!headers_sent()) {
    header('Location: /dashboard');
    exit;
}

echo 'Headers were already sent, cannot redirect via HTTP.';

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

Определение места начала вывода

Передайте две переменные по ссылке, чтобы узнать точно, что отправило заголовки — это незаменимо, когда случайный пробел или echo скрыт в подключённом файле:

<?php

if (headers_sent($file, $line)) {
    echo "Headers already sent in $file on line $line";
} else {
    setcookie('theme', 'dark');
    echo 'Cookie set successfully.';
}

Если условие истинно, вы получите сообщение вида Headers already sent in /var/www/header.php on line 12, которое укажет точно, где искать проблему.

Что вызывает ошибку «Headers Already Sent»

Любой вывод тела до вызова заголовка приводит к их немедленной отправке. Распространённые причины:

  • Пробел или пустая строка перед <?php — даже один пробел или перенос строки считается выводом.
  • Перенос строки после закрывающего ?> подключённого файла. (Рекомендуется вообще опускать закрывающий ?> в файлах, содержащих только PHP.)
  • echo, print, printf или var_dump, запущенные до заголовка.
  • UTF-8-файл, сохранённый с BOM (метка порядка байтов) — эти невидимые ведущие байты являются выводом.
  • PHP-предупреждения и уведомления, выводимые на страницу (когда включён display_errors) до заголовков.

Исправление с помощью буферизации вывода

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

<?php

ob_start();              // start buffering — nothing is sent yet

echo 'Some early output';

// Still safe: the echo above is held in the buffer, headers are not sent
setcookie('user', 'jane');
header('X-App-Version: 2.0');

ob_end_flush();          // now send headers, then the buffered body

Поскольку вывод буферизован, headers_sent() вернёт false даже после echo, а последующие вызовы setcookie() и header() выполнятся успешно.

Связанные функции

  • header() — отправить сырой HTTP-заголовок.
  • headers_list() — список заголовков, поставленных в очередь или уже отправленных.
  • setcookie() — установить куки (отправляет заголовок Set-Cookie).
  • ob_start() — начать буферизацию вывода, чтобы отложить отправку заголовков.
  • PHP Sessionssession_start() тоже отправляет заголовки и часто становится источником проблемы.

Заключение

headers_sent() — небольшая, но важная защитная функция: вызывайте её перед любым header(), setcookie() или session_start(), чтобы проверить, не начался ли уже вывод. Когда она возвращает true, параметры по ссылке $filename и $line указывают точно на проблемный вывод, чтобы вы могли его исправить — или оберните скрипт в ob_start(), чтобы заголовки оставались изменяемыми до момента сброса буфера.

Практика

Практика
Что может вызвать предупреждение 'headers already sent' в PHP?
Что может вызвать предупреждение 'headers already sent' в PHP?
Was this page helpful?