#Симптомы, область применения и причины
После подключения шаблона PHP не может отправить cookie, перенаправление или другой HTTP-заголовок. Как найти ранний вывод, пробелы и BOM до вызова header()/setcookie()/session_start(). Исправлять нужно точку первого вывода, указанную в сообщении «output started at», а не убирать сам заголовок. Особенно часто проблема появляется после вставки HTML-макета или сохранения шаблона с маркером BOM.
| Возможная причина | Как узнать | Что делать |
|---|---|---|
HTML или echo выполнен до заголовковШаблон сразу выводит разметку, а контроллер позже вызывает header или session_start. | Ошибка возникает после включения конкретного шаблона; «output started at» указывает на него. | Переместить формирование заголовков до любого вывода. |
BOM или пробелы в PHP-файлеНевидимые байты до <?php или после ?> становятся телом ответа. | В предупреждении указана первая строка шаблона; визуально вывод отсутствует. | Сохранить чистый UTF-8 без BOM и убрать ненужный закрывающий PHP-тег. |
Предупреждение PHP вывелось в ответ раньшеУведомление об ошибке само стало текстом, отправленным до header. | До основной ошибки браузер показывает Warning/Notice. | Исправить исходное предупреждение; не полагаться на подавление вывода. |
#Безопасная диагностика и пошаговое исправление
- Сохраните полную строку ошибкиВ тестовом окружении воспроизведите действие: вход в систему, перенаправление после формы или установку cookie. Откройте журнал PHP в панели сайта. Запишите оба пути и строки из
headers already sent by (output started at ...:строка) in ... on line .... Первое местоположение указывает, где начался ответ, второе — где пытались отправить заголовок. Не включайте отображение предупреждений на общедоступном сайте.
- Проверьте порядок выполнения в контроллереОткройте указанный PHP-файл в редакторе кода (например, VS Code или редакторе панели). Найдите
include,require,echo, выход из режима?>, HTML-разметку и вызовheader,setcookieилиsession_start. Выводимый шаблон должен запускаться после проверки прав, обработки формы и установки заголовков. Не изменяйте рабочий сайт напрямую: сделайте копию контроллера и проверьте изменения в тестовом окружении.
- Найдите невидимые байты в начале файлаОткройте шаблон, который назван после
output started at, в редакторе с отображением кодировки. В VS Code в нижней строке состояния нажмите на обозначение кодировки; при необходимости выберите «Сохранить с кодировкой» → «UTF-8» без BOM. Проверьте, чтобы до<?phpне было пустых строк или пробелов; для файла с одним PHP-кодом предпочтительно не писать закрывающий тег?>. Если BOM нужен по специфике стороннего файла, согласуйте преобразование с разработчиком.
- Проверьте, отправлялись ли заголовки раньшеВставьте временную проверку
headers_sent($file, $line)непосредственно перед проблемным вызовом заголовка и записывайте значения в закрытый журнал. Если функция возвращает true, первые байты уже отправлены; откройте именно указанный файл и строку. Если false, проверьте другие ветви выполнения или буферизацию: сообщение могло относиться к иному запросу. После диагностики код обязательно удалите. - Пример кода по темеPHPВставлять непосредственно перед
header()/setcookie()в тестовой среде; выводятся сведения только в закрытый журнал.<?php if (headers_sent($file, $line)) { error_log('HTTP output started: '.$file.':'.$line); }
- Перенесите перенаправление перед шаблономВ обработчике после проверки данных формы выполните
header("Location: /account/")и сразуexit, прежде чем подключить визуальный шаблон или сделатьecho. Адрес/account/— лишь пример внутреннего маршрута: используйте реально существующую страницу вашего приложения. Если после этого пользователь видит пустую страницу, сначала проверьте журнал —exitсознательно останавливает рендеринг после редиректа. - Пример кода по темеPHPКод показывает порядок действий, но не готовый контроллер: авторизация и адрес маршрута должны быть реализованы в вашем приложении.
<?php // После успешной авторизации, ДО подключения шаблона: header('Location: /account/', true, 303); exit;
- Не маскируйте ошибку буферизацией
ob_start()может временно отсрочить передачу содержимого, но не гарантирует верный порядок вывода и заголовков. Применяйте буферизацию только если так устроен проект и вы понимаете сброс буферов. Не используйте@header()и глобальное подавление ошибок как исправление: браузер всё равно может получать неправильный ответ.
- Проверьте синтаксис и конечные HTTP-заголовкиВ терминале разработчика выполните
php -lс точным путём копии изменённого PHP-файла, предварительно указав правильное имя после команды, либо используйте синтаксическую проверку редактора. Затем запустите исходное действие в браузере и во вкладке «Сеть» проверьте статус ответа и Location/Set-Cookie. Если переделка нарушила работу, восстановите сохранённый контроллер и шаблон, сравните строки и повторите отладку.
#Как проверить результат и что делать дальше
Работа исправлена, когда на исходном действии нет предупреждения headers already sent, а браузер получает нужный статус, Location или Set-Cookie. Если ошибка осталась, найдите другую точку вывода через headers_sent() и восстановите файлы из копий при неуспешном изменении.