Avatar ·

Как исправить ошибку "Headers already sent" в PHP

Всем привет! Я новичок в PHP и столкнулся с очень неприятной ошибкой. Пишу простой скрипт для редиректа пользователя после авторизации, но получаю сообщение: Warning: Cannot modify header information - headers already sent by (output started at /home/user/index.php:10) Вот мой код: ```php Авторизация
``` Я понимаю, что ошибка связана с тем, что заголовки уже отправлены, но не могу понять, почему это происходит. Ведь я вызываю header() до того, как вывожу HTML. Может быть, проблема в том, что у меня есть пробелы или пустые строки перед >>

Причина ошибки

Ошибка "Headers already sent" возникает, когда PHP-скрипт пытается отправить HTTP-заголовок (с помощью header(), setcookie(), session_start() и т.д.) после того, как тело ответа уже начало отправляться. В PHP заголовки должны отправляться до любого вывода — будь то echo, print, HTML-код или даже пустая строка перед <?php.

В вашем коде проблема в строке echo "Успешный вход!";. Этот вывод отправляется в браузер немедленно. После этого вызов header() уже невозможен, потому что заголовки были отправлены вместе с первым байтом вывода.

Решение 1: Убрать echo перед header()

Самый простой способ — не выводить ничего до вызова header(). Если вам нужно сообщить пользователю об успехе, сделайте это после редиректа на целевой странице.

<?php
session_start();

if ($_POST['login'] == 'admin' && $_POST['pass'] == '123') {
    // Никакого echo! Просто редирект
    header('Location: /dashboard.php');
    exit;
}
?>
<html>
<head><title>Авторизация</title></head>
<body>
<form method="post">
    <input type="text" name="login">
    <input type="password" name="pass">
    <button type="submit">Войти</button>
</form>
</body>
</html>

Решение 2: Использовать буферизацию вывода

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

<?php
ob_start(); // Включаем буферизацию
session_start();

if ($_POST['login'] == 'admin' && $_POST['pass'] == '123') {
    echo "Успешный вход!";
    header('Location: /dashboard.php');
    ob_end_clean(); // Очищаем буфер и отправляем заголовки
    exit;
}
ob_end_flush(); // Отправляем всё, что накопилось в буфере
?>
<html>
...

Решение 3: Проверить наличие BOM и пробелов

Частая причина — невидимые символы перед <?php. Убедитесь, что:

  • В файле нет пробелов, табуляций или пустых строк перед открывающим тегом <?php
  • Файл сохранён в кодировке UTF-8 без BOM (Byte Order Mark). BOM — это невидимые символы в начале файла, которые воспринимаются как вывод
  • После закрывающего тега ?> нет лишних пробелов или переводов строки (лучше вообще не использовать закрывающий тег в конце файла)
<?php
// Правильно: нет пробелов перед <?php
// И нет закрывающего тега ?> в конце файла
session_start();
// ... ваш код
// Файл заканчивается без ?>

Дополнительные советы

  • Всегда вызывайте exit или die после header('Location: ...'), чтобы скрипт не продолжал выполнение
  • Используйте функцию headers_sent() для проверки, были ли уже отправлены заголовки: if (!headers_sent()) { header(...); }
  • В production-среде включите output_buffering в php.ini (обычно включено по умолчанию)
<<>>

Альтернативный подход: разделение логики и представления

Вместо того чтобы бороться с ошибкой, лучше изменить архитектуру кода. Разделите логику обработки формы и отображение HTML. Это не только решит проблему с заголовками, но и сделает код чище и удобнее для поддержки.

Создайте два файла:

login.php — только форма:

<html>
<body>
<form method="post" action="auth.php">
    <input type="text" name="login">
    <input type="password" name="pass">
    <button type="submit">Войти</button>
</form>
</body>
</html>

auth.php — только логика:

<?php
session_start();

if ($_POST['login'] == 'admin' && $_POST['pass'] == '123') {
    $_SESSION['user'] = 'admin';
    header('Location: /dashboard.php');
    exit;
}

// Если данные неверные — редирект обратно с сообщением об ошибке
header('Location: /login.php?error=1');
exit;

Этот подход полностью исключает возможность вывода до заголовков, так как файл auth.php не содержит никакого HTML. Кроме того, он соответствует принципу единой ответственности (Single Responsibility Principle) и упрощает тестирование.