Как отследить окончание сессии по времени в Laravel?
Есть необходимость отслеживать действия пользователей, в том числе вход и выход из системы. Отследить выход по нажатию на клавишу просто, а вот как его отследить, если сессия истекла по времени? Использую Laravel 7.7.1
Ответы (1 шт):
Идея такая: отслеживать устаревшие сессии и записывать в журнал их данные (текущая дата, пользователь) - это то что вам нужно.
В механизме сессий PHP есть обработчик, который удаляет старые сессии - сборщик мусора. Он работает так: при старте сессии (зашел новый посетитель) PHP случайным образом (вероятность настраивается) запускает сборщик мусорных сессий. Если в качестве хранилища используется файловая система, то PHP просто ищет устаревшие файлы и удаляет их, это зашито в его коде и работает по-умолчанию. Вот исходный код, функция static zend_long php_session_gc
Но можно реализовать свой сборщик мусора, для этого нужно расширить класс SessionHandler и в нем реализовать метод SessionHandler::gc(), а затем установить обработчик сессий через session_set_save_handler().
А в Laravel даже сделали обертку в виде \SessionHandlerInterface::gc().
Вот что нужно сделать для отслеживания истекающих сессий.
Написать свою реализацию сборщика мусора, отнаследовавшись от
\Illuminate\Session\DatabaseSessionHandlerи зарегистрировать его средствами LaravelТак как очистка мусора инициируется стартом новой сессии (заходом посетителя на сайт), а посетителей может и не быть, можно подтюнить:
Поэтому рекомендуется выполнять сборку мусора на рабочих системах периодически, например, использовать задачи cron в UNIX-подобных системах. При этом убедитесь, что отключили сборку мусора на основе вероятности, установив session.gc_probability в 0
https://www.php.net/manual/ru/function.session-gc.php
Своя реализация сборщика мусора
Все что нам нужно, это отнаследовать свой обработчик от \Illuminate\Session\DatabaseSessionHandler и переписать в нем метод gc.
Так сделано в родительском классе:
public function gc($lifetime)
{
$this->getQuery()->where('last_activity', '<=', $this->currentTime() - $lifetime)->delete();
}
Так нужно сделать в дочернем:
public function gc($lifetime)
{
/**
* тут пишем запрос, который из таблицы sessions берет user_id и другую
* информацию и записывает в журнал
*/
// вызываем родительский метод очистки мусора
parent::gc($lifetime);
}