Как исправить ошибку «Заголовки уже отправлены» в PHP

831

При запуске моего скрипта я получаю несколько ошибок, подобных этой:

Предупреждение: невозможно изменить информацию заголовка - заголовки уже отправлены ( вывод начался с /some/file.php:12 ) в /some/file.php в строке 23

Строки, упомянутые в сообщениях об ошибках, содержат header()и setcookie()вызовы.

Что может быть причиной этого? И как это исправить?

Moses89
источник
читайте: stackoverflow.com/questions/1912029/…
Книга Зевса
Убедитесь, что текст не выводится ( ob_startи ob_end_clean() может оказаться полезным здесь). Затем вы можете установить cookie или сеанс равными, ob_get_contents()а затем использовать ob_end_clean()для очистки буфера.
Джек Так
Используйте safeRedirectфункцию в моей библиотеке PHP: github.com/heinkasner/PHP-Library/blob/master/extra.php
heinkasner
5
~~~~~~~~~~ Ваш файл ENCODING не должен быть UTF-8, а UTF-8 (Without BOM)~~~~~~~~~~~
T.Todua

Ответы:

2998

Нет вывода перед отправкой заголовков!

Функции, которые отправляют / изменяют заголовки HTTP, должны быть вызваны перед выполнением любого вывода . summary ⇊ В противном случае вызов не выполняется:

Предупреждение: невозможно изменить информацию заголовка - заголовки уже отправлены (вывод начат в script: line )

Некоторые функции, изменяющие заголовок HTTP:

Выход может быть:

  • Непреднамеренное:

    • Пробелы до <?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 . Вот где вам пришлось искать преждевременный выход.

