HTTP заголовки ответа в PHP: как правильно настроить и избежать ошибок

Раздел: Работа с HTTP заголовками -> Установка заголовков ответа

Основной способ: функция header()

Как установить произвольный HTTP заголовок ответа?

Функция header() принимает строку с заголовком в формате "Имя: Значение". Вызов должен произойти до любого вывода данных (включая пробелы и HTML). Пример:


<?php
header('X-Custom-Header: MyValue');
?>
  

Php add header (добавление заголовка в php)

После этого заголовок будет передан браузеру. Если в скрипте уже был вывод (echo, print, пробелы перед <?php), возникнет ошибка Headers already sent.

Типичная проблема:

Ошибка "Cannot modify header information - headers already sent by (output started at ...)". Причина: вывод пробела, HTML или текста до вызова header(). Решение: проверить наличие пробелов перед <?php, перенести header() в самое начало скрипта, либо использовать буферизацию вывода с ob_start().

Альтернативные подходы и частные случаи

Как выполнить перенаправление (редирект)?

Для перенаправления используется заголовок Location. Третий параметр функции header() задаёт HTTP статус-код (по умолчанию 302). Пример:


<?php
header('Location: https://example.com/new-page', true, 301); // постоянный редирект
?>
  

Php http response header (установка http заголовков ответа в php)

После вызова header('Location:') следует завершить скрипт командой exit или die, чтобы предотвратить дальнейшее выполнение.

Ошибка: редирект не срабатывает, если перед header() был вывод. Решение: убедиться в отсутствии вывода, либо использовать ob_start().

Как установить Content-Type и кодировку?

Заголовок Content-Type управляет типом контента (HTML, JSON, XML и т.д.) и кодировкой символов:


<?php
header('Content-Type: text/html; charset=utf-8');
// или для JSON:
header('Content-Type: application/json; charset=utf-8');
?>
  

Если кодировка не указана, PHP по умолчанию отправляет ISO-8859-1, что может привести к некорректному отображению кириллицы. Рекомендуется всегда указывать charset=utf-8.

Как отправить несколько заголовков с одним именем?

По умолчанию header() заменяет предыдущий заголовок с тем же именем. Чтобы добавить ещё один (например, несколько Set-Cookie), нужно передать второй параметр false:


<?php
header('Set-Cookie: session=abc123', false);
header('Set-Cookie: user=john', false);
?>
  

При использовании false заголовки не перезаписываются, а добавляются.

Как установить статус-код ответа?

Для установки HTTP статус-кода используется функция http_response_code() (начиная с PHP 5.4). Пример:


<?php
http_response_code(404);
header('Content-Type: text/plain');
echo 'Страница не найдена';
?>
  

Также можно комбинировать с header('HTTP/1.1 404 Not Found'), но http_response_code() проще.

Как удалить ранее установленный заголовок?

Функция header_remove() удаляет заголовок по имени или все заголовки, если вызвана без аргументов:


<?php
header('X-Debug: 1');
// ... позже
header_remove('X-Debug'); // удалит конкретный заголовок
// header_remove(); удалит все заголовки
?>
  

Полезна при динамическом управлении заголовками в сложных приложениях.

Как установить cookie через заголовки?

Помимо функции setcookie(), можно вручную установить заголовок Set-Cookie. Это даёт полный контроль над параметрами.


<?php
$value = 'test';
$expires = time() + 3600;
header('Set-Cookie: mycookie=' . urlencode($value) . '; expires=' . gmdate('D, d M Y H:i:s T', $expires) . '; path=/; secure; httponly', false);
?>
  

При использовании setcookie() PHP сам формирует заголовок, но прямой вызов header() даёт гибкость (например, несколько значений в одной cookie).

Как избежать ошибки при уже начатом выводе?

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


<?php
ob_start(); // включить буферизацию
echo 'Некий контент';
header('Content-Type: text/html; charset=utf-8'); // теперь это возможно
ob_end_flush(); // отправить буфер
?>
  

