Вирішення проблеми "Cannot add header information - headers already sent". Як знайти і подолати BOM - неприємна помилка в WordPress Виправлення помилки cannot modify header information

У цій статті ми розглянемо основні причини та рішення виникнення помилки "Неможливо змінити заголовки - оскільки вони вже були відправлені" ("Cannot modify header information - headers already sent by").

Що означає ця помилка?

Щоб розібратися з причинами виникнення помилки, потрібно спочатку розібратися з тим, що таке ці заголовки.

Не заглиблюватимемося в теорію. Скажімо лише, що перед тим як будь-який користувач відкриває веб-сторінку, йому надсилаються ці самі "заголовки", які містять кодування, мову сайту, дані про сервер та іншу службову інформацію. Варто також окремо додати, що куки і сесія так само вирушають у заголовках.

Які команди викликають помилку?

Помилка "Cannot modify header information - headers already sent by"можуть викликати такі PHP-команди, як header, setcookie та інші, пов'язані з роботою cookie або сесій.

Причини та вирішення виникнення помилки.

Сама часта помилкавідбувається через не досвідченість. Ми вже розібралися, що заголовки надсилаються до того, як починає завантажуватися сама сторінка.

Але програмісти, особливо початківці просто забувають або навіть не знають цього. І спочатку намагаються щось вивести на сторінці – найчастіше за допомогою команди echo, а потім встановлюють кукі, посилають заголовки тощо. Що призводить саме до цієї помилки.

Ось приклад коду, який призведе до такої помилки:

А ось правильний варіант:

Тобто, по-перше, не можна нічого виводити до надсилання заголовків!

Не завжди це очевидно, але є помилка з невеликою відмінністю. Це коли php-документ у вас починається з прогалин чи порожніх рядків, що передбачає виведення у браузері цих рядків.

За цим буває дуже складно стежити, тому що, наприклад, Windows блокнот може додати спочатку Byte Order Mark, ніяк нас не попередивши і навіть не показуючи цей символ. У цьому випадку слід відкрити документ за допомогою інших редакторів та перевірити.

Ось приклад із неправильного завдання заголовків:

Тобто, по-друге, перед

Особливо уважним варто бути, якщо ви використовуєте команду include, по суті вона об'єднує всі файли і робить один результуючий, і якщо ви спочатку підключили шапку сайту (слайдер, меню і т.д.), а потім в основному файлі намагаєтеся відправити заголовки, то у вас, звичайно, вилізе ця помилка.

Ось приклад такого неправильного коду:

У цій статті ми розглянемо, навіщо заголовки потрібні, не вдаючись у подробиці, який відповідає. Опис ролей найпоширеніших заголовків буде дано у наступних статтях.

Усі статті з циклу:

  • Що таке Http заголовки | Загальна теорія.

HTTPрозшифровується як HyperText Transfer Protocol (протокол передачі гіпертексту). Протокол - це набір правил, за якими різні пристроїобмінюються даними. Він був створений у 1990-х роках. Зараз він використовується в Інтернеті практично повсюдно. Все, що ви бачите у вікні браузера, було одержано за допомогою цього протоколу. http заголовки - мабуть головна річ у спілкуванні між пристроями. Вони передають основну інформацію про з'єднання, що встановлюється, і про передану інформацію через це з'єднання.
Погляньмо на схему спілкування двох пристроїв. Нехай цими пристроями будуть ваш комп'ютер і якийсь сервер в інтернеті:

Як видно, браузер надіслав http-запит. Він може виглядати приблизно так:

GET /other-19 HTTP/1.1
Host: www.scriptsite.ru
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

При цьому перший рядок є рядком запиту, всі інші рядки - це і є http-заголовки, що несуть у собі додаткову інформаціюпро запит, про клієнта, який запитує цю інформацію, про багато інших речей.
У відповідь на наш запит сервер може надіслати такі заголовки:

Server: Apache/2.0.61 (Unix) mod_ssl/2.0.61 OpenSSL/0.9.8k mod_dp20/0.99.2 PHP/5.2.5 mod_python/3.3.1 Python/2.5.1 mod_ruby/1.2.6 Ruby/ (2007-09-24)

X-Powered-By: PHP/5.2.5

Set-Cookie: PHPSESSID=ft47gokfee6amv3eda3k1p93s3; path=/

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Pragma: no-cache