Типичные причины:

  1. Печать, эхо

    Преднамеренное выход из printи echoзаявления прервет возможность отправлять HTTP заголовки. Поток приложений должен быть реструктурирован, чтобы избежать этого. Используйте функции и шаблонные схемы. Убедитесь, что header()звонки происходят до сообщения будут записаны.

    Функции, которые производят вывод, включают

    • print, echo, printf,vprintf
    • trigger_error, ob_flush, ob_end_flush, var_dump,print_r
    • readfile, passthru, flush, imagepng,imagejpeg


    среди других и пользовательских функций.

  2. Необработанные области HTML

    Непарсированные разделы HTML в .phpфайле также являются прямым выводом. Условия сценария, которые инициируют header()вызов, должны быть записаны перед любыми необработанными <html>блоками.

    <!DOCTYPE html>
    <?php
        // Too late for headers already.

    Используйте шаблонную схему для отделения обработки от логики вывода.

    • Поместите код обработки форм поверх скриптов.
    • Используйте временные строковые переменные для отсрочки сообщений.
    • Фактическая логика вывода и смешанный вывод HTML должны следовать последним.

  3. Пробел перед <?phpдля "script.php строки 1 предупреждением "

    Если предупреждение относится к выводу в строке 1, то перед открывающим токеном в основном идут пробелы , текст или HTML <?php.

     <?php
    # There's a SINGLE space/newline before <? - Which already seals it.

    Аналогичным образом это может происходить для добавленных сценариев или разделов сценариев:

    ?>
    
    <?php

    PHP фактически съедает один перевод строки после закрывающих тегов. Но это не компенсирует множественные новые строки или табуляции или пробелы, сдвинутые в такие пробелы.

  4. UTF-8 BOM

    Только разрывы строк и пробелы могут быть проблемой. Но есть также «невидимые» последовательности символов, которые могут вызвать это. Наиболее известным является UTF-8 BOM (Byte-Order-Mark), который не отображается большинством текстовых редакторов. Это последовательность байтов EF BB BF, которая является необязательной и избыточной для документов в кодировке UTF-8. PHP, однако, должен воспринимать это как необработанный вывод. Может отображаться как персонажи в выходных данных (если клиент интерпретирует документ как Latin-1) или как подобный «мусор».

    В частности, графические редакторы и IDE на основе Java не замечают его присутствия. Они не визуализируют это (обязано стандартом Unicode). Большинство программистов и консольных редакторов, однако, делают:

    редактор joes, показывающий местозаполнитель спецификации UTF-8, а редактор MC - точку

    Там легко распознать проблему на ранней стадии. Другие редакторы могут идентифицировать его присутствие в файле / меню настроек (Notepad ++ в Windows может идентифицировать и устранить проблему ). Другой вариант проверки наличия спецификаций - использование шестигранника . В системах * nix hexdumpобычно доступен, если не графический вариант, который упрощает аудит этих и других проблем:

    Beav Hexeditor показывает UTF-8 бомба

    Простое решение - настроить текстовый редактор для сохранения файлов как «UTF-8 (без спецификации)» или подобной номенклатуры. Часто новички в противном случае прибегают к созданию новых файлов и просто копируют и вставляют предыдущий код обратно.

    Коррекция коммунальных услуг

    Есть также автоматизированные инструменты для проверки и перезаписи текстовых файлов ( sed/awk или recode). Для PHP, в частности, есть phptagsтег Tidier . Он переписывает закрытые и открытые теги в длинные и короткие формы, а также легко исправляет начальные и конечные пробелы, проблемы Unicode и UTF-x BOM:

    phptags  --whitespace  *.php

    Разумно использовать весь каталог include или проекта.

  5. Пробел после ?>

    Если источник ошибки упоминается как закрытие?> то это то место, где записывается какой-то пробел или необработанный текст. Маркер конца PHP не останавливает выполнение скрипта на этом этапе. Любые текстовые / пробельные символы после этого будут записаны как содержимое страницы.

    Обычно советуют, в частности, новичкам, что конечные ?>теги закрытия PHP должны быть опущены. Это избегает небольшой части этих случаев. (Довольно часто include()dсценарии являются виновниками.)

  6. Источник ошибки, указанный как «Неизвестный в строке 0»

    Обычно это расширение PHP или параметр php.ini, если источник ошибок не конкретизирован.

    • Иногда это gzipнастройка кодирования потока илиob_gzhandler .
    • Но это также может быть любой дважды загруженный extension=модуль, генерирующий неявное сообщение запуска / предупреждения PHP.

  7. Предыдущие сообщения об ошибках

    Если другой оператор или выражение 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 - это обходной путь для решения этой проблемы. Это часто работает надежно, но не должно заменять правильное структурирование приложения и отделение вывода от логики управления. Его реальная цель - минимизировать частичные переводы на веб-сервер.

  1. output_buffering= Параметр , тем не менее может помочь. Настройте его в php.ini или через .htaccess или даже .user.ini для современных установок FPM / FastCGI.
    Включение этого позволит PHP буферизировать вывод вместо того, чтобы мгновенно передавать его веб-серверу. Таким образом, PHP может собирать заголовки HTTP.

  2. Он также может быть задействован с вызовом ob_start(); поверх сценария вызова. Что, однако, менее надежно по нескольким причинам:

    • Даже если <?php ob_start(); ?>первый скрипт запускается, пробелы или спецификация могут быть перетасованы ранее, что делает его неэффективным .

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

    • Размер буфера ограничен, и его можно легко переполнить, если оставить значение по умолчанию. И это тоже не редкость, трудно отследить, когда это произойдет.

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

См. Также базовый пример использования в руководстве, а также дополнительные плюсы и минусы:

Но это работает на другом сервере !?

Если вы раньше не получали предупреждение о заголовках, тогда настройка выходной буферизации 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 (). В идеале вы всегда должны сочетать это с удобным сообщением и кликабельной ссылкой в ​​качестве крайней меры. (Что, например, то, что http_redirect () расширение PECL .)

Почему setcookie()и session_start()на что тоже влияют

И то setcookie()и другое session_start()нужно отправить Set-Cookie:HTTP-заголовок. Поэтому применяются те же условия, и аналогичные сообщения об ошибках будут генерироваться для преждевременных выходных ситуаций.

(Конечно, на них, кроме того, влияют отключенные файлы cookie в браузере или даже проблемы с прокси. Функциональность сеанса, очевидно, также зависит от свободного места на диске и других настроек php.ini и т. Д.)

Дальнейшие ссылки

марио
источник
Также обычный notepad.exe сложно. Я обычно использую NetBeans, который не добавляет спецификацию, даже если файл закодирован так. Редактирование файла позже в блокноте приводит к путанице, особенно к IIS как веб-серверу. Кажется, что apache отбрасывает (добавленную единицу) спецификацию.
Teson
4
Удаление закрытия ?>с конца php-файлов обычно является хорошей практикой, которая также помогает минимизировать эти ошибки. Нежелательные пробелы не будут появляться в конце файлов, и вы все равно сможете добавить заголовки к ответу позже. Это также удобно, если вы используете буферизацию вывода и не хотите видеть добавленные нежелательные пробелы в конце частей, сгенерированных включенными файлами.
Никита 웃
Странно, я переместил свой файл с хостинга cPanel Linux на VPS. До того, как он работал правильно, но здесь он показал эту ошибку. (У меня был HTML-код перед заголовком). Почему?
Пабло Эскобар
@Purushotamrawat Вы читали часть о « Но это сработало на другом сервере !? »
Марио
1
@PeterSMcIntyre Спецификация UTF8 предположительно (исправьте это) / буферизация вывода не включена (не полагайтесь на это).
Марио
199