Буферизация полезна при работе с шаблонизаторами, когда код заголовков расположен не в начале скрипта.

Как проверить, какие заголовки будут отправлены?

Функция headers_list() возвращает массив всех установленных заголовков (до их отправки). Это помогает отладке.


<?php
header('X-Test: 123');
$headers = headers_list();
print_r($headers);
?>
  

Результат можно посмотреть до вывода тела страницы.

Почему заголовок не применяется? (общие ошибки)

  • Заголовок вызван после вывода - решение: переместить вызов или использовать ob_start.
  • Некорректный синтаксис - заголовок должен содержать двоеточие после имени.
  • Конфликт с настройками PHP (output_buffering) - проверьте php.ini.
  • Заголовок перенаправления Location без exit - дальнейший код может выполняться.

Расширенные примеры с пояснениями

Пример 1: Настройка CORS заголовков

CORS (Cross-Origin Resource Sharing) позволяет разрешить запросы с других доменов. Типичная конфигурация для API:

Пример

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Max-Age: 86400');
?>
  

Здесь разрешены все источники (*) и основные методы. Для продакшена следует указывать конкретный домен вместо звёздочки.

Пример 2: Отключение кэширования страницы

Чтобы браузер не кэшировал страницу, используются заголовки Cache-Control, Pragma и Expires:

Пример

<?php
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
?>
  

Первый заголовок указывает, что данные не должны сохраняться в кэше (no-store), а второй - для совместимости с HTTP/1.0. Третий устанавливает дату в прошлом.

Пример 3: Защита от Clickjacking (X-Frame-Options)

Заголовок X-Frame-Options запрещает отображение страницы во фрейме:

Пример

<?php
header('X-Frame-Options: DENY');
// или SAMEORIGIN для разрешения фреймов того же домена
?>
  

Это стандартная практика безопасности.

Пример 4: Content-Security-Policy (CSP)

CSP позволяет ограничить источники контента (скриптов, стилей и т.д.) для защиты от XSS-атак:

Пример

<?php
header("Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'");
?>
  

Приведённая политика разрешает скрипты только с собственного домена и указанного CDN, а стили - с self и inline.

Пример 5: Передача заголовков с помощью header_register_callback

Функция header_register_callback() позволяет зарегистрировать обработчик, который вызывается перед отправкой каждого заголовка. Это может быть полезным для логирования или модификации:

Пример

<?php
header_register_callback(function() {
    error_log('Заголовок отправлен: ' . implode(', ', headers_list()));
});
header('X-Debug: 1');
?>
  

Коллбэк сработает при каждом вызове header(), даже если он не приводит к добавлению (например, при перезаписи).

Пример 6: Использование http_response_code() вместе с header()

Комбинированный пример для возврата JSON с кодом 422 (Unprocessable Entity):

Пример

<?php
http_response_code(422);
header('Content-Type: application/json; charset=utf-8');
$data = ['error' => 'Validation failed', 'details' => ['field' => 'email', 'message' => 'Invalid format']];
echo json_encode($data);
?>
  

Результат: заголовок Content-Type + JSON-тело + статус 422.

Пример 7: Установка заголовков с условной логикой (A/B тестирование)

В зависимости от параметра можно отправлять разные заголовки:

Пример

<?php
$variant = $_GET['variant'] ?? 'A';
if ($variant === 'B') {
    header('X-Experience: variant_B');
} else {
    header('X-Experience: variant_A');
}
?>
  

Результат: если в URL передать ?variant=B, заголовок будет соответствовать.

Пример 8: Передача файла через заголовки (Content-Disposition)

Для принудительной загрузки файла используется заголовок Content-Disposition:

Пример

<?php
$file = 'document.pdf';
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
?>
  

Результат: браузер предложит скачать файл document.pdf.

Установка HTTP заголовков ответа в PHP - comments

En
Php http response header (php)