Keep-Alive: timeout = 10, max = 1024

Connection: Keep-Alive

Transfer-Encoding: chunked

Content-Type: text/html

Перший рядок – рядок статусу. Інші рядки - заголовки. У схемі було показано, що підвантажується також вміст сторінки. Але цей вміст зазвичай не прийнято відображати в плагінах, що переглядають заголовки. Та й вміст сторінки – це лише окремий випадок. За протоколом не обов'язково сторінка повинна передаватися. Замість неї можуть бути передані і картинка, і звуковий файл, та відео. І у всіх них заголовки сильно відрізнятимуться.

Як побачити http-заголовки?

Щоб побачити http-заголовки, я рекомендую наступні плагіни для браузера firefox:

Якщо ви користуєтеся браузером Chrome, переглянути всю інформацію можна, натиснувши кнопку налаштування — інструменти — інструменти розробника. Вкладка мереж.
Користувачам браузера operaнічого порадити не можу, бо не дружу із цим браузером. Встановивши плагіни та запустивши їх, спробуйте оновити сторінку. Ви відразу побачите величезні списки запитів та відповідей, за допомогою яких ваш браузер спілкувався із сервером.

Http-заголовки та доступ до них у php

Якщо ви є розробником php, ви можете отримати доступ до заголовків запиту за допомогою функції getallheaders() . Для розуміння її роботи виконаємо такий код:

І ми отримуємо роздруківку масиву заголовків.

Але найчастіше до них звертаються через глобальну змінну $_SERVER. Майже для кожного http заголовка є аналогічна назва елемента цієї змінної, утвореного за принципом HTTP_ім'я_заголовка. Так для того ж User_Agent є змінна $_SERVER[HTTP_USER_AGENT];

Для отримання заголовків, які сервер збирається надіслати користувачеві, використовується функція headers_list(). Як правило, сервер складає відсутні обов'язкові заголовки вже наприкінці роботи всіх скриптів. Тому цей масив міститиме заголовки або ті, які сервер створив перед початком виконання скрипта (і вони не будуть змінені), або ті, що ми встановили вручну. Вручну їх можна встановити за допомогою функції header (текст заголовка);
Виконаємо такий код:

Побачимо роздруківку готових до відправки на момент виклику функції заголовків:

Перший заголовок був встановлений автоматично, і він несе назву сервера, на якому виконується скрипт. Другий – встановлений нами вручну. Якби браузеру потрібен був заголовок «Фрукт», він узяв би його з http-відповіді сервра і використав. Але оскільки наш браузер не потребує його, то він просто ігнорує незрозумілий йому рядок.

Структура http запиту

Наш запит має такий вигляд:

Перший рядок у ньому, як було зазначено раніше, є рядком запиту. Вона складається з трьох частин:

  • метод(Метод) - вказує, якого роду запит. Найпоширеніші методи: GET, POST, HEAD. Про них буде написано у наступному параграфі.
  • path(шлях) — як правило, це частина URL після домену. Наприклад, якщо ви вводите в адресний рядок http://www.scriptsite.ru/about/, значення path буде /about/.
  • protocol(протокол) - протокол, що використовується. Як правило, складається з «HTTP» та версії протоколу. Зазвичай, у сучасних браузерахвикористовується версія 1.1

Далі йдуть заголовки у вигляді рядків формату "Ім'я: значення".
До речі, дані про cookies також передаються у цьому запиті у вигляді одного із заголовків. Більшість із цих рядків не є обов'язковими. Запит може бути скорочений взагалі до двох рядків:

GET /article/show/4/ HTTP/1.1

Host: scriptsite.ru

Методи запиту

GET

get-запит зазвичай використовується для запиту документа з передачею деяких параметрів.
Це основний метод, який використовується для отримання html-сторінок, зображень, CSS та JavaScript файлів, і т.д.
Через те, що параметри можуть бути будь-якими, а на сервері немає обмежень за способами їх обробки часто метод для запитів даних використовують для передачі інформації. Наприклад, у нас буде така форма

При цьому ці параметри буде видно в адресному рядку браузера.

POST