Это сообщение об ошибке выдается, когда что-либо отправляется перед отправкой заголовков 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или error_reporting , вам лучше решить проблему.
    Распространенными причинами являются обращения к неопределенным элементам массива (например, $_POST['input']без использования emptyили issetдля проверки того, установлен ли ввод) или использование неопределенной константы вместо строкового литерала (как $_POST[input], например, обратите внимание на отсутствующие кавычки).

Включение буферизации вывода должно устранить проблему; весь вывод после вызова ob_startбуферизуется в памяти до тех пор, пока вы не освободите буфер, например, с помощью ob_end_flush.

Однако, хотя буферизация вывода позволяет избежать проблем, вы должны действительно определить, почему ваше приложение выводит тело HTTP перед заголовком HTTP. Это все равно, что позвонить по телефону и обсудить свой день и погоду, прежде чем сказать звонящему, что он набрал неправильный номер.

phihag
источник
это помогает мне спасибо
Вишва Пратап
122

Я получал эту ошибку много раз раньше, и я уверен, что все программисты PHP получили эту ошибку, по крайней мере, один раз.

Возможное решение 1

Эта ошибка могла быть вызвана пробелами до начала файла или после конца файла. Эти пробелы не должны быть здесь.

ex) ЗДЕСЬ НЕ ДОЛЖНО БЫТЬ ПУСТЫХ ПРОСТРАНСТВ

   echo "your code here";

?>
THERE SHOULD BE NO BLANK SPACES HERE

Проверьте все файлы, связанные с файлом, который вызывает эту ошибку.

Замечания: Иногда EDITOR (IDE), такой как gedit (редактор linux по умолчанию), добавляет одну пустую строку в файл сохранения. Этого не должно быть. Если вы используете Linux. Вы можете использовать редактор VI, чтобы удалить пробел / строки после?> в конце страницы.

Возможное решение 2: если это не ваш случай, используйте ob_start для вывода буферизации:

<?php
  ob_start();

  // code 

 ob_end_flush();
?> 

Это включит буферизацию вывода, и ваши заголовки будут созданы после буферизации страницы.

Маниш Шривастава
источник
18
ob_start()просто скрывает проблему; не используйте его для решения этой конкретной проблемы.
Яцк
@ Ja͢ck Если я не использую ob_start(), то что я должен сделать для решения этой проблемы:Headers already sent
Shafizadeh
@ Sajad, если вы получаете сообщение об ошибке именно из-за используемого вами редактора, вам следует поиграться с настройками, чтобы он перестал вызывать проблему, или переключить редакторы. Если вы получаете сообщение об ошибке по любой другой причине, вам следует прочитать ответы на этот вопрос (в частности, принятый ответ), чтобы выяснить, в чем заключается проблема, и решить ее.
Samsquanch
3
ob_start()не «скрывает» проблему, она решает проблему.
TMS
1
У меня была такая проблема, когда я загружал свои файлы на сервер, который поддерживал даже PHP5.3. Использовать сервер с PHP 5.6 или более
GGSoft
86

Вместо строки ниже

//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

Это определенно решит вашу проблему. Я столкнулся с той же проблемой, но решил ее путем написания местоположения заголовка вышеуказанным способом.

Ипсита Раут
источник
41

Вы делаете

printf ("Hi %s,</br />", $name);

перед установкой файлов cookie, что запрещено. Вы не можете отправлять выходные данные перед заголовками, даже пустую строку.

Сет Карнеги
источник
32

Именно из-за этой строки:

printf ("Hi %s,</br />", $name);

Вы не должны ничего печатать / выводить перед отправкой заголовков.

Sarfraz
источник
31

ОБЩИЕ ПРОБЛЕМЫ:

(скопировано из источника )

====================

1)echo.. перед header(.......);командой не должно быть никаких выводов (т. Е. HTML-кодов) .

2) удалить все пробелы (или перевод строки ) до <?phpи после ?>тегов.

