Введение: почему редирект в PHP — это не просто header('Location:')
Каждый, кто хоть раз писал на PHP, сталкивался с задачей перенаправления пользователя на другую страницу. Казалось бы, что может быть проще? Одна строчка header('Location: /new-page'); — и готово. Но на практике этот простой механизм превращается в головную боль для тысяч разработчиков. Не зря вопрос «How do I make a redirect in PHP?» на Stack Overflow собрал миллионы просмотров.
Проблема в том, что редирект в PHP — это не просто вызов функции, а целый процесс, который легко сломать. Вы когда-нибудь видели ошибку «Cannot modify header information»? Или замечали, что редирект работает, но страница всё равно загружается? Или, что ещё хуже, сталкивались с тем, что редирект вообще не срабатывает, а пользователь видит пустую страницу?
В этой статье мы разберём 5 самых частых ошибок при создании редиректа в PHP, научимся их исправлять и узнаем, как сделать перенаправление безопасным и предсказуемым. Поехали!
Ошибка №1: Редирект после вывода контента (Header already sent)
Суть проблемы
Самая распространённая ошибка новичков — попытка отправить HTTP-заголовок Location после того, как в браузер уже ушёл HTML-код или даже один пробел. PHP выдаёт фатальную ошибку: «Cannot modify header information - headers already sent».
Почему это происходит?
HTTP-протокол устроен так, что заголовки должны отправляться строго до тела ответа. Как только PHP выводит что-то на экран (через echo, print, даже пустую строку перед <?php), заголовки уже зафиксированы. Изменить их нельзя.
Пример ошибки
<?php
echo "Привет!";
header('Location: /dashboard.php'); // ОШИБКА: заголовки уже отправлены
?>
Как исправить
- Правило №1: вызывайте
header()до любого вывода, включая пробелы и HTML - Правило №2: убедитесь, что в вашем PHP-файле нет пробелов или пустых строк до
<?phpили после?> - Правило №3: используйте буферизацию вывода, если без раннего вывода не обойтись
<?php
// Правильно: редирект до любого вывода
header('Location: /dashboard.php');
exit;
?>
Буферизация вывода (продвинутый метод):
<?php
ob_start(); // Включаем буферизацию
echo "Временный контент";
header('Location: /dashboard.php');
ob_end_flush(); // Отправляем всё разом
exit;
?>
Ошибка №2: Забытый exit (или die) после редиректа
Суть проблемы
Вызов header('Location: ...') не останавливает выполнение скрипта автоматически. PHP продолжает обрабатывать код дальше, а браузер, получив заголовок, начинает загружать новую страницу. Но что, если после редиректа идёт ресурсоёмкий код или, что ещё опаснее, код, изменяющий данные в базе?
Пример ошибки
<?php
header('Location: /success.php');
// Пользователь уже перенаправлен, но PHP продолжает работу!
update_user_balance($userId, -1000); // ОПАСНО: списание средств
send_email_to_admin("Пользователь совершил покупку");
?>
Как исправить
Всегда используйте exit (или die) сразу после вызова header(). Это гарантирует, что скрипт завершится и никакой лишний код не выполнится.
<?php
header('Location: /success.php');
exit; // Полная остановка скрипта
// Код ниже уже не выполнится
update_user_balance($userId, -1000);
?>
Ошибка №3: Неправильный URL (относительные vs абсолютные)
Суть проблемы
Стандарт HTTP требует, чтобы значение заголовка Location содержало абсолютный URL (с протоколом и доменом). Хотя многие современные браузеры понимают и относительные пути, полагаться на это — плохая практика. На старых браузерах или в некоторых прокси-серверах относительный редирект может не сработать.
Пример ошибки
<?php
header('Location: /dashboard'); // Относительный путь — может не сработать
exit;
?>
Как исправить
Формируйте полный URL. Лучший способ — использовать суперглобальный массив $_SERVER для динамического построения адреса.
<?php
// Простой вариант
header('Location: https://' . $_SERVER['HTTP_HOST'] . '/dashboard');
exit;
// Универсальный вариант с проверкой HTTPS
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
header('Location: ' . $protocol . '://' . $_SERVER['HTTP_HOST'] . '/dashboard');
exit;
?>
Ошибка №4: Игнорирование кода состояния (301, 302, 303)
Суть проблемы
По умолчанию PHP отправляет редирект с кодом 302 (Found) — временное перенаправление. Но в реальных проектах часто требуется явно указать тип редиректа: постоянный (301), временный (302) или редирект с изменением метода запроса (303). Ошибка в коде может привести к проблемам с SEO или некорректной работе API.
Пример ошибки
<?php
// По умолчанию 302 — временный редирект
header('Location: /new-page');
exit;
?>
Как исправить
Используйте второй параметр функции header() для замены предыдущего заголовка и третий — для указания кода состояния.
<?php
// Постоянный редирект (301) — для SEO, когда страница навсегда изменила адрес
header('Location: /new-page', true, 301);
exit;
// Редирект после POST-запроса (303) — чтобы избежать повторной отправки формы
header('Location: /success', true, 303);
exit;
// Временный редирект (302) — явное указание
header('Location: /maintenance', true, 302);
exit;
?>
Когда какой код использовать?
- 301 Moved Permanently — стра