Сессия PHP истекает через 30 минут: 4 работающих способа

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Вступление: «Почему моя сессия не умирает?»

Представьте: вы пишете интернет-магазин, админку или личный кабинет. Пользователь вошёл, поработал, ушёл пить кофе — а через час его сессия всё ещё жива. Данные в корзине висят, доступ открыт. Это не только неудобно, но и опасно. Особенно если сайт работает с платёжными данными.

Вопрос «How do I expire a PHP session after 30 minutes?» — один из самых популярных на Stack Overflow (десятки тысяч просмотров). И неудивительно: начинающие разработчики часто думают, что достаточно выставить session.gc_maxlifetime — и всё заработает. А потом удивляются, почему сессия живёт часами.

В этой статье мы разберём 4 реальных подхода, как заставить PHP сессию истекать ровно через 30 минут. Вы узнаете, почему стандартные настройки могут подвести, и какой метод выбрать под свою задачу. Поехали!

Немного теории: как PHP управляет временем сессии

Прежде чем писать код, важно понять два механизма, которые влияют на «смерть» сессии:

  • Время жизни cookie сессии — сколько браузер хранит идентификатор сессии (PHPSESSID). Управляется параметром session.cookie_lifetime.
  • Время жизни данных на сервере — как долго файл сессии лежит в папке /tmp. Управляется session.gc_maxlifetime.

Проблема в том, что сборщик мусора (GC — garbage collector) запускается вероятностно. По умолчанию он срабатывает в 1% запросов. Это значит, что даже если gc_maxlifetime = 1800 (30 минут), сессия может висеть ещё час, пока GC до неё доберётся.

Поэтому полагаться только на серверную настройку — плохая идея. Нужно проверять время «вручную».

Способ №1. Классический: проверка времени в сессии (рекомендуемый)

Это самый надёжный и прозрачный способ. Вы сами храните в сессии метку времени последней активности, и при каждом запросе проверяете, не прошло ли 30 минут.

<?php
session_start();

// Устанавливаем время жизни сессии — 30 минут (1800 секунд)
$timeout_duration = 1800;

// Если в сессии есть метка времени и она просрочена
if (isset($_SESSION['LAST_ACTIVITY']) && 
    (time() - $_SESSION['LAST_ACTIVITY']) > $timeout_duration) {
    // Уничтожаем сессию
    session_unset();
    session_destroy();
    // Перенаправляем на страницу логина
    header("Location: login.php?timeout=1");
    exit;
}

// Обновляем метку времени (если пользователь активен)
$_SESSION['LAST_ACTIVITY'] = time();
?>

Плюсы:

  • Абсолютный контроль: сессия умрёт ровно через 30 минут бездействия.
  • Не зависит от настроек PHP и сборщика мусора.
  • Легко менять время под разные разделы сайта (например, админка — 15 минут, пользователь — 60).

Минусы:

  • Нужно добавлять проверку на каждую страницу (или вынести в общий файл инициализации).
  • Если пользователь держит страницу открытой, но не кликает — сессия умрёт. Для некоторых сценариев (долгая форма) это минус.

Способ №2. Комбинированный: gc_maxlifetime + cookie_lifetime

Если вы не хотите писать ручную проверку, можно попробовать настроить PHP «из коробки». Но помните о нюансах.

// В начале скрипта, до session_start()
$lifetime = 1800; // 30 минут

// Устанавливаем время жизни cookie сессии
session_set_cookie_params($lifetime);

// Устанавливаем максимальное время жизни данных на сервере
ini_set('session.gc_maxlifetime', $lifetime);

// Теперь стартуем сессию
session_start();

Дополнительно — чтобы GC работал чаще, можно уменьшить вероятность запуска:

ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1); // GC будет запускаться при каждом запросе

Важно! Установка gc_divisor = 1 может слегка нагрузить сервер на высоконагруженных проектах. Для маленьких сайтов — OK.

Плюсы:

  • Минимум кода.
  • Работает «из коробки» на стандартных хостингах.

Минусы:

  • Cookie живёт 30 минут с момента создания, а не с момента последнего действия. Если пользователь активен, cookie всё равно умрёт через 30 минут.
  • GC может не успеть подчистить старые сессии (если не менять gc_probability).
  • Не подходит, если нужно продлевать сессию при каждом действии.

Способ №3. Продвинутый: регенерация ID сессии + скользящее окно

Этот подход часто используют банковские и платёжные системы. Суть: при каждом действии пользователя мы не только проверяем время, но и регенерируем ID сессии, чтобы предотвратить фиксацию сессии (session fixation).

<?php
session_start();

$timeout = 1800; // 30 минут
$regenerate_time = 300; // регенерировать ID каждые 5 минут

// Проверка на таймаут
if (isset($_SESSION['LAST_ACTIVITY']) && 
    (time() - $_SESSION['LAST_ACTIVITY'] > $timeout)) {
    session_unset();
    session_destroy();
    header("Location: login.php?timeout=1");
    exit;
}

// Регенерация ID сессии для безопасности
if (!isset($_SESSION['CREATED'])) {
    $_SESSION['CREATED'] = time();
} else if (time() - $_SESSION['CREATED'] > $regenerate_time) {
    session_regenerate_id(true);
    $_SESSION['CREATED'] = time();
}

// Обновляем метку последней активности
$_SESSION['LAST_ACTIVITY'] = time();
?>

Плюсы:

  • Максимальная безопасность: ID сессии меняется каждые 5 минут.
  • Скользящее окно: сессия продлевается при каждом действии.
  • Идеально для интернет-банков и кабинетов с деньгами.

Минусы:

  • Больше кода.
  • Требует понимания безопасности сессий (не для новичков).

Способ №4. Хардкорный: ручное управление файлами сессий

Этот метод используется, когда стандартные механизмы PHP не подходят (например, вы храните сессии в базе

Блоги

Рекомендаций по книгам