3) ЗОЛОТОЕ ПРАВИЛО! - проверьте, имеет ли этот php-файл (а также, если вы includeдругие файлы) UTF8 без кодировки BOM (а не только UTF-8 ). Это проблема во многих случаях (потому что UTF8 в начале файла php в кодированном файле есть какой-то специальный символ, который не отображается в вашем текстовом редакторе) !!!!!!!!!!!

4) После header(...);того, как вы должны использоватьexit;

5) всегда используйте 301 или 302 ссылку:

header("location: http://example.com",  true,  301 );  exit;

6) Включите отчет об ошибках и найдите ошибку. Ваша ошибка может быть вызвана функцией, которая не работает. Когда вы включаете отчеты об ошибках, вы всегда должны сначала исправить самую верхнюю ошибку. Например, это может быть «Предупреждение: date_default_timezone_get (): небезопасно полагаться на настройки часового пояса системы». - затем дальше вы можете увидеть ошибку «заголовки не отправлены». После исправления самой первой (первой) ошибки перезагрузите страницу. Если у вас все еще есть ошибки, то снова исправьте самую верхнюю ошибку.

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

echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;
T.Todua
источник
Почему явно сеттинг 301или 302важно?
Янис Элмерис
26

Простой совет: простой пробел (или невидимый специальный символ) в вашем скрипте, прямо перед самым первым <?phpтегом, может вызвать это! Особенно, когда вы работаете в команде, и кто-то использует «слабую» IDE или работает в файлах со странными текстовыми редакторами.

Я видел эти вещи;)

SliQ
источник
22

Другая плохая практика может вызвать эту проблему, которая еще не установлена.

Посмотрите этот фрагмент кода:

<?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

Поверьте, следование этим стандартам может сэкономить вам массу времени из вашей жизни :)

MD. Сахиб бин Махбуб
источник
2
Согласно нескольким стандартам (например, Zend), вы ?>ни в коем случае не должны ставить закрывающий тег ни в каком файле
Даниэль В.
Я не могу воспроизвести это в среде Windows, поскольку она работает с использованием любой комбинации (добавление закрывающих тегов, пробелов, нажатие клавиши ввода и т. Д.). Похоже, что эта проблема возникает в основном в среде Linux.
Младший Mayhé
@JuniorM Это должно быть воспроизводимо. Можете ли вы поделиться кодом, который вы экспериментировали в сущности или что-то подобное?
доктор медицинских наук Сахиб бин Махбуб
Я на Windows 7, с последней установленной Wamp. Я думаю, что эта ошибка связана со скрытыми символами в конце строки. Мой Wordpress 'shortcodes.php был причиной проблемы. Я добавил в этот файл простую функцию, и она начала выдавать ошибку «отправленные заголовки». Я сравнил свой shortcodes.php с wordpress ', и все было в порядке, кроме CR LF(типичный конец строки для Windows). Я решил эту проблему, загрузив исходный файл из репозитория Wordpress, в котором LFвместо (конец Linux) есть строка, CR LFи я также перенес свою функцию в файл functions.php темы. Основано на: bit.ly/1Gh6mzN
Младший Mayhé
@ Сахиб, обратите внимание, что я все еще не могу воспроизвести то, что указано в этом ответе. Ответ полностью подходит для среды Linux. Я проверил такие вещи, как пробел ?> <?php, удаляя и добавляя одну пустую строку, добавляя и опуская закрывающий тег ?>. В Windows + Wamp все эти комбинации работают нормально. Странно ...
Младший Mayhé
15

Иногда, когда процесс dev имеет рабочие станции WIN и системы LINUX (хостинг), и в коде вы не видите вывод перед соответствующей строкой, это может быть форматирование файла и отсутствие конца строки Unix LF (перевод строки) ,

Чтобы быстро это исправить, мы обычно делаем переименование файла и в системе LINUX создаем новый файл вместо переименованного, а затем копируем содержимое в него. Много раз это решает проблему, так как некоторые из файлов, которые были созданы в WIN после перемещения на хостинг, вызывают эту проблему.

Это исправление является простым исправлением для сайтов, которыми мы управляем по FTP, и иногда может спасти наших новых членов команды некоторое время.

Lupin
источник
2

Обычно эта ошибка возникает, когда мы отправляем заголовок после отображения или печати. Если эта ошибка возникает на определенной странице, убедитесь, что страница ничего не отображает, прежде чем звонить 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()функций, даже не пробел или новую строку

Biswadeep Sarkar
источник