У цій вступній замітці ми розглянемо стандартні функції PHP по роботі з HTTP заголовками. Ми детально розглянемо всі переваги і недоліки цих функцій.
Функція header ()
Функція header () записує в масив заголовків поточного HTTP-відповіді черговий заголовок. Функція має один обов'язковий аргумент string string, який повинен містити рядок заголовка.
Другий необов'язковий аргумент bool replace включає або відключає режим перезапису значення заголовка. Якщо аргумент має значення true, то нові заголовки будуть замінювати вже записані в масив заголовки з тим же ім'ям. Якщо аргумент має значення false, то нове значення вже наявного заголовка буде додано в попередній заголовок через кому. Наприклад: PHP В результаті в заголовках відповіді виявиться один заголовок з двома значеннями HTTP Втім, якщо вам відразу відомі всі надіслані значення цього заголовка, то простіше записати їх одним рядком: PHP
Третій необов'язковий параметр int http_response_code може містити код стану (код відповіді), згідно з яким буде змінено рядок стану.
Однак, не дивлячись на те, що функція header () приймає рядок заголовка в сирому вигляді, вона не настільки ліберальна, щоб записувати в заголовки все, що ви їй передасте. Існують певні обмеження на формат записуваних заголовків. Якщо вимоги не виконуються, це в кращому випадку призведе до відсутності очікуваної вами рядка в переданих клієнтові заголовках. У гіршому випадку клієнт отримає відповідь з кодом стану 500 Internal Server Error.
Функції header () можуть бути передані два види рядків: рядок стану і HTTP-заголовки.
На передаються HTTP-заголовки накладається наступне обмеження: вони повинні містити ім'я та значення заголовка, відокремлені знаком двокрапки. Якщо відсутня ім'я, значення або пропущено двокрапку, то такий рядок не розглядається як заголовок і ігнорується. Крім того ім'я заголовка має складатися тільки з символів ASCII. Ніяких інших обмежень на імена і значення немає. Ви можете вигадувати власні заголовки і відправляти їх кому заманеться. Відповідно до стандарту протоколу HTTP, невідомі заголовки повинні передаватися на всіх ділянках ланцюга, а браузери при інтерпретації заголовків повинні їх ігнорувати.
Одним з незаперечних переваг функції header () є те, що вона може змінювати рядок стану HTTP відповіді. Рядок стану завжди стоїть першим рядком в масиві заголовків і має такий вигляд: HTTP
Версія протоколу може бути як конкретної, наприклад 1.0 або 1.1, так і загальної, наприклад 1.x. Однак при спробі записати конкретну версію протоколу, я виявляв, що клієнту все одно вирушає загальний шаблон 1.x. Можливо тут винен не PHP, а сервер Apache, який якось обробляє заголовки перед відправкою.
Код стану - це числовий код, співвіднесений з певним типом відповіді. Обробка неіснуючих кодів стану залежить від версії сервера Apache. Більш ранні версії не дозволяли відправляти некоректні коди стану. При спробі передати невідомий код стану (наприклад 430 або 600), клієнт отримує відповідь з помилкою: HTTP
Однак, у новій версії Apache 2 допустимо відправляти неіснуючі коди станів. До неіснуючому коду стану Apache 2 додає пояснює фразу "OK".
Пояснює фразу можна взагалі не передавати. Якщо ви її не передасте, то Apache сам допише її, на підставі коду стану. Якщо ж ви передасте якусь довільну пояснює фразу, вона все одно буде переписана на стандартну фразу на підставі переданого коду стану.
У функції header () існує особлива поведінка при додаванні заголовка Location. Крім додавання цього заголовка функція змінює рядок стану на HTTP / 1.x 302 Found. Але якщо вам необхідно встановити інший код стану, наприклад 307 Temporary Redirect, то вам буде потрібно додатковий виклик функції header (), щоб змінити рядок стану. Не важливо, буде це зроблено до додавання заголовка Location, або після - зміни будуть збережені і відправлені клієнту. Але існує більш витончений спосіб з використанням третього аргументу int http_response_code. Тема location з кодом стану 307 можна додати одним рядком наступним чином: PHP
У світлі змін в PHP 4.3.0, які дозволили змінювати рядок стану таким способом, стає абсолютно безглуздим зміна рядка стану явно (хіба що для наочності). Адже фактично, як ми побачили вище, функція header () реагує тільки на код стану, який ви їй передаєте в рядку стану. А версію протоколу і пояснює фразу Apache все одно ставить на свій розсуд. Неприпустимі коди станів в аргументі http_response_code обробляються точно так же, як і при передачі їх в рядку стану. Більш детальну інформацію про коди стану без прив'язки до PHP можна прочитати в замітці Коди стану протоколу HTTP.
При використанні функції header () важливо пам'ятати, що запис заголовків відповіді можлива тільки до тих пір, поки не почалося виведення даних в вихідний потік. Як тільки ви виводите дані на екран (конструкція echo, print, print_f і ін. Або ж просто текст або прогалини поза тегів ), Разом з цими першими даними відправляються і заголовки відповіді. Якщо після цього ви спробуєте записати заголовок відповіді, ви отримаєте наступне попередження:
Warning: Can not modify header information - headers already sent by
і далі повідомляється файл PHP-скрипта і рядок коду, в якій було розпочато виведення даних в вихідний потік.
Функція headers_list ()
Функція headers_list () доступна лише з п'ятої версії PHP. Вона повертає тільки ті заголовки, які були додані з PHP-скрипта. Якщо ви не прописували ніяких заголовків, функція поверне тільки заголовок X-Powered-By: PHP / 5.2.10. і то не завжди. Звичайно, інакше бути не може, адже всі інші заголовки сервер прописує вже після виконання скрипта PHP.
Більш того, ця функція не повертає рядок стану, навіть якщо вона була змінена з PHP-скрипта.
Функція headers_sent ()
Отладочная функція, що повідомляє про те, відправлені клієнту заголовки поточного HTTP-відповіді. Два необов'язкові параметри дозволяють записати в передані змінні ім'я PHP скрипта (перший аргумент) і номер рядка (другий аргумент), де почалося виведення даних в вихідний потік, з якими були відправлені заголовки.
Функція getallheaders ()
Ця функція працює тільки в тому випадку, якщо PHP працює як модуль Apache. Щоб цей факт був більш очевидний, починаючи з PHP 4.3.0 ця функція отримала псевдонім apache_request_headers ()
а так само всі змінні оточення з іменами "HTTP_ІМЯ_ЗАГОЛОВКА", які створені сервером на підставі заголовків поточного HTTP-запиту. Приклади інших змінних оточення, що містять заголовки запиту: $ _SERVER [ 'HTTP_KEEP_ALIVE']. $ _SERVER [ 'HTTP_CACHE_CONTROL']. $ _SERVER [ 'HTTP_REFERER']. Ці елементи можуть бути і відсутніми в масиві, якщо клієнт не передав відповідні заголовки запиту.
На жаль, чого не можна дізнатися, так це клієнтської версії HTTP протоколу, яка міститься в рядку запиту.
Одним з достоїнств функції getallheaders () перед масивом $ _SERVER є те, що вона надає імена заголовків в їх первозданному вигляді, тоді як в масиві $ _SERVER до імені заголовка додається префікс "HTTP_". Однак з огляду на той факт, що імена заголовків є регістронезавісімого, клієнт може передати імена в нижньому регістрі, а може з великими літерами, або, у виняткових випадках, в будь-якому екзотичному варіанті регістрів. Цим ускладнюється пошук цікавлять заголовків в масиві, який видає функція getallheaders (). З масивом $ _SERVER такої проблеми немає - там все ключі масиву завжди у верхньому регістрі.
Функція get_headers ()
До версії PHP 5.3.0 ця функція має один недолік, який обмежує її застосування виключно налагоджувальними цілями. За логікою протоколу HTTP ця функція повинна була б здійснювати запит методом HEAD, тому що її цікавлять тільки заголовки. Однак при виклику цієї функції PHP посилає віддаленого серверу запит наступного виду: HTTP
Природно, на цей запит віддалений сервер повертає не тільки заголовки, а й вміст ресурсу, яке в порівнянні з заголовками займає обсяг часом в сотні разів більший. Таким чином, робиться кричуще не раціонально запит, безглуздо навантажує обидва сервера і мережу маршрутизаторів і шлюзів між ними. Розробники протоколу HTTP всіляко борються за ослаблення зростаючого навантаження на мережу, а програмні рішення на кшталт функції get_headers (), а точніше їх бездумне використання зводять ці зусилля нанівець.
Однак у версії PHP 5.3.0 цей недолік був усунутий з появою функції stream_context_set_default (). Ще починаючи з версії 5.1.3 функція get_headers () використовує stream context за замовчуванням. Але налаштування stream context стало можливим міняти тільки з версії 5.3.0, наприклад змінити метод запиту. PHP
Зрозуміло робити це потрібно перед викликом функції get_headers ().
Метод HTTP-запиту HEAD був введений ще в HTTP / 1.0 Цей метод був розроблений саме для таких випадків. У специфікації RFC 1 945 особливо відзначено, що цей метод ідентичний методу GET за винятком того, що він не повертає вмісту ресурсу. Правда в специфікації RFC 2616 для протоколу HTTP / 1.1 умова повернення ідентичних заголовків в порівнянні з методом GET має рівень вимоги SHOULD, тобто бажано, але не сторого обов'язково (докладніше див. замітку метод HEAD). Найбільш популярний сервер Apache підтримує цю вимогу. Смію припустити, що і багато інших сервери теж його підтримують.