Как исправить ошибку "Заголовки уже отправлены" в PHP
Когда я запускаю свой скрипт, я получаю несколько таких ошибок:
Предупреждение: невозможно изменить информацию заголовка - заголовки уже отправлены (вывод начался с /some/file.php:12) в /some/file.php в строке 23
Строки, упомянутые в сообщениях об ошибках, содержат header()
а также setcookie()
звонки.
Что может быть причиной этого? И как это исправить?
11 ответов
Нет вывода перед отправкой заголовков!
Функции, которые отправляют / изменяют заголовки HTTP, должны быть вызваны перед выполнением любого вывода. резюме ⇊ В противном случае вызов не выполняется:
Предупреждение: невозможно изменить информацию заголовка - заголовки уже отправлены (вывод начат в script: line)
Некоторые функции, изменяющие заголовок HTTP:
header
/header_remove
session_start
/session_regenerate_id
setcookie
/setrawcookie
Вывод может быть:
Непреднамеренное:
- Пробелы перед
<?php
или после?>
- Порядок порядка байтов UTF-8 специально
- Предыдущие сообщения об ошибках или уведомления
- Пробелы перед
Преднамеренное:
print
,echo
и другие функции, производящие вывод- необработанный
<html>
разделы до<?php
код.
Почему это происходит?
Чтобы понять, почему заголовки должны отправляться перед выводом, необходимо взглянуть на типичный HTTP- ответ. Сценарии PHP в основном генерируют контент HTML, но также передают набор заголовков HTTP/CGI веб-серверу:
HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8
<html><head><title>PHP page output page</title></head>
<body><h1>Content</h1> <p>Some more output follows...</p>
and <a href="/"> <img src=internal-icon-delayed> </a>
Страница / вывод всегда следует за заголовками. PHP должен сначала передать заголовки веб-серверу. Это можно сделать только один раз. После двойного разрыва он больше не сможет их исправить.
Когда PHP получает первый вывод (print
, echo
, <html>
) он очистит все собранные заголовки. После этого он может отправить все выходные данные, которые он хочет. Но отправка дальнейших HTTP-заголовков невозможна.
Как узнать, где произошел преждевременный выход?
header()
предупреждение содержит всю необходимую информацию для определения причины проблемы:
Предупреждение: невозможно изменить информацию заголовка - заголовки уже отправлены (вывод начался с / www / usr2345 / htdocs / auth.php: 52) в /www/usr2345/htdocs/index.php в строке 100
Здесь "строка 100" относится к сценарию, где header()
вызов не удался.
Примечание " вывод начался с " в скобках является более значимым. Он обозначает источник предыдущего вывода. В этом примере это auth.php
и линия 52
, Вот где вам пришлось искать преждевременный выход.
Типичные причины:
Печать, эхо
Преднамеренный выход из
print
а такжеecho
операторы прекратят возможность отправки заголовков HTTP. Поток приложений должен быть реструктурирован, чтобы избежать этого. Используйте функции и шаблонные схемы. обеспечиватьheader()
звонки происходят до того, как сообщения будут записаны.Функции, которые производят вывод, включают
print
,echo
,printf
,vprintf
trigger_error
,ob_flush
,ob_end_flush
,var_dump
,print_r
readfile
,passthru
,flush
,imagepng
,imagejpeg
среди других и пользовательских функций.Необработанные области HTML
Непарсированные разделы HTML в
.php
файл прямой вывод, а также. Условия сценария, которые вызовутheader()
вызов должен быть записан до любого необработанного<html>
блоки.<!DOCTYPE html> <?php // Too late for headers already.
Используйте шаблонную схему для отделения обработки от логики вывода.
- Поместите код обработки форм поверх скриптов.
- Используйте временные строковые переменные для отсрочки сообщений.
- Фактическая логика вывода и смешанный вывод HTML должны следовать последним.
Пробелы перед
<?php
для предупреждений "script.php line 1 "Если предупреждение относится к выводу в строке
1
, то это, прежде всего, вводный пробел, текст или HTML перед открытием<?php
маркер.<?php # There's a SINGLE space/newline before <? - Which already seals it.
Аналогичным образом это может происходить для добавленных сценариев или разделов сценариев:
?> <?php
PHP фактически съедает один перевод строки после закрывающих тегов. Но это не компенсирует множественные новые строки, табуляции или пробелы, сдвинутые в такие пробелы.
UTF-8 BOM
Только разрывы строк и пробелы могут быть проблемой. Но есть также "невидимые" последовательности символов, которые могут вызвать это. Наиболее известным является UTF-8 BOM (Byte-Order-Mark), который не отображается большинством текстовых редакторов. Это последовательность байтов
EF BB BF
, что является необязательным и избыточным для документов в кодировке UTF-8. PHP, однако, должен воспринимать это как необработанный вывод. Может отображаться как персонажи
в выводе (если клиент интерпретирует документ как Latin-1) или подобный "мусор".В частности, графические редакторы и IDE на основе Java не замечают его присутствия. Они не визуализируют это (обязано стандартом Unicode). Большинство программистов и консольных редакторов, однако, делают:
Там легко распознать проблему на ранней стадии. Другие редакторы могут определить его присутствие в файле / меню настроек (Notepad++ в Windows может идентифицировать и устранить проблему). Другой вариант проверки присутствия спецификаций - использование шестигранника. В системах *nix
hexdump
обычно доступен, если не графический вариант, который упрощает аудит этих и других вопросов:Простое решение - настроить текстовый редактор для сохранения файлов в формате "UTF-8 (без спецификации)" или подобной номенклатуры. Часто новички в противном случае прибегают к созданию новых файлов и просто копируют и вставляют предыдущий код обратно.
Коррекция коммунальных услуг
Есть также автоматизированные инструменты для проверки и перезаписи текстовых файлов (
sed
/awk
или жеrecode
). Для PHP специально естьphptags
тег более аккуратный. Он переписывает закрытые и открытые теги в длинные и короткие формы, но также легко исправляет начальные и конечные пробелы, проблемы Unicode и UTF-x BOM:phptags --whitespace *.php
Разумно использовать весь каталог include или проекта.
Пробел после
?>
Если источник ошибки упоминается как закрытие
?>
тогда это - то, где некоторый пробел или необработанный текст были написаны. Маркер конца PHP не останавливает выполнение скрипта на этом этапе. Любые текстовые / пробельные символы после этого будут записаны как содержимое страницы.Обычно советуют, в частности, новичкам, что трейлинг
?>
Теги закрытия PHP должны быть опущены. Это избегает небольшой части этих случаев. (Довольно частоinclude()d
сценарии виновник.)Источник ошибки, указанный как "Неизвестный в строке 0"
Обычно это расширение PHP или настройка php.ini, если источник ошибок не конкретизирован.
- Это иногда
gzip
настройка кодирования потока илиob_gzhandler
, - Но это также может быть любой вдвойне загружен
extension=
модуль, генерирующий неявное сообщение запуска / предупреждения PHP.
- Это иногда
Предыдущие сообщения об ошибках
Если другой оператор или выражение PHP вызывает вывод предупреждающего сообщения или уведомления, это также считается преждевременным выводом.
В этом случае вам необходимо избежать ошибки, отложить выполнение оператора или подавить сообщение, например:
isset()
или же@()
- когда либо не затрудняет отладку позже.
Нет сообщения об ошибке
Если у вас есть error_reporting
или же display_errors
инвалид в php.ini
, тогда никакое предупреждение не появится. Но игнорирование ошибок не устранит проблему. Заголовки все еще не могут быть отправлены после преждевременного вывода.
Так когда header("Location: ...")
молчаливый сбой перенаправления очень желательно проверить на наличие предупреждений. Включите их с помощью двух простых команд поверх сценария вызова:
error_reporting(E_ALL);
ini_set("display_errors", 1);
Или же set_error_handler("var_dump");
если все остальное терпит неудачу.
Говоря о заголовках перенаправления, вы часто должны использовать такую идиому, как эта, для окончательных путей кода:
exit(header("Location: /finished.html"));
Предпочтительно даже служебная функция, которая печатает пользовательское сообщение в случае header()
неудачи.
Буферизация вывода в качестве обходного пути
Выходная буферизация PHP - это обходной путь для решения этой проблемы. Это часто работает надежно, но не должно заменять правильную структуризацию приложения и отделение вывода от логики управления. Его реальная цель - минимизировать частичные переводы на веб-сервер.
output_buffering=
установка тем не менее может помочь. Настройте его в php.ini или через .htaccess или даже .user.ini на современных установках FPM/FastCGI.
Включение этого позволит PHP буферизировать вывод вместо того, чтобы мгновенно передавать его веб-серверу. Таким образом, PHP может собирать заголовки HTTP.Он также может быть занят с вызовом
ob_start();
поверх сценария вызова. Что, однако, менее надежно по нескольким причинам:Даже если
<?php ob_start(); ?>
запускает первый скрипт, пробелы или спецификация могут быть перетасованы ранее, что делает его неэффективным.Он может скрывать пробелы для вывода HTML. Но как только логика приложения пытается отправить двоичный контент (например, сгенерированное изображение), буферизованный посторонний вывод становится проблемой. (, потребовавшие
ob_clean()
как дальнейшее решение.)Размер буфера ограничен, и его можно легко переполнить, если оставить значение по умолчанию. И это тоже не редкость, трудно отследить, когда это произойдет.
Поэтому оба подхода могут стать ненадежными - в частности, при переключении между настройками разработки и / или производственными серверами. Вот почему выходная буферизация широко считается просто костыль / строго обходной путь.
См. Также основной пример использования в руководстве, а также дополнительные плюсы и минусы:
- Что такое выходная буферизация?
- Зачем использовать буферизацию вывода в PHP?
- Использование буферизации вывода считается плохой практикой?
- Вариант использования для буферизации вывода как правильное решение для "заголовков уже отправлено"
Но это работает на другом сервере!?
Если вы раньше не получали предупреждение о заголовках, то изменилась настройка буферизации вывода php.ini. Вероятно, он не настроен на текущем / новом сервере.
Проверка с headers_sent()
Вы всегда можете использовать headers_sent()
проверить, все ли еще возможно... отправить заголовки. Что полезно для условной печати информации или применения другой резервной логики.
if (headers_sent()) {
die("Redirect failed. Please click on this link: <a href=...>");
}
else{
exit(header("Location: /user.php"));
}
Полезные обходные пути:
HTML
<meta>
тегЕсли ваше приложение структурно сложно исправить, то простой (но несколько непрофессиональный) способ разрешить перенаправления - это внедрение HTML
<meta>
тег. Перенаправление может быть достигнуто с помощью:<meta http-equiv="Location" content="http://example.com/">
Или с небольшой задержкой:
<meta http-equiv="Refresh" content="2; url=../target.html">
Это приводит к недействительному HTML при использовании после
<head>
раздел. Большинство браузеров все еще принимают это.JavaScript перенаправить
В качестве альтернативы перенаправления JavaScript могут быть использованы для перенаправления страниц:
<script> location.replace("target.html"); </script>
Хотя это часто более совместимо с HTML, чем
<meta>
Обходной путь - использование клиентов с поддержкой JavaScript.
Оба подхода, однако, делают приемлемые откаты, когда подлинные вызовы HTTP header() не выполняются. В идеале вы всегда должны сочетать это с удобным сообщением и кликабельной ссылкой в качестве крайней меры. (Что, например, то, что делает расширение PECL http://php.net/http_redirect.)
Зачем setcookie()
а также session_start()
также затронуты
И то и другое setcookie()
а также session_start()
нужно отправить Set-Cookie:
HTTP заголовок. Поэтому применяются те же условия, и аналогичные сообщения об ошибках будут генерироваться для преждевременных выходных ситуаций.
(Разумеется, на них, кроме того, влияют отключенные файлы cookie в браузере или даже проблемы с прокси-сервером. Очевидно, что функциональность сеанса также зависит от свободного места на диске и других настроек php.ini и т. Д.)
Дальнейшие ссылки
- Google предоставляет длинный список подобных обсуждений.
- И, конечно же, многие конкретные случаи были рассмотрены и в случае переполнения стека.
- Часто задаваемые вопросы по Wordpress объясняют, как я могу решить проблему с предупреждением уже отправленных заголовков? в общем виде.
- Adobe Community: разработка PHP: почему перенаправления не работают (заголовки уже отправлены)
- Часто задаваемые вопросы по Nucleus: что означает "заголовки страниц уже отправлены"?
- Одним из более подробных объяснений являются заголовки HTTP и функция заголовка PHP () - руководство от NicholasSolutions (ссылка на Интернет-архив). Он подробно описывает HTTP и дает несколько рекомендаций по переписыванию скриптов.
Это сообщение об ошибке срабатывает, когда что-либо отправляется перед отправкой заголовков HTTP (с setcookie
или же header
). Общие причины вывода чего-либо до заголовков HTTP:
Случайный пробел, часто в начале или конце файлов, например:
<?php // Note the space before "<?php" ?>
Чтобы избежать этого, просто пропустите закрытие ?>
- это не требуется в любом случае.
- Порядок следования байтов в начале файла php. Проверьте ваши php файлы с помощью шестнадцатеричного редактора, чтобы выяснить, так ли это. Они должны начинаться с байтов
3F 3C
, Вы можете безопасно удалить спецификациюEF BB BF
с самого начала файлов. - Явный вывод, такой как вызовы
echo
,printf
,readfile
,passthru
код перед<?
и т.п. - Предупреждение выводится php, если
display_errors
свойство php.ini установлено. Вместо сбоя при ошибке программиста php молча исправляет ошибку и выдает предупреждение. Хотя вы можете изменитьdisplay_errors
или http://php.net/error-reporting конфигурации, вы должны скорее решить проблему.
Распространенными причинами являются обращения к неопределенным элементам массива (таким как$_POST['input']
без использованияempty
или жеisset
проверить, установлен ли вход), или использовать неопределенную константу вместо строкового литерала (как в$_POST[input]
Обратите внимание на пропущенные цитаты).
Включение буферизации вывода должно устранить проблему; весь вывод после звонка ob_start
буферизируется в памяти, пока вы не освободите буфер, например, с помощью ob_end_flush
,
Однако, хотя буферизация вывода позволяет избежать проблем, вы должны действительно определить, почему ваше приложение выводит тело HTTP перед заголовком HTTP. Это все равно, что позвонить по телефону и обсудить свой день и погоду, прежде чем сказать звонящему, что он набрал неправильный номер.
Я получал эту ошибку много раз прежде. И я уверен, что все программисты PHP хотя бы однажды получили эту ошибку. Чтобы решить эту ошибку, вы можете решить использовать решение в соответствии с уровнем вашей проблемы:
Возможное решение 1:
Возможно, вы оставили пробелы до или после (в конце файла после?>), Т.е.
THERE SHOULD BE NO BLANK SPACES HERE
<?php
echo "your code here";
?>
DO CHECK FOR BLANK SPACES HERE AS WELL; THIS LINE (blank line) SHOULD NOT EXIST.
В большинстве случаев это должно решить вашу проблему. Проверьте все файлы, связанные с файлом, который вы require
,
Примечание. Иногда EDITOR(IDE), такой как gedit(редактор linux по умолчанию), добавляет одну пустую строку в файл сохранения и сохранения. Этого не должно быть. Если вы используете Linux. Вы можете использовать редактор VI, чтобы удалить пробел / строки после?> в конце страницы.
Если это не ваш случай, тогда вы можете использовать ob_start для буферизации вывода, как показано ниже:
Возможное решение 2:
<?php
ob_start();
// code
ob_end_flush();
?>
Это включит буферизацию вывода, и ваши заголовки будут созданы после буферизации страницы.
Вместо строки ниже
//header("Location:".ADMIN_URL."/index.php");
записывать
echo("<script>location.href = '".ADMIN_URL."/index.php?msg=$msg';</script>");
или же
?><script><?php echo("location.href = '".ADMIN_URL."/index.php?msg=$msg';");?></script><?php
Это определенно решит вашу проблему. Я столкнулся с той же проблемой, но решил ее путем написания местоположения заголовка вышеуказанным способом.
Ты сделаешь
printf ("Hi %s,</br />", $name);
перед установкой файлов cookie, что запрещено. Вы не можете отправлять выходные данные перед заголовками, даже пустую строку.
ОБЩИЕ ПРОБЛЕМЫ:
(скопировано из источника)
====================
1) не должно быть никакого вывода (т.е. echo..
или HTML коды) перед header(.......);
команда.
2) удалить все пробелы (или перевод строки) перед <?php
и после ?>
теги.
3) ЗОЛОТОЕ ПРАВИЛО! - проверьте, что этот файл php (а также, если вы include
другие файлы) имеют UTF8 без кодировки BOM (и не только UTF-8). Во многих случаях это является проблемой (поскольку в начале файла php в кодированном UTF8 файле есть какой-то специальный символ, который не отображается в вашем текстовом редакторе)!!!!!!!!!!!
4) После header(...);
ты должен использовать exit;
5) всегда используйте 301 или 302 ссылку:
header("location: http://example.com", true, 301 ); exit;
6) Включите отчет об ошибках и найдите ошибку. Ваша ошибка может быть вызвана функцией, которая не работает. Когда вы включаете отчеты об ошибках, вы всегда должны сначала исправить самую верхнюю ошибку. Например, это может быть "Предупреждение: date_default_timezone_get(): небезопасно полагаться на настройки часового пояса системы". - затем дальше вы можете увидеть ошибку "заголовки не отправлены". После исправления самой первой (1-й) ошибки перезагрузите страницу. Если у вас все еще есть ошибки, то снова исправьте самую верхнюю ошибку.
7) Если ничего из вышеперечисленного не помогает, используйте перенаправление JAVSCRIPT (однако, это абсолютно не рекомендуется), может быть последним шансом в пользовательских случаях...:
echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;
Именно из-за этой строки:
printf ("Hi %s,</br />", $name);
Вы не должны ничего печатать / выводить перед отправкой заголовков.
Простой совет: простой пробел (или невидимый специальный символ) в вашем скрипте, прямо перед самым первым <?php
тег, может вызвать это! Особенно, когда вы работаете в команде, и кто-то использует "слабую" IDE или работает в файлах со странными текстовыми редакторами.
Я видел эти вещи;)
Другая плохая практика может вызвать эту проблему, которая еще не установлена.
Посмотрите этот фрагмент кода:
<?php
include('a_important_file.php'); //really really really bad practise
header("Location:A location");
?>
Все хорошо, верно?
Что если "a_important_file.php" это:
<?php
//some php code
//another line of php code
//no line above is generating any output
?>
----------This is the end of the an_important_file-------------------
Это не будет работать? Почему? Потому что уже создана новая строка.
Теперь, хотя это не распространенный сценарий, что, если вы используете инфраструктуру MVC, которая загружает много файлов перед передачей вещей на ваш контроллер? Это не редкий сценарий. Будьте готовы к этому.
Из ПСР-2 2.2:
- Все файлы PHP ДОЛЖНЫ использовать
Unix LF (linefeed) line ending
, - Все файлы PHP ДОЛЖНЫ заканчиваться
single blank line
, - Закрывающий тег?> ДОЛЖЕН быть
omitted
из файлов, содержащихonly php
Поверьте, следование этим стандартам может сэкономить вам массу времени из вашей жизни:)
Иногда, когда процесс dev имеет рабочие станции WIN и системы LINUX (хостинг), и в коде вы не видите вывод перед соответствующей строкой, это может быть форматирование файла и отсутствие окончания строки Unix LF (перевод строки),
Чтобы быстро это исправить, мы обычно делаем переименование файла и в системе LINUX создаем новый файл вместо переименованного, а затем копируем содержимое в него. Много раз это решает проблему, поскольку некоторые файлы, созданные в WIN, после перемещения на хостинг вызывают эту проблему.
Это исправление является простым исправлением для сайтов, которыми мы управляем по FTP, и иногда может спасти наших новых членов команды некоторое время.
Обычно эта ошибка возникает, когда мы отправляем заголовок после отображения или печати. Если эта ошибка возникает на определенной странице, убедитесь, что страница ничего не отображает, прежде чем вызывать start_session()
,
Пример непредсказуемой ошибки:
<?php //a white-space before <?php also send for output and arise error
session_start();
session_regenerate_id();
//your page content
Еще один пример:
<?php
includes 'functions.php';
?> <!-- This new line will also arise error -->
<?php
session_start();
session_regenerate_id();
//your page content
Вывод: не выводите никаких символов перед вызовом session_start()
или же header()
функции даже не пробел или новая строка