Как отследить окончание сессии по времени в Laravel?

Есть необходимость отслеживать действия пользователей, в том числе вход и выход из системы. Отследить выход по нажатию на клавишу просто, а вот как его отследить, если сессия истекла по времени? Использую Laravel 7.7.1


Ответы (1 шт):

Автор решения: Total Pusher

Идея такая: отслеживать устаревшие сессии и записывать в журнал их данные (текущая дата, пользователь) - это то что вам нужно.

В механизме сессий PHP есть обработчик, который удаляет старые сессии - сборщик мусора. Он работает так: при старте сессии (зашел новый посетитель) PHP случайным образом (вероятность настраивается) запускает сборщик мусорных сессий. Если в качестве хранилища используется файловая система, то PHP просто ищет устаревшие файлы и удаляет их, это зашито в его коде и работает по-умолчанию. Вот исходный код, функция static zend_long php_session_gc

Но можно реализовать свой сборщик мусора, для этого нужно расширить класс SessionHandler и в нем реализовать метод SessionHandler::gc(), а затем установить обработчик сессий через session_set_save_handler().

А в Laravel даже сделали обертку в виде \SessionHandlerInterface::gc().

Вот что нужно сделать для отслеживания истекающих сессий.

  1. Сконфигурировать хранение сессий в базе данных

  2. Создать таблицу БД

  3. Написать свою реализацию сборщика мусора, отнаследовавшись от \Illuminate\Session\DatabaseSessionHandler и зарегистрировать его средствами Laravel

  4. Так как очистка мусора инициируется стартом новой сессии (заходом посетителя на сайт), а посетителей может и не быть, можно подтюнить:

Поэтому рекомендуется выполнять сборку мусора на рабочих системах периодически, например, использовать задачи 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);
}
→ Ссылка