Post — метод, який використовується для надсилання даних на сервер. Незважаючи на те, що ви можете надсилати дані серверу методом GET через адресний рядок браузера, у більшості випадків краще використовувати POST. Надсилати великі обсяги даних через GET непрактично. До того ж GET має деякі обмеження, що не дозволяють, наприклад, опублікувати цю статтю на моєму сайті через один лише рядок браузера. POST запити найчастіше використовуються передачі web-форм. Давайте змінимо форму з попереднього прикладу, задавши їй метод POST

З цією помилкою до мене постійно звертаються і запитують: Де помилка?". Подібних листів за весь час я отримав десь штук 500 , Не менше. Час із помилкою "" вже закінчувати. У цій статті я розповім про причини виникнення цієї помилки, а також про те, як її вирішити.

Якщо перекласти цю помилкуросійською мовою, то вийде приблизно таке: " Не можна змінити заголовок, оскільки вони вже надіслані". Що це за " заголовки"? Давайте розберемося.

Коли сервер повертає відповідь клієнту, крім тіла (наприклад, HTML-кодсторінки), йдуть ще й заголовки. Вони містять код відповіді сервера, cookie, кодування та безліч інших службових параметрів. Чи може PHP-скриптнадіслати заголовок? Звісно, ​​може. Для цього існує функція header().

Ця функція, наприклад, постійно використовується при . Також дана функціярегулярно використовується при .

Також заголовки модифікуються під час відправлення cookieі на початку сесії (функція session_start()).

А тепер про те, чому все-таки виникає помилка? Сервер завжди спочатку віддає сервер заголовки, а потім тіло. Якщо сервер вже повернув заголовки, потім пішло тіло, і тут він зустрічає якийсь. session_start(). Виявляється горе-програміст забув відправити заголовки до початку тіла, і тепер хоче наздогнати поїзд, що вже пішов.

Ось код із помилкою "":



?>

Зрозуміло, таке марення PHPне прощає. І треба було писати так:

session_start(); // А давайте почнемо сесію
?>

Ось цей скрипт вже не викликає жодних помилок, тому що спочатку надсилаються всі заголовки, а вже потім йде генерація тіла відповіді сервера.

Інший приклад коду з помилкою:

echo "Hello!"; // Щось виведемо
session_start(); // А давайте почнемо сесію
?>

Те саме, чомусь спочатку виводиться тіло (або його шматок), а потім згадали, що ще й треба заголовки модифікувати.

Як правильно переписати даний код, подумайте самі.

Ще приклад:




exit;
?>

Коли автор такого коду, нічого не виходить, він дивується від цієї помилки і каже: "Дуже дивний збіг, коли операція проходить успішно, все добре, а коли якась помилка, мені повідомляють Cannot modify header information - headers already sent". Не дослівно, але сенс у цьому.

Проблема та сама, і правильно писати так:

$ error = true; // Чи були помилки?
if ($error) echo "Відбулася помилка";
else header("Location: ".$_SERVER["HTTP_REFERER"]); // Робимо редирект назад
exit;
?>

Є й непомітні помилки:

header("Location: ".$_SERVER["HTTP_REFERER"]); // Робимо редирект назад
exit;
?>

Помилка в даному коді виникає через пробіл, який присутній перед . Пробіл – це звичайний символ, і він є частиною тіла відповіді. І коли сервер його бачить, він робить висновок про те, що заголовків більше не буде і настав час виводити тіло.

Бувають і такі помилки, що мають ту саму природу. Допустимо є файл a.html:

require_once "a.html";
header("Location: ".$_SERVER["HTTP_REFERER"]); // Робимо редирект назад
exit;
?>

І людина щиро дивується, звідки помилка, якщо вона нічого не виводила? Тому дивитися треба не конкретно 1 файл, а всі файли, що підключаються до нього. І в тих, що підключаються у тих, що підключаються, теж треба дивитися, щоб не було висновку.

І останній момент, але вже складніший. Виявляється, що іноді ця помилка відбувається і за правильного коду. Тоді все справа у кодуванні. Переконайтеся, що кодування файлу " UTF-8 без BOM", причому саме " без BOM", а не просто" UTF-8". Оскільки BOM- це байти, що йдуть на початку файлу, і вони є висновком.

Дуже сподіваюся, що дана стаття допоможе вирішити абсолютно всі проблеми, пов'язані з помилкою "", оскільки я постарався висвітлити всі проблеми, що виникають. А далі треба включити голову і подумати, а що у Вашому коді не так?

Це повідомлення про помилку часто зустрічають програмісти, які використовують PHP. Розуміння того, чому виникає ця помилка допоможе знайти рішення.

PHP робить багато роботи з генерації веб-сторінок за вас, навіть без вашого прохання. Веб-сторінка складається з двох частин: заголовка та тіла.

Ця поширена помилка PHP спостерігається, коли програміст робить помилки в маніпуляції або створення заголовків. Ось приклад:

Warning: Cannot modify header information – headers already sent by (output started at /home/usr1/public_html/sent.php:42) у

Як правило, вам не потрібно турбуватися про заголовок, так як він генерується автоматично і містить інформацію про сторінку, сервер, і coockie. Інформація в заголовку важлива, але вона зазвичай не помітна користувачеві. Ось кілька прикладів:

Date: Mon, 10 Jul 2006 18:51:59 GMT Server: Apache/2.2.0 (Unix) mod_ssl/2.2.0 OpenSSL/0.9.7g Content-Encoding: gzip Content-Type: text/html

Іноді програмісти хочуть змінити деякі значення заголовка. Наприклад, якщо PHP генерує висновок XML, Content-Type повинен бути змінений, щоб вказати це. Іншим поширеним прикладом є перенаправлення браузера користувача на іншу веб-сторінку за допомогою елемента заголовка Location, як описано в цій статті.

Заголовок повинен йти першим у відповіді з веб-сервера і відокремлюється від тіла одним порожнім рядком. Причиною цієї помилки є те, що деяку частину тіла веб-сторінки було відправлено користувачеві вже до того, коли робиться спроба встановити значення заголовка. Оскільки PHP спрощує багато речей для вас, проблема може ховатися у звичайному місці. Ось деякі вказівки для знаходження проблеми:

  1. Знайдіть інструкцію header(), яка є причиною проблеми. Помилка має бути на або до цієї лінії.
  2. Подивіться будь-які інструкції, які могли б направити висновок користувачеві до цієї інструкції заголовка. Якщо ви виявили один або кілька, змініть код, щоб перемістити інструкцію заголовка перед ними. Складні умовні операториможуть ускладнити проблему, але вони також можуть допомогти вирішити проблему. Як варіант можете застосувати умовний вираз у верхній частині сценарію PHPщо визначає значення заголовка якомога раніше, і встановлює його там.
  3. Переконайтеся, що немає пробілів за межами початкового та кінцевого PHP тегів. Хоча порожній рядок перед початковим тегом
  4. Якщо ви зберігаєте файл у кодуванні UTF-8, переконайтеся, що файл зберігається без сигнатури (without BOM). Сигнатура - це байт, що додається на початку файлу, і якщо PHP скрипт зберегти в такому форматі, то цей байт буде сприйнятий як частина виведення тіла сторінки, чого не можна допускати, щоб уникнути цієї проблеми.

Помилку цю виправити нескладно.
Часто таке ж повідомлення з'являється при старті сесій, у трохи іншому формулюванні:
Warning: Cannot send session cookie - headers already sent
Warning: Cannot send session cache limiter - headers already sent

Byte Order Mark
Іноді ви перевірили ВСЕ – ніде нічого немає. Змініть редактор. Перегляньте свій файл в іншій програмі. Наприклад, Windows Блокнот при використанні кодування Unicode додає на початок вашого файлу службовий знак Byte Order Mark, ніяк при цьому не повідомляючи вас. Відкрийте скрипт в іншому редакторі та видаліть сторонні символи. І змініть Блокнот на інший редактор.
Або зберігайте у кодуванні UTF-8 без BOM

Численні питання на форумі змушують мене зробити тут важливе зауваження:
Ця помилка з'являється не від того, що у вас у скрипті "щось написано вище". А від того, що РНР виводить щось у браузер. Це не обов'язково код. Це може бути повідомлення про помилку. може бути пробіл або хтмл тег. Так-так. Для найталановитіших: мова йде про будь-який символ, відправлений у браузер, а не лише про ті, які браузер відображає недосвідченому користувачеві. HTML сторінки мають вихідний текст. І саме він є результатом роботи PHP скрипта, а не красиві літери з картинками, як думає дуже велика кількість людей.