Avatar ·

Как установить время жизни PHP-сессии 30 минут и автоматически её завершать?

Всем привет! Я новичок в PHP и столкнулся с проблемой управления сессиями. Мне нужно, чтобы сессия пользователя на моём сайте автоматически истекала через 30 минут бездействия. Я читал документацию, но запутался в настройках. Вот что я пробовал: ```php // В начале каждой страницы session_start(); // Пытался установить время жизни через ini_set ini_set('session.gc_maxlifetime', 1800); ini_set('session.cookie_lifetime', 1800); ``` Но это не работает — сессия всё равно остаётся активной даже через час. Я проверяю время последнего действия пользователя так: ```php if (isset($_SESSION['LAST_ACTIVITY']) && (time() - $_SESSION['LAST_ACTIVITY'] > 1800)) { session_destroy(); session_unset(); header('Location: login.php'); exit; } $_SESSION['LAST_ACTIVITY'] = time(); ``` Но это приводит к тому, что пользователя выкидывает даже при активной работе, если он долго не обновлял страницу. Как правильно реализовать тайм-аут сессии именно через 30 минут неактивности? Желательно с безопасным хранением данных и возможностью продления сессии при активности пользователя. Заранее спасибо! <<>>

Правильная реализация тайм-аута сессии через 30 минут

Ваша проблема типична для начинающих. Дело в том, что настройки session.gc_maxlifetime и session.cookie_lifetime работают не так, как вы ожидаете. session.gc_maxlifetime задаёт максимальное время жизни файла сессии на сервере до того, как сборщик мусора (GC) его удалит. Но GC запускается не при каждом запросе, а с вероятностью 1/100 (по умолчанию). session.cookie_lifetime вообще отвечает за время жизни cookie с идентификатором сессии, а не за саму сессию.

Вот рабочий подход с проверкой времени последней активности:

<?php
session_start();

// Время жизни сессии в секундах (30 минут = 1800 секунд)
$session_lifetime = 1800;

// Проверяем, установлена ли метка времени последней активности
if (isset($_SESSION['LAST_ACTIVITY'])) {
    // Вычисляем разницу между текущим временем и временем последней активности
    $inactive_time = time() - $_SESSION['LAST_ACTIVITY'];
    
    // Если время бездействия превышает лимит
    if ($inactive_time > $session_lifetime) {
        // Уничтожаем сессию и все её данные
        session_unset();
        session_destroy();
        
        // Перенаправляем на страницу входа
        header('Location: login.php?timeout=1');
        exit;
    }
}

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

Ключевые моменты:

  • Проверка и обновление — код должен выполняться на каждой странице, где требуется авторизация. Обычно его выносят в отдельный файл (например, session_check.php) и подключают через require_once.
  • Порядок действий: сначала проверяем, не истекла ли сессия, затем обновляем метку. Если сделать наоборот, сессия никогда не истечёт.
  • Безопасность: после уничтожения сессии обязательно используйте session_unset() перед session_destroy(), чтобы очистить все переменные сессии.
  • Продление при активности: этот код автоматически продлевает сессию при каждом действии пользователя (загрузке страницы, AJAX-запросе и т.д.).

Дополнительные настройки для надёжности

Чтобы сборщик мусора не удалял сессию раньше времени, добавьте в начало скрипта:

// Увеличиваем время жизни сессии на сервере
ini_set('session.gc_maxlifetime', $session_lifetime);

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

// Запускаем сессию после всех настроек
session_start();

Обратите внимание: session_set_cookie_params() нужно вызывать до session_start(). Это гарантирует, что cookie с идентификатором сессии тоже будет жить 30 минут. Если пользователь закроет браузер раньше — cookie удалится, и сессия завершится.

Полный пример для файла session_check.php:

<?php
$session_lifetime = 1800; // 30 минут

ini_set('session.gc_maxlifetime', $session_lifetime);
session_set_cookie_params($session_lifetime);
session_start();

if (isset($_SESSION['LAST_ACTIVITY'])) {
    if (time() - $_SESSION['LAST_ACTIVITY'] > $session_lifetime) {
        session_unset();
        session_destroy();
        header('Location: login.php?timeout=1');
        exit;
    }
}
$_SESSION['LAST_ACTIVITY'] = time();
?>

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

<<>>

Альтернативный подход: использование базы данных для хранения сессий

Если ваш проект использует базу данных (например, MySQL), рекомендую хранить сессии в БД. Это даёт больше контроля и безопасности. Вот пример реализации:

// Включаем хранение сессий в БД
ini_set('session.save_handler', 'user');

// Функция для открытия сессии
function open_session($save_path, $session_name) {
    // Подключение к БД (упрощённо)
    global $db;
    return true;
}

// Функция для чтения данных сессии
function read_session($session_id) {
    global $db;
    $stmt = $db->prepare("SELECT data FROM sessions WHERE id = ? AND expiry > NOW()");
    $stmt->execute([$session_id]);
    $row = $stmt->fetch();
    return $row ? $row['data'] : '';
}

// Функция для записи данных сессии
function write_session($session_id, $data) {
    global $db;
    $expiry = date('Y-m-d H:i:s', time() + 1800); // +30 минут
    $stmt = $db->prepare("REPLACE INTO sessions (id, data, expiry) VALUES (?, ?, ?)");
    return $stmt->execute([$session_id, $data, $expiry]);
}

// Регистрируем обработчики
session_set_save_handler('open_session', 'close_session', 'read_session', 'write_session', 'destroy_session', 'gc_session');
session_start();

В таблице sessions должно быть поле expiry с типом DATETIME. Сессия автоматически истечёт, когда текущее время превысит значение в этом поле. Плюс такого подхода — вы можете легко реализовать "скользящее" время жизни, обновляя expiry при каждом запросе пользователя.

Для очистки устаревших сессий можно запускать cron-задачу: DELETE FROM sessions WHERE expiry < NOW(). Это надёжнее, чем полагаться на сборщик мусора PHP.