PHP-сессии: полное руководство
Как работают PHP-сессии, как хранить и получать данные сессий и защищать их от атак с подменой и перехватом идентификатора.
HTTP — протокол без сохранения состояния: каждый запрос браузера независим, и сервер забывает всё, как только отправляет ответ. Сессии — это механизм, с помощью которого PHP запоминает посетителя между запросами: они позволяют удерживать пользователя в системе, строить корзину покупок или сохранять настройки по мере перехода со страницы на страницу. В этом руководстве рассматривается, что такое сессии, как они работают изнутри, как читать и записывать данные сессий и как обеспечить их безопасность.
Что такое PHP-сессии?
PHP-сессия — это механизм хранения пользовательских данных на стороне сервера на протяжении всего визита пользователя. В отличие от куков, которые хранят данные в браузере, сессия хранит сами данные на сервере и отправляет браузеру лишь небольшой идентификатор сессии, чтобы определить, кому принадлежат данные.
Это важно по двум причинам:
- Объём — куки ограничены примерно 4 КБ и хранятся в браузере; данные сессии хранятся в серверном хранилище (файлах, базе данных или памяти) и могут быть значительно больше.
- Безопасность — конфиденциальные значения (идентификатор пользователя, роль или содержимое корзины) никогда не покидают сервер, поэтому браузер не может их прочитать или подделать. Наружу передаётся только непрозрачный идентификатор сессии.
Как работают PHP-сессии?
При запуске сессии PHP генерирует уникальный идентификатор сессии для посетителя и отправляет его браузеру в куке с именем PHPSESSID. При каждом последующем запросе браузер возвращает эту куку, и PHP использует идентификатор для поиска соответствующих данных, хранящихся на сервере. Сами данные доступны вашему коду через array $_SESSION.
Рабочий процесс сессии
graph LR
A[Browser] -- 1. Request + Session Cookie --> B[Server]
B -- 2. Validate Cookie & Fetch Data --> A
A -- 3. Receive Response --> BКоротко: кука содержит идентификатор; сервер хранит данные.
Запуск сессии
Каждая страница, которая читает или записывает данные сессии, должна вызывать session_start() до того, как в браузер будут отправлены какие-либо данные. Поскольку session_start() отправляет куку PHPSESSID через HTTP-заголовок, даже один пробел или пустая строка перед открывающим тегом <?php вызовет предупреждение «headers already sent» и сломает сессию.
Вызов session_start() либо возобновляет существующую сессию посетителя (если браузер прислал действительный идентификатор), либо создаёт новую. Проверка через session_status() позволяет избежать предупреждения, если сессия уже была запущена ранее в том же запросе:
Как запустить PHP-сессию
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}Чтение и запись данных сессии
После запуска сессии суперглобальная переменная $_SESSION ведёт себя как обычный ассоциативный array. Присвойте значение ключу для его сохранения:
Сохранение данных в PHP-сессии
<?php
$_SESSION['username'] = 'John Doe';
$_SESSION['cart'] = ['book', 'pen'];Считайте данные на той же странице или на любой последующей странице в рамках той же сессии:
Получение данных из PHP-сессии
<?php
// Always check the key exists to avoid a warning
$username = $_SESSION['username'] ?? 'Guest';
echo "Welcome, {$username}";Поскольку данные сохраняются между запросами, распространённый паттерн — счётчик просмотров страниц, который выживает при перезагрузках:
Подсчёт просмотров страниц в текущей сессии
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$_SESSION['views'] = ($_SESSION['views'] ?? 0) + 1;
echo "You have viewed this page {$_SESSION['views']} time(s).";Чтобы удалить одно значение, используйте unset() по его ключу — не присваивайте null, это оставит ключ в массиве:
<?php
unset($_SESSION['cart']);Сессии и куки
Сессии и куки часто работают вместе, но хранят данные в разных местах. Используйте сессию, когда данные конфиденциальны или велики; используйте куку, когда браузер сам должен что-то помнить (например, токен «запомнить меня») между визитами.
| Сессия | Кука | |
|---|---|---|
| Хранится на | Сервере | Браузере |
| Видна пользователю | Нет (только идентификатор) | Да |
| Ограничение размера | Большое (серверное хранилище) | ~4 КБ |
| Время жизни | До закрытия браузера или тайм-аута | Настраиваемый срок |
Защита PHP-сессий
Важно защитить PHP-сессии, чтобы предотвратить несанкционированный доступ к конфиденциальным данным пользователей. Существует несколько способов защитить PHP-сессии:
- Периодически обновляйте идентификатор сессии.
- Храните данные сессии на сервере в защищённом каталоге.
- Используйте HTTPS для защиты передачи данных сессии.
Обновление идентификатора сессии и усиление защиты куки
Параметры усиления защиты необходимо установить до вызова session_start(), иначе кука уже будет отправлена со старыми настройками. Обновление идентификатора сразу после изменения привилегий (например, входа в систему) предотвращает атаки подмены сессии, при которых злоумышленник вынуждает жертву использовать известный ему идентификатор сессии:
<?php
// Configure before the session starts
ini_set('session.cookie_secure', '1'); // send cookie over HTTPS only
ini_set('session.use_only_cookies', '1'); // never accept the ID from the URL
ini_set('session.cookie_httponly', '1'); // hide the cookie from JavaScript
session_start();
// After a successful login, swap the ID and discard the old one
session_regenerate_id(true);| Настройка | От чего защищает |
|---|---|
cookie_secure | Утечка идентификатора сессии через HTTP |
cookie_httponly | Кража куки через JavaScript (XSS) |
use_only_cookies | Передача идентификатора сессии в URL |
session_regenerate_id | Подмена сессии после входа в систему |
Завершение PHP-сессии
Чтобы выйти из системы, очистите данные и уничтожьте сессию. Очистка $_SESSION удаляет переменные; session_destroy() удаляет данные на сервере; удаление куки не позволяет браузеру отправлять устаревший идентификатор:
<?php
session_start();
// 1. Clear all session variables
$_SESSION = [];
// 2. Delete the session cookie in the browser
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. Destroy the data stored on the server
session_destroy();Заключение
PHP-сессии — незаменимый инструмент для хранения пользовательских данных на стороне сервера и улучшения пользовательского опыта на вашем сайте. Понимая принципы их работы и умея их использовать, вы сможете в полной мере воспользоваться преимуществами, которые они предоставляют. При наличии надлежащих мер безопасности вы также обеспечите защиту конфиденциальных данных пользователей.