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

836

При запуске my script я получаю несколько таких ошибок:

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

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

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

  • 0
    прочитайте: stackoverflow.com/questions/1912029/…
  • 0
    Убедитесь, что текст не выводится ( ob_start и ob_end_clean() могут оказаться здесь полезными). Затем вы можете установить cookie или сеанс, равный ob_get_contents() а затем использовать ob_end_clean() для очистки буфера.
Показать ещё 2 комментария
Теги:
header

11 ответов

2703
Лучший ответ

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

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

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

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

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

  • Преднамеренное:

    • 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/usr 2345/htdocs/index.php в строке 100

Здесь "строка 100" относится к script, где не удалось выполнить вызов 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 также являются прямым выходом. Script должны быть отмечены условия, вызывающие вызов header() перед любыми необработанными блоками <html>.

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

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

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

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

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

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

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

    ?>
    
    <?php
    

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

  • Спецификация UTF-8

    Одной из проблем может быть только односторонняя линия и пространство. Но есть и "невидимые" последовательности символов, которые могут вызвать это. Самый классный Спецификация UTF-8 (байт-заказ-марка)который не отображается большинством текстовых редакторов. Это байтовая последовательность EF BB BF, которая является необязательным и избыточным для кодированных документов UTF-8. Однако PHP должен лечить это как сырой выход. Он может отображаться как символы  на выходе (если клиент интерпретирует документ как латинский-1) или аналогичный "мусор".

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

    Изображение 725

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

    Изображение 726

    Легкое исправление заключается в том, чтобы установить текстовый редактор для сохранения файлов как "UTF-8 (no BOM)" или подобная такая номенклатура. Зачастую новички прибегают к созданию новых файлы и просто скопировать и снова вставить предыдущий код.

    Утилиты исправления Изображение 727

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

    phptags  --whitespace  *.php
    

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

  • Пробелы после ?>

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

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

  • Источник ошибки, указанный как "Неизвестно в строке 0"

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

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

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

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

    В этом случае вам нужно избежать ошибки, задержать выполнение оператора или подавить сообщение, например. isset() или @() - когда либо не препятствует отладке позже.

Нет сообщения об ошибке

Если у вас error_reporting или display_errors отключено на php.ini, то предупреждение не появится. Но игнорирование ошибок не вызовет проблемы далеко. Заголовки по-прежнему не могут быть отправлены после преждевременного выхода.

Поэтому, когда header("Location: ...") перенаправляет молча, рекомендуется проконтролировать предупреждения. Обозначить их двумя простыми командами на вызов script:

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 on современные установки FPM/FastCGI.
    Включение этого режима позволит PHP выводить выходные данные вместо того, чтобы передавать его на веб-сервер мгновенно. Таким образом, PHP может собирать заголовки HTTP.

  • Он также может быть связан с вызовом ob_start(); на вершине вызова script. Это, однако, менее надежно по нескольким причинам:

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

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

Почему setcookie() и session_start() также затронуты

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

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

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

  • 0
    Также обычный notepad.exe сложно. Я обычно использую NetBeans, который не добавляет спецификацию, даже если файл закодирован так. Редактирование файла позже в блокноте приводит к путанице, особенно к IIS как веб-серверу. Кажется, что apache отбрасывает (добавленную единицу) спецификацию.
  • 4
    Удаление закрывающего ?> Из конца php-файлов обычно является хорошей практикой, которая также помогает минимизировать эти ошибки. Нежелательные пробелы не будут появляться в конце файлов, и вы все равно сможете добавить заголовки к ответу позже. Это также удобно, если вы используете буферизацию вывода и не хотите видеть добавленные нежелательные пробелы в конце частей, сгенерированных включенными файлами.
Показать ещё 12 комментариев
187

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

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

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

97

Я получил эту ошибку много раз раньше. И я уверен, что все программисты 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.

Большая часть времени это должно решить ваш problem.Do проверить все файлы, связанные с файлом вам require.

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

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

Возможное решение 2:

<?php
  ob_start();

  // code 

 ob_end_flush();
?> 

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

  • 17
    ob_start() просто скрывает проблему; не используйте его для решения этой конкретной проблемы.
  • 0
    @ Ja͢ck Если я не использую ob_start() , то что мне делать для решения этой проблемы: Headers already sent
Показать ещё 5 комментариев
78

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

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

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

  • 16
    это нормально, но если пользователь отключит Java-скрипт, он не будет работать.
38

Вы делаете

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

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

30

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

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

Прежде чем отправлять заголовки, вы не должны печатать/эхо.

26

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

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

22

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

(скопировано из: source)

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

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

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

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

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

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

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

6) Включите отчет об ошибках. И сообщите об ошибке.

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

echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;
20

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

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

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

Из PSR-2 2.2:


  • Все файлы PHP ДОЛЖНЫ использовать Unix LF (linefeed) line ending.
  • Все файлы PHP ДОЛЖНЫ заканчиваться на single blank line.
  • Тег закрытия? > ДОЛЖЕН быть omitted из файлов, содержащих only php

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

  • 2
    Согласно нескольким стандартам (например, Zend), вы ни в коем случае не должны ставить закрывающий тег ?> В любом файле.
  • 0
    Я не могу воспроизвести это в среде Windows, поскольку она работает с использованием любой комбинации (добавление закрывающих тегов, пробелов, нажатие клавиши ввода и т. Д.). Похоже, что эта проблема возникает в основном в среде Linux.
Показать ещё 4 комментария
14

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

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

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

1

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню