Как завершить сессию PHP через 30 минут неактивности пользователя?
Решение: проверка времени последнего действия вручную
Параметры session.gc_maxlifetime и session.cookie_lifetime действительно не гарантируют точное истечение сессии по времени неактивности. Первый отвечает за время жизни файла сессии на сервере, но сборщик мусора (GC) запускается только с вероятностью 1% при каждом запросе (по умолчанию). Второй — за время жизни куки в браузере, но это не отменяет данные сессии на сервере.
Правильный подход — хранить в сессии метку времени последнего действия пользователя и проверять её при каждом запросе. Вот полный пример реализации:
<?php
// Настройка времени жизни сессии (30 минут = 1800 секунд)
$timeout = 1800; // 30 минут
// Запуск сессии
session_start();
// Функция для проверки и обновления времени активности
function checkSessionTimeout($timeout) {
// Если в сессии есть метка времени последнего действия
if (isset($_SESSION['last_activity'])) {
// Вычисляем разницу между текущим временем и последним действием
$inactive_time = time() - $_SESSION['last_activity'];
// Если прошло больше, чем $timeout секунд
if ($inactive_time > $timeout) {
// Уничтожаем сессию
session_unset(); // Очищаем все переменные сессии
session_destroy(); // Уничтожаем сессию
return true; // Возвращаем true, если сессия истекла
}
}
// Обновляем время последнего действия
$_SESSION['last_activity'] = time();
return false; // Сессия активна
}
// Вызываем проверку при каждом запросе
$session_expired = checkSessionTimeout($timeout);
if ($session_expired) {
// Перенаправляем на страницу логина или выводим сообщение
header('Location: login.php?expired=1');
exit;
}
// Остальной код страницы (только если сессия активна)
?>
Как это работает?
- Хранение метки времени: При каждом успешном запросе мы сохраняем в
$_SESSION['last_activity']текущий timestamp с помощьюtime(). - Проверка при каждом запросе: В начале скрипта вызывается
checkSessionTimeout(). Если разница между текущим временем иlast_activityпревышает 30 минут, сессия уничтожается. - Автоматическое продление: Если пользователь активен (делает запросы), метка времени обновляется, и таймер сбрасывается.
Дополнительные рекомендации
Для надёжности можно также настроить параметры сессии, чтобы сборщик мусора работал эффективнее:
// В начале скрипта, до session_start()
ini_set('session.gc_maxlifetime', $timeout);
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1); // Запускать GC при каждом запросе (не рекомендуется на продакшене без необходимости)
session_start();
Однако основной механизм — это именно ручная проверка времени. Не полагайтесь только на GC.
Важно: Не используйте session_regenerate_id() без необходимости, если не хотите сбрасывать таймер. Если используете, убедитесь, что обновляете last_activity после регенерации.
Альтернативный подход: использование куки с временем жизни и проверка на сервере
Можно комбинировать куки и серверную проверку. Идея: установить куку с временем жизни 30 минут, а на сервере проверять её наличие. Если кука истекла или удалена, сессия считается недействительной. Однако этот метод менее надёжен, так как пользователь может удалить куки вручную.
<?php
session_start();
// Устанавливаем куку на 30 минут (1800 секунд) при первом запросе
if (!isset($_COOKIE['session_timer'])) {
setcookie('session_timer', time(), time() + 1800, '/');
}
// При каждом запросе проверяем, есть ли кука
if (!isset($_COOKIE['session_timer'])) {
// Кука отсутствует или истекла — уничтожаем сессию
session_destroy();
header('Location: login.php');
exit;
} else {
// Обновляем куку (продлеваем на 30 минут)
setcookie('session_timer', time(), time() + 1800, '/');
}
?>
Недостатки: Куки могут быть отключены в браузере, и этот метод не защищает от подделки времени. Ручная проверка на сервере (как в первом ответе) — более надёжный и безопасный способ.
Используйте первый подход, если вам нужна гарантированная защита от неактивности.