Сессии и куки в PHP: пошаговая инструкция для начала
За полчаса вы поднимете авторизацию на сессиях, научитесь читать и ставить куки и не наступите на классические грабли с «headers already sent».

К концу этой инструкции у вас будет рабочая страница, которая помнит вошедшего пользователя между запросами: залогинились — видите приветствие, обновили страницу — оно осталось, нажали «Выйти» — данные стёрлись. Займёт минут двадцать-тридцать, если PHP уже установлен. Проверено на PHP 8.2 и 8.3, но всё описанное работает начиная с PHP 7.x.
Что нужно иметь до начала
Прежде чем писать код, убедитесь, что у вас есть всё необходимое. Иначе застрянете на середине.
- PHP 7.4 или новее. Проверьте командой
php -vв терминале. Если версия ниже — часть примеров с типами и стрелочными функциями всё равно сработает, но обновиться стоит. - Способ запустить PHP. Для тренировки хватит встроенного сервера: в папке проекта выполните
php -S localhost:8000и открывайтеhttp://localhost:8000в браузере. - Браузер с открытой панелью разработчика (F12). Вкладка Application → Cookies покажет, какие куки реально ушли клиенту. Без неё вы будете гадать.
Одно важное правило заранее: и сессии, и куки требуют, чтобы к моменту их запуска браузеру ещё не был отправлен ни один байт вывода. Ни HTML, ни пробела перед <?php, ни echo. Из-за этого правила возникает самая частая ошибка новичка, о ней в конце.
Шаг 1. Понять разницу: кука живёт в браузере, сессия — на сервере
Кука — это маленькая строка, которую сервер просит браузер хранить и присылать обратно при каждом запросе к сайту. Её видно и можно подделать на стороне клиента, поэтому пароли и роли в куки не кладут.
Сессия хранит данные на сервере (по умолчанию — в файлах во временной папке), а браузеру отдаёт только идентификатор — куку PHPSESSID. Клиент видит бессмысленную строку вроде a1b2c3..., а сами данные ему недоступны. Поэтому логин пользователя держат в сессии, а не в обычной куке.
Шаг 2. Запустить сессию и записать в неё данные
Создайте файл login.php. Сессия стартует функцией session_start() — она должна стоять до любого вывода.
<?php
// login.php — PHP 8.x
// session_start() ставим самой первой строкой, до любого HTML
session_start();
// Имитируем успешную проверку логина и пароля.
// В реальном проекте здесь была бы проверка по базе с password_verify().
$_SESSION['user_id'] = 42;
$_SESSION['user_name'] = 'Ирина';
// Перекидываем на защищённую страницу
header('Location: /profile.php');
exit;
Как понять, что получилось: откройте http://localhost:8000/login.php. Браузер должен молча переадресовать вас на profile.php (даже если файла ещё нет — увидите 404, это нормально). Во вкладке Application → Cookies появится PHPSESSID.
Шаг 3. Прочитать данные сессии на другой странице
Теперь profile.php. Здесь снова вызываем session_start() — на каждой странице, которая работает с сессией, вызов обязателен, иначе $_SESSION будет пустым.
<?php
// profile.php — PHP 8.x
session_start();
// Если пользователь не залогинен — отправляем на страницу входа
if (empty($_SESSION['user_id'])) {
header('Location: /login.php');
exit;
}
$name = $_SESSION['user_name'];
?>
<!DOCTYPE html>
<html lang="ru">
<body>
<p>Привет, <?= htmlspecialchars($name) ?>. Вы вошли.</p>
<a href="/logout.php">Выйти</a>
</body>
</html>
Обратите внимание на htmlspecialchars() при выводе — это защита от XSS, если данные пришли от пользователя. Привыкайте оборачивать вывод сразу.
Как понять, что получилось: зайдите на login.php, вас перекинет на profile.php с приветствием. Обновите страницу — приветствие осталось. Откройте profile.php в режиме инкогнито (там нет вашей куки) — вас отправит на страницу входа.
Шаг 4. Корректно завершить сессию при выходе
Удалить $_SESSION недостаточно: нужно уничтожить и серверные данные, и куку идентификатора. Файл logout.php:
<?php
// logout.php — PHP 8.x
session_start();
// 1. Очищаем массив данных сессии
$_SESSION = [];
// 2. Просим браузер удалить куку PHPSESSID (ставим ей время в прошлом)
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(),
'',
time() - 42000,
$params['path'],
$params['domain'],
$params['secure'],
$params['httponly']
);
}
// 3. Уничтожаем данные сессии на сервере
session_destroy();
header('Location: /login.php');
exit;
Как понять, что получилось: нажмите «Выйти». Во вкладке Cookies кука PHPSESSID исчезнет или обнулится, а попытка открыть profile.php вернёт на вход.
Шаг 5. Поставить и прочитать обычную куку
Куки нужны для данных, которые не секретны и должны пережить закрытие браузера: язык интерфейса, тема оформления, «показывать ли баннер». Ставятся функцией setcookie() — тоже до вывода.
<?php
// theme.php — PHP 8.x
// Запоминаем выбранную тему на 30 дней.
// Синтаксис с массивом опций доступен начиная с PHP 7.3.
setcookie('theme', 'dark', [
'expires' => time() + 60 * 60 * 24 * 30, // 30 дней
'path' => '/',
'httponly' => true, // недоступна из JavaScript
'samesite' => 'Lax', // защита от части CSRF-атак
]);
// Внимание: только что установленная кука появится в $_COOKIE
// не на этом запросе, а на следующем — после того как браузер её вернёт.
$currentTheme = $_COOKIE['theme'] ?? 'light';
echo "Тема из куки: " . htmlspecialchars($currentTheme);
Установленная кука не попадает в$_COOKIEв том же запросе, где вы её поставили. Массив$_COOKIEзаполняется из того, что браузер прислал в начале запроса. Свежую куку вы увидите только при следующей загрузке страницы.
Флаги куки, которые стоит ставить сразу
| Опция | Что делает | Когда включать |
|---|---|---|
httponly | Кука недоступна из JavaScript (document.cookie) | Почти всегда для служебных кук |
secure | Кука уходит только по HTTPS | На боевом сайте с TLS |
samesite | Ограничивает отправку куки с чужих сайтов | Lax подойдёт по умолчанию |
expires | Срок жизни куки | Без него кука живёт до закрытия браузера |
Если не получилось
Три ошибки, на которые натыкаются практически все.
Warning: session_start(): Cannot start session when headers already sent(илиCannot modify header information — headers already sent by ...). Значит, до вызова уже что-то ушло в браузер. Частая причина — пробел или пустая строка перед открывающим<?phpлибо BOM в начале файла. Уберите любой вывод доsession_start()иsetcookie(). В сообщении обычно указан файл и строка, откуда пошёл вывод — читайте её.- Сессия «не запоминается»,
$_SESSIONпуст на другой странице. Проверьте, чтоsession_start()стоит на каждой странице, работающей с сессией. Ещё причина — вы открываете страницы на разных хостах (localhostи127.0.0.1), для браузера это разные домены, и кукаPHPSESSIDтуда не отправляется. - Кука не появляется в
$_COOKIE. Скорее всего вы читаете её в том же запросе, где поставили — так не работает (см. врезку выше). Обновите страницу. Если и после этого пусто — проверьте во вкладке Application, ушла ли кука вообще и совпадает лиpath.
Что делать дальше
Базовый механизм работает. Следующие шаги, когда пойдёте в реальный проект:
- Настройте параметры куки сессии через
session_set_cookie_params()доsession_start()— включитеhttponlyиsamesiteдляPHPSESSID. - После успешного входа вызывайте
session_regenerate_id(true), чтобы сменить идентификатор сессии — это защита от фиксации сессии. - Замена хранилища сессий с файлов на Redis или базу — отдельная тема, актуальная при нескольких серверах; здесь мы её не разворачиваем.
- Проверьте актуальный набор опций
setcookie()и поведение сессий в документации вашей версии PHP — детали вроде значенияsamesite=Noneзависят от версии.
Антиблок-аналитик 115-ФЗ: Анализ выписок, поиск рисков блокировки счёта, инструкции по безопасным транзакциям.
Спросить за 41 ₽Источники: PHP Manual — Session handling, PHP Manual — setcookie
Частые вопросы
Что делать, если у меня PHP 7.2, а не 8.x?
Почему появляется ошибка «headers already sent» именно у меня, если вывода вроде нет?
Сколько данных можно хранить в сессии?
В чём разница между сессионной кукой и обычной?
Куки нужно спрашивать у пользователя согласие?
Данные сессии пропадают через некоторое время сами — это нормально?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.