PHP сессия в базе данных
версия для печатиХочу организовать хранение сессий на стороне сервера в базе данных. Зачем? "Just for fun!" ©. Вы можете найти для себя другие причины :)
Оказалось, свой велосипед не нужен, в PHP уже все есть. Нужно реализовать интерфейс php::SessionHandlerInterface и где-то назначить сессионным обработчиком объект моего класса. Для этого вызываем функцию php::session_set_save_handler(). Проще всего сделать вызов в bootstrap.php или index.php приложения.
Очень полезно было почитать, как работает сессия PHP на самом деле (en). Оказалось, что при закрытии сессии всегда вызвается SessionHandlerInterface::write(), не зависимо от того, изменились ли данные в сессионном объекте. Я это учел, и в моей реализации выполняется проверка, прежде чем выполнять сохранение в БД.
Есть еще один инструмент в PHP - SessionHandler class. Его можно использовать для расширения текущей логики сессий. Т.е. когда я не хочу принципиально поменять хранилище, но допустим, хочу выполнять дополнительные действия при чтении/записи в сессии. Тогда наследую этот класс и реализую в наследнике нужные мне методы. В отличие от реализации интерфейса SessionHandlerInterface тут мне не нужно полностью продумывать механизм работы сессий, только свои дополнения в нем.
А вот для чего все эти инструменты не подходят, так это для добавления новых методов в механизм работы сессий. Клиент-то работает с $_SESSION, а не с каким-то классом, см. Session Basic usage. Все вызовы нужных методов скрыты от клиента, он просто выполняет чтение/запись в переменную-массив. Даже если клиент задействует напрямую какие-то методы, типа php::session_start(), к классовым методам нет такого неявного доступа.
Архив с исходниками моей реализации. Класс модели, которую я там использовал, опирается на движок Kira в его текущей dev-версии. Вы можете рассматривать эту модель, как пвсевдокод, там ничего сложного.
Дополнительные заметки
Данные в сессии сериализованы, но это не тот же самый результат, что при php:serialize(). Вообще формат зависит от настройки session.serialize-handler.
В сравнении, обычная сериализация и то, что по дефолту в сессии:
$_SESSION['test'] = 'summer';
// test|s:6:"summer";
echo serialize(['test' => 'summer']);
// "a:1:{s:4:"test";s:6:"summer";}"
Это значит, что не нужно пытаться вручную менять ланшафты изменять значение в сессионных данных. Если настройка session.serialize-handler поменяется, формат будет другой.
У меня был баг в реализации, возникало исключение в вызове SessionHandlerInterface::write() и оно почему-то шло мимо кастомного перехватчика и отрисовывалось, как есть в PHP, черно-оранжевая таблица. А это значит, никакого логирования или уведомления админу или любой другой кастомной реакции на исключение.
Почему так: конкретно в моей ситуации важно было, когда происходит запись в сессию. Она вызывалась при закрытии сессии, которая выполняется уже после php::shutdown(). Т.е. на момент закрытия сессии мои обработчики уже отключены, как и вообще все приложение. А я, наивный, полагал, что php::shutdown() действительно последняя остановка :)
[1oo%, EoF]
Понравилась статья? Расскажите о ней друзьям: