HTTP заголовки в PHP: от базовых до продвинутых техник
Основы установки HTTP заголовков
Функция header() в PHP позволяет отправлять произвольные HTTP заголовки ответа. Вызов должен происходить до любого вывода данных (включая пробелы, HTML, echo). В противном случае возникает ошибка "headers already sent".
<?php
header('Content-Type: text/html; charset=utf-8');
echo 'Привет, мир!';
?>Http response code php (установка http статус кода в php)
Наиболее эффективное решение: проверка отправки заголовков
Для избежания ошибок рекомендуется перед вызовом header() проверять, не отправлены ли уже заголовки, с помощью функции headers_sent(). Также можно включить буферизацию вывода в начале скрипта.
<?php
ob_start(); // включение буферизации
// ... код ...
if (!headers_sent()) {
header('Content-Type: application/json');
echo json_encode($data);
} else {
// если заголовки уже отправлены, можно очистить буфер
ob_clean();
header('Content-Type: text/plain');
echo 'Ошибка: заголовки отправлены ранее';
}
ob_end_flush();
?>Code php header (установка http заголовков в php)
Такой подход гарантирует, что заголовки будут установлены корректно, даже если в коде есть неконтролируемый вывод.
Как выполнить перенаправление пользователя на другой URL?
Для редиректа используется заголовок Location с последующим вызовом exit или die.
<?php
header('Location: https://example.com/new-page');
exit;
?>
По умолчанию используется код состояния 302 (временный редирект). Для 301 (постоянный) нужно указать:
<?php
header('Location: https://example.com/new-page', true, 301);
exit;
?>
Типичные ошибки:
- Вызов
header()после вывода текста приводит к фатальной ошибке. - Пропуск
exitпозволяет продолжить выполнение скрипта, что может вызвать нежелательное поведение. - Использование относительного URL допускается, но рекомендуется абсолютный.
Как установить тип контента для скачивания файла?
Для принудительного скачивания файла используются заголовки Content-Type и Content-Disposition.
<?php
$file = 'document.pdf';
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
?>
Возможные проблемы:
- Неверный MIME-тип может вызвать некорректное отображение.
- Отсутствие
Content-Lengthможет сломать прогресс загрузки. - Большие файлы требуют специальной обработки (буферизация, chunked).
Как управлять кэшированием страницы через заголовки?
Для контроля кэширования используются заголовки Cache-Control, Expires, Pragma.
<?php
// Отключение кэширования
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
header('Pragma: no-cache');
?>
Для разрешения кэширования на определенное время:
<?php
$seconds = 3600; // 1 час
header('Cache-Control: public, max-age=' . $seconds);
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $seconds) . ' GMT');
?>
Распространенные ошибки:
- Неправильное указание даты в
Expires(должна быть в формате HTTP). - Смешивание
Cache-ControlиPragma(последний устарел). - Игнорирование кэширования на стороне прокси.
Как настроить CORS для кросс-доменных запросов?
Для разрешения запросов с других доменов добавляются заголовки Access-Control-Allow-Origin и другие.
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
?>
Для работы с авторизацией и куками требуется указать конкретный origin и установить Access-Control-Allow-Credentials: true.
Типичные проблемы:
- Использование
*вместе сCredentials: trueзапрещено. - Заголовки CORS должны быть отправлены даже для предварительных OPTIONS запросов.
- Необходимость обработки preflight запросов.
Как защитить сайт с помощью заголовков безопасности?
HTTP заголовки безопасности помогают предотвратить атаки XSS, clickjacking и другие.
<?php
header('X-Frame-Options: DENY'); // запрет фреймов
header('X-Content-Type-Options: nosniff'); // запрет MIME sniffing
header('Strict-Transport-Security: max-age=31536000; includeSubDomains'); // HSTS
header('Content-Security-Policy: default-src \'self\''); // политика контента
?>
Ошибки и нюансы:
- Слишком строгая CSP может сломать функциональность сайта.
- HSTS требует HTTPS и не работает при первом визите.
- X-Frame-Options устарел в пользу CSP frame-ancestors.
Как обработать ошибку "Headers already sent"?
Ошибка возникает, когда header() вызывается после вывода данных. Решение: использовать буферизацию и проверку.
<?php
ob_start(); // в начале скрипта
// ... код, который может выводить данные ...
if (!headers_sent()) {
header('Content-Type: text/plain');
} else {
ob_clean(); // очищаем буфер
header('Content-Type: text/plain');
}
// вывод
ob_end_flush();
?>
Другие причины ошибки: пробелы перед <?php, BOM в файле, вывод до header.
Как найти источник вывода:
- Включить отладку:
error_reporting(E_ALL); ini_set('display_errors', 1); - Проверить наличие пробелов и пустых строк вначале файлов.
- Использовать
var_dump(headers_list())для просмотра уже отправленных заголовков.
Расширенные примеры установки HTTP заголовков
Данные примеры демонстрируют более сложные сценарии использования функции header().
Пример 1: Условное кэширование с ETag
<?php
$etag = md5(file_get_contents('content.txt'));
header('ETag: "' . $etag . '"');
header('Cache-Control: public, max-age=3600');
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == '"' . $etag . '"') {
header('HTTP/1.1 304 Not Modified');
exit;
}
readfile('content.txt');
?>
Результат:
При повторном запросе сервер вернет 304 Not Modified без тела, если контент не изменился.
Пример 2: Отправка нескольких кук с атрибутами
<?php
$cookieValue1 = 'session123';
$cookieValue2 = 'prefs_dark';
header('Set-Cookie: session=' . urlencode($cookieValue1) . '; Path=/; Secure; HttpOnly; SameSite=Strict');
header('Set-Cookie: preferences=' . urlencode($cookieValue2) . '; Path=/; Expires=' . gmdate('D, d M Y H:i:s', time() + 86400*30) . ' GMT; HttpOnly');
?>
Результат:
Браузер установит две куки с разными сроками жизни и атрибутами безопасности. Первая кука (сессионная) будет удалена при закрытии браузера, вторая сохранится на 30 дней.
Пример 3: Динамическая генерация изображения с заголовками
<?php
$width = 200;
$height = 100;
$text = 'Hello';
$im = imagecreatetruecolor($width, $height);
$bg = imagecolorallocate($im, 255, 255, 255);
$textcolor = imagecolorallocate($im, 0, 0, 0);
imagestring($im, 5, 50, 40, $text, $textcolor);
header('Content-Type: image/png');
header('Content-Disposition: inline; filename="hello.png"');
header('Cache-Control: public, max-age=86400');
imagepng($im);
imagedestroy($im);
?>
Результат:
Браузер отобразит изображение PNG с текстом, а заголовки укажут на возможность кэширования на сутки.
Пример 4: Удаление заголовков с помощью header_remove()
<?php
header('X-Powered-By: PHP/7.4');
// позже решили удалить
header_remove('X-Powered-By');
?>
Результат:
Заголовок X-Powered-By не будет включен в ответ сервера, что улучшает безопасность, скрывая версию PHP.
Пример 5: Заголовок Link для HTTP/2 Server Push
<?php
header('Link: </style.css>; rel=preload; as=style');
header('Link: </script.js>; rel=preload; as=script');
?>
Результат:
Сервер, поддерживающий HTTP/2, может отправить указанные ресурсы клиенту до запроса, сокращая время загрузки.