Как найти и побороть BOM — неприятная ошибка в WordPress. Что такое Http заголовки (Http headers)

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

Все статьи из цикла:

  • Что такое 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/1.8.6(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, просмотреть всю информацию можно, нажав на кнопку настройки — инструменты — инструменты разработчика. Вкладка networks.
Пользователям браузера opera ничего посоветовать не могу, так как не дружу с этим браузером. Установив плагины и запустив их, попробуйте обновить страницу. Вы сразу же увидите огромные списки запросов и ответов, посредством которых ваш браузер общался с сервером.

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

Если вы являетесь php-разработчиком, вы можете получить доступ к заголовкам запроса с помощью функции getallheaders() . Для понимания её работы выполним такой код:

И мы получаем распечатку массива заголовков.

Но чаще к ним обращаются через глобальную переменную $_SERVER. Почти для каждого http заголовка есть аналогичное название элемента в этой переменной, образуемого по принципу HTTP_имя_заголовка. Так для того же ‘User_Agent’ есть переменная $_SERVER[‘HTTP_USER_AGENT’];

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

Увидим распечатку готовых к отправке на момент вызова функции заголовков:

Первый заголовок был установлен автоматически, и он несёт в себе название сервера, на котором выполняется скрипт. Второй - установленный нами вручную. Если бы браузеру нужен был заголовок «Фрукт», он бы взял его из http-ответа сервра и использовал. Но так как наш браузер не нуждается в нём, то он просто игнорирует непонятную ему строку.

Структура http запроса

Наш запрос выглядит следующим образом:

Первая строка в нём, как уже было сказано раньше, является строкой запроса. Она состоит из трёх частей:

  • method (метод) — указывает, какого рода запрос. Самые распространённые методы: 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

Как-то раз, зайдя на свой блог я с удивлением обнаружил непонятную ошибку, что-то вроде:

Warning: Cannot modify header information — headers already sent by (output started at /xxxxxxxx/wp-config.php:1)

Причем в админку зайти никак нельзя. Сразу же пошел проверять что не так с файлом wp-config.php. Все было на месте, пароли к БД правильные. Подумал было — снова хакнули)) Но опять же никаких признаков вандализма на FTP замечено не было. Самое странное (это меня в конце-концов окончательно запутало), что не работала только ссылка на сайт без www или наоборот (точно не помню). Начал стучать хостеру, смотреть настройки в админке домена — в общем, много чего.

А оказалось все намного проще — в начале файла конфига был некий BOM — маркер (сигнатура) для UTF-8 файлов. Именно поэтому выскакивала приведенная выше ошибка. Чтобы такого не случилось с вами в первую очередь нужно использовать редакторы кода, которые либо не ставят эту сигнатуру вообще, либо перед сохранением файла уточняют нужна ли она.

В некоторых текстовых редакторах вы можете найти в настройках флажки «Include Unicode Signature (BOM)», «Add Byte Order Mark» или подобные им. В противном случае, не имея возможности отключить ненужную опцию в той или иной программе, использовать ее не рекомендуется. На специализированных форумах можно найти список хороших текстовых редакторов, это — Notepad2, PSPad, UnicEdit, Notepad++ . О последнем вообще много пишут, достаточно мощный инструмент. У меня каким-то случайным образом на компа был в наличии альтернативный редактор — Akelpad — его для подобных задач и применяю.

Следует заметить вот еще какой момент — ошибка с BOM может быть не только в файле wp-config.php. Более того, при отключенной опции вывод предупреждений, вы вообще не увидите где закралась неполадка. В таких случаях (ну и всех других) я бы рекомендовал использовать простой скрипт для поиска файлов с BOM . За разработку следует поблагодарить Юрия Белотицкого .

Использование скрипта очень простое.

  1. нужный файлик
  2. Заливаете его на FTP сервер в корневую директорию. Если WordPress установлен не в корне сайта (а в папке blog, например), то скрипт нужно разместить в директорию, где лежит WordPress, и из нее же и запускать.
  3. Запуск очень простой — набираете в адресной строке броузера ссылку http://ваш.сайт/find_bom.php

В результате получите список файлов, которые являются неисправными. Кстати, для быстроты работы скрипт проверяет только те директории, куда пользователи, как правило, заливают файлы — корень, /wp-content/themes и /wp-content/plugins.

Вот, в принципе, и все. Как сложно пришлось решать такую простую проблему. Надеюсь, вам помог немного своим опытом, и теперь при появлении соответствующего предупреждения, вы будете знать, что делать:) Если не получается исправить тот или иной файл от BOM, можно просто залить новый из дистрибутива WordPress.

P.S. Для молодоженов подходящий сайт — организация банкетов и решение всех вопросов, связанных со свадьбой.

Сегодня мы решили рассказать о том, что значит сообщение «Warning: Cannot modify header information — headers already sent by (output started at /home/...» , появившееся на странице сайта вместо его основного содержимого.
Как оказалось, в сети достаточно написано на эту тему, но нет обобщенной инструкции о том, что все это значит и как от этого избавиться.
Мы решили добавить несколько капель в огромное море информации на эту тему, поскольку столкнулись с данной проблемой лично.

Некоторое время назад мы осуществили перенос нескольких клиентских сайтов с одного хостинга на другой.
Все прошло нормально, сайты были доступны, но при попытке зайти в админ. панель, после ввода логина и пароля вместо панели управления появлялась белая страница.
Проверили на остальных сайтах — тоже самое.
Для того, чтобы узнать возможные причины, мы включили отображение ошибок.
Для этого необходимо по FTP отредактировать файл.htaccess, находящийся в корне сайта, добавив в него строку:

Php_flag display_errors on

После этого при входе в админ.панель появилось несколько сообщений вида «Warning: Cannot modify header information — headers already sent by (output started at /home/.../functions.php:1552) in /home/.../public_html/wp-login.php on line 362» и т.п.

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


Заголовки (Headers ) — это служебная информация сервера, на котором расположен сайт. Перед тем, как браузер отобразит содержимое сайта, он принимает заголовки от сервера, где указываются различные данные: включено ли кэширование страницы, её кодировка, тип контента страницы и другие. В системах управления содержимым сайта заголовки формируются функциями, находящимися в различных файлах системы.
Обязательно условие — заголовки должны быть отправлены до основного содержимого (контента) страницы.


Если содержимое сайта передается до заголовков, то возникает ситуация, о которой нас предупреждает сообщение «Warning: Cannot modify header information — headers already sent by...»

В каких ситуациях это может возникать? Как уже говорили, в современных CMS заголовки являются результатом работы одной или нескольких функций. Сама функция это некий фрагмент кода, заключенный между начальным и конечным ?> тегами.

Все, что находится за пределами этих тегов считается контентом страницы.
Таким образом, если в начале страницы находятся функции, результатом работы которых являются отправляемые заголовки, и мы получаем сообщение «Warning: Cannot modify header information...», то получается что какая-то информация, относящаяся к контенту страницы отправляется с сервера до заголовков.

Что это за информация и как её найти. Чаще всего это пробелы и пустые строки.

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

Нужно скачать файлы, указанные в сообщениях «Warning: Cannot modify header information...» на локальный компьютер, открыть в редакторе кода (я использую NotePad++) и внимательно проверить на наличие пустых строк и пробелов:

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

Для того, чтобы избавиться от данного идентификатора, необходимо пересохранить скаченные файлы в формат UTF-8 without BOM (UTF-8 без BOM).

С этой задачей отлично справляется NotePad++.

После этих действий и обновлений файлов на сервере, сообщение должно исчезнуть и сайт будет работать в привычном режиме.

Understanding HTTP headers and HTTP header fields

HTTP headers provide vital information required for a HTTP transaction send via http protocol .

The general HTTP header format contains colon-separated name - value pairs in the header field. Each of the name-value pair end with a carriage return (CR) and a line feed (LF) character sequence. Empty fields at the end of each header indicate the end of the header.

The common header format followed by applications looks like:

Types of HTTP headers

There are four types of HTTP message headers. They are:

  • General Header
  • Request Header
  • Response Header
  • Entity Header

General Header

General Header fields have common applicability in request and response messages. The header fields apply only to the transmitted message and do not apply on the transferred entity.

The structure of a general header looks like:

Cache-control field specifies directives that have to be followed by every caching mechanism on a request and response system.

Connection field allows the sender to specify options required for a connection. The connection header has the following format:

Date field represents the date and time during the initiation of the message. The date format specified in HTTP look like:

Pragma field helps to include implementation specific directive applicable to any recipient on a request and response system.

Trailer field value specifies whether a set of header fields in message trailer is encoded with chunk transfer-coding.

Transfer-Encoding field indicate whether any type of transformation is applied to the message body.

Upgrade field enables clients to specify additional supported communication protocols. It also enables the server to switch protocols with the additional protocols.

Via field are mandatory fields used by proxies and gateways which indicate intermediate protocols. It also indicates request recipient between user-agent and server and response between server and client.

Warning field carries additional information on message status and message transformations which are not reflected in the message.

Warning headers are usually sent with responses.

The request header field allows clients to additionally pass request information and client information to the server.

The structure of a request header looks like:

Accept field specifies media types which are acceptable for response.

"*" is used to group media types in range

"*/*" indicate all media types

"type/*" indicate all subtypes of a type

Accept-Charset field indicates response acceptable character sets. It makes clients capable to understand special-purpose character sets to signal the server to represent the document in these character sets.

Accept-Encoding field is similar to Accept, restricts response acceptable content-coding.

Accept-Language field is similar to Accept, restricts preferred set of natural languages.

Authorization field is for user agents who wish to authenticate themselves with the server.

Expect field indicates server behaviors required by a client.

From field contains e-mail address of a user who controls the requesting user-agent.

Host field specifies the internet host and requested resource port number from user URI.

If-Match field is used to make conditional methods.

If-Modified-Since field is used to make a conditional method. If the requested variant is not modified within the specified time, the entity will not be returned from the server.

If-None-Match field allows efficient update of cache information with minimum transaction overhead.

If-Range field allows clients to receive part of the missing entity or otherwise, clients can ask to send the entire new entity.

If-Unmodified-Since field allows the server to perform requested operation if it has not been modified since the time specified in this field.

Max Forwards field provides mechanisms with TRACE and OPTIONS methods to limit the request forwarding proxies or gateways.

Proxy Authorization field allows client to identify to secure proxy.

Range field specifies the HTTP entities in HTTP messages represented as a sequence of bytes. HTTP retrieval request requests one or more sub range of entity using GET methods.

Referrer field allows clients to specify the address URI of the resource from which Request-URI is found.

TE field indicates extension transfer-coding it can accept in the response. Additionally, it indicates whether it will accept trailer fields in chunk transfer-coding.

User-Agent field contains information about the requesting user-agent.

HTTP Response Header

The response header field allows the server to pass additional information through the responses other than simple Status-Line response.

The structure of the response header looks like:

Accept-Ranges field enables servers to indicate acceptance of resource range requests.

Age field indicates sender the approximate amount of time since server responded.

ETag field provides current value of the entity tag for a request.

Location field redirects recipients to locations other than Request-URI to complete identification of a new resource.

Proxy-Authenticate field is a mandatory inclusion for proxy authentication response.

Retry-After field is used as a response when a service is unavailable to indicate the length of period for which service will remain unavailable to the client.

Server field contains information about software used by server to handle requests.

Vary field indicates request field that determine whether a cache is eligible to use the response of a request without revalidation of the response.

WWW-Authenticate field are used when a response message is unauthorized.

Entity header fields define metainformation about the entity-body or the requested resource. The entity-header format looks like:

Allow field list the set of methods supported by Request-URI identified resources.

Content-Encoding field is used as a media-type modifier.

Content-Language field describes natural language for clients of an entity.

Content-Length field indicates the size of an entity represented in decimal number.

Content-Location field provides resource location for an entity when it is accessible from a location other than Requested-URI.

Content-MD5 field provides message integrity check (MIC) using an MD5 digest on the entity body.

Content-Range field specifies where partial body of the full entity-body should be applied.

Content-Type field indicates whether the media type of the entity body is sent to the recipient or GET method is used to send requests.

Expires field provides the date/time after which the response becomes stale.

Last Modified field indicates the date and time of last modification of the variant.

The order in which field name appears in the header when received is insignificant. Conventionally general headers are placed first, followed by request or response header with entity header at the end.

Copyright Notice: Please don"t copy or translate this article without prior written permission from the сайт

HTTP Debugger is a proxy-less HTTP analyzer for developers that provides the ability to capture and analyze HTTP headers, cookies, POST params, HTTP content and CORS headers from any browser or desktop application. Awesome UI and very easy to use. Not a proxy, no network issues!

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

Что означает эта ошибка?

Чтобы разобраться с причинами возникновения ошибки, нужно сначала разобраться с тем, что такое эти "заголовки".

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

Какие команды вызывают эту ошибку?

Ошибку "Cannot modify header information - headers already sent by" могут вызывать такие PHP -команды, как header , setcookie и другие, связанные с работой куки или сессий.

Причины и решения возникновения ошибки.

Самая частая ошибка происходит из-за не опытности. Мы уже разобрались, что заголовки отправляются до того, как начинает загружаться сама страница.

Но программисты, особенно начинающие попросту забывают или даже не знают этого. И сначала пытаются что-то вывести на странице - чаще всего при помощи команды echo , а потом устанавливают куки, посылают заголовки и т.д. Что приводит как раз к этой ошибке.

Вот пример кода, который приведет к такой ошибке:

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

Т.е., во-первых, нельзя ничего выводить до отправки заголовков!

Не всегда это очевидно, но есть ошибка с небольшим различием. Это когда php-документ у вас начинается с пробелов или пустых строк, что подразумевает вывод в браузере этих строк.

За этим бывает очень сложно следить, так как например Windows блокнок может добавить вначале Byte Order Mark , никак нас не предупредив и даже не показывая этот символ. В этом случае стоит открыть документ при помощи других редакторов и проверить.

Вот пример по неправильному заданию заголовков:

Т.е., во-вторых, перед

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

Вот пример такого неправильного кода: