Headers sent: примеры (PHP)

Использование headers_sent для контроля отправки HTTP-заголовков
Раздел: HTTP
headers_sent(&$filename = null, &$line = null): bool

Функция headers_sent в PHP

Функция headers_sent() в языке PHP проверяет, были ли уже отправлены HTTP-заголовки клиенту. Её основное применение - предотвращение ошибок, связанных с попыткой изменить заголовки после их отправки, что в протоколе HTTP не допускается. Эта функция часто используется перед вызовом header(), setcookie() или session_start().

Аргументы функции

Функция поддерживает два необязательных параметра:

  • $filename (string) - если заголовки уже отправлены, в эту переменную будет записано имя файла скрипта, в котором это произошло.
  • $line (int) - если заголовки отправлены, в эту переменную будет записан номер строки в файле, на которой это произошло.

Возвращаемое значение: bool - true, если заголовки отправлены, false в противном случае.

Примеры использования headers_sent
Базовое применение

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

<?php
if (!headers_sent()) {
    header('Location: /newpage.php');
    exit;
} else {
    echo 'Заголовки уже отправлены. Перенаправление невозможно.';
}
?>
Заголовки уже отправлены. Перенаправление невозможно.
Использование с параметрами для отладки
<?php
// Попытка отправить cookie после вывода
echo 'Некоторый вывод';

if (headers_sent($file, $line)) {
    echo "Заголовки отправлены в файле $file на строке $line";
} else {
    setcookie('test', 'value');
}
?>
Некоторый вывод
Заголовки отправлены в файле /var/www/script.php на строке 3
Похожие функции в PHP
  • header() - непосредственно отправляет HTTP-заголовок. headers_sent() часто используется как условие перед вызовом этой функции.
  • ob_start() - включает буферизацию вывода, что позволяет откладывать отправку заголовков до момента вывода всего контента. Предпочтительнее для сложных сценариев, где возможен ранний вывод.
  • session_start() - также отправляет заголовки (cookie сессии). Перед её вызовом в существующем коде иногда проверяют headers_sent().

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

Аналоги в других языках
Python (Django/Flask)

В веб-фреймворках Python заголовки обычно устанавливаются до начала тела ответа, но явной проверки нет. Фреймворк контролирует этот процесс.

# Flask пример
from flask import Flask, make_response
app = Flask(__name__)

@app.route('/')
def index():
    response = make_response('Hello')
    response.headers['X-Custom'] = 'Value'  # Заголовки можно менять до возврата
    return response
JavaScript (Node.js)
// Express.js пример
app.get('/', (req, res) => {
    // Проверка, отправлены ли заголовки
    if (res.headersSent) {
        console.log('Заголовки уже отправлены');
    } else {
        res.setHeader('Content-Type', 'text/html');
        res.send('Hello');
    }
});
Отличия

В отличие от PHP, где проверка глобальная, в Node.js свойство headersSent относится к конкретному объекту ответа. В Python типичный паттерн предполагает формирование объекта ответа с заголовками до отправки.

Типичные ошибки
Некорректная интерпретация возвращаемого значения
<?php
// ОШИБКА: Логическая ошибка в условии
if (headers_sent()) {
    header('Content-Type: application/json'); // Попытка отправить после отправки
}
?>
Warning: Cannot modify header information - headers already sent
Вывод перед проверкой
<?php
echo 'Старт';
// Любой вывод, включая пробелы до <?php или после ?> в included файлах,
// может вызвать отправку заголовков.
if (!headers_sent()) { // Условие уже не выполнится
    setcookie('name', 'value');
}
?>
Старт
Warning: Cannot modify header information - headers already sent
Изменения в PHP 8

В PHP 8 не было внесено значительных изменений в поведение или сигнатуру функции headers_sent(). Функция сохраняет обратную совместимость с предыдущими версиями языка. Однако, в PHP 8.1 были улучшены некоторые внутренние механизмы обработки заголовков, но это не повлияло на внешний API функции.

Расширенные примеры
Буферизация вывода с проверкой
Пример php
<?php
ob_start(); // Включаем буферизацию
// ... сложная логика с потенциальным выводом ...
echo 'Потенциально ранний вывод';

// Проверяем, не было ли вывода до ob_start()
if (headers_sent()) {
    echo '<div class="error">Критическая ошибка конфигурации</div>';
} else {
    // Безопасно отправляем заголовки, так как вывод в буфере
    header('Cache-Control: no-cache');
    setcookie('session', 'token');
    ob_end_flush(); // Отправляем вывод
}
?>
Логирование точки отправки заголовков
Пример php
<?php
function safe_header($header, $value) {
    if (!headers_sent($file, $line)) {
        header("$header: $value");
        return true;
    } else {
        error_log("Попытка отправить заголовок $header после отправки в $file:$line");
        return false;
    }
}

// Использование
safe_header('Content-Type', 'text/html');
?>
Интеграция с исключениями
Пример php
<?php
class HeadersSentException extends Exception {}

function require_headers_not_sent() {
    if (headers_sent($file, $line)) {
        throw new HeadersSentException("Заголовки отправлены в $file:$line", $line);
    }
}

try {
    require_headers_not_sent();
    header('Location: /secure');
} catch (HeadersSentException $e) {
    // Альтернативная логика без перенаправления
    echo '<meta http-equiv="refresh" content="0;url=/secure">';
}
?>

PHP headers_sent function comments

En
Headers sent Checks if or where headers have been sent