Ars Longa, Vita Brevis

Подход, позволяющий хранить PHP-сессии в базе данных вместо файлов

Начну сразу с причин, по которым я пишу эту статью. Я периодически просматриваю лог запросов, по которому люди попадают сюда, и вот один из запросов — хранить php сессию в mysql.

Итак, как же хранить PHP-сессии в базе данных?

На самом деле, в этом нет ничего сложного: в PHP есть одна полезная функция — session_set_save_handler — которая и выполняет всю грязную работу:

session_set_save_handler() sets the user-level session storage functions which are used for storing and retrieving data associated with a session. This is most useful when a storage method other than those supplied by PHP sessions is preferred. i.e. Storing the session data in a local database.

Эта функция принимает шесть аргументов типа сallback:

  • open — вызывается при открытии/создании сессии;
  • close — вызывается при закрытии сессии (например, чтобы приложение могло закрыть файл);
  • read — чтение сессии;
  • write — запись сессии;
  • destroy — уничтожение сессии (session_destroy);
  • gc — "сборка мусора"

Все функции (кроме read) должны возвращать true, если все прошло успешно и false в противном случае.

Для хранения сессии у нас есть такая таблица:

[-]
View Code MySQL
CREATE TABLE `session` (
    `id` CHARACTER(32) BINARY NOT NULL PRIMARY KEY, /* Session ID */
    `expires` INTEGER NOT NULL, /* Время истекания сессии */
    `session_data` TEXT NOT NULL, /* Данные, хранящиеся в сессии */

    KEY(`expires`)
)

Один маленький нюанс: если в MySQL делать таблицу сессий типа MEMORY (т.е. задать ей такой storage engine), то могут возникнуть проблемы с удалением записей при сборке мусора, ибо MEMORY storage engine не может использовать индексы для операций сравнения типа "больше"/"меньше".

Для абстракции от конкретного SQL-сервера, будем считать, что у нас имеется некий класс Persistent, обладающий способностями загружать/сохранять данные в базу данных.

Таким образом, реализация класса Session будет иметь следующий вид:

[-]
View Code PHP
<?php
    require_once('class.Persistent.php');

    class Session extends Persistent
    {
        /**
         * @var string
         */

        public $id;

        /**
         * @var int
         */

        public $expires;

        /**
         * @var string
         */

        public $session_data;

        /**
         * @var bool
         */

        public $m_new;

        function __contruct($data)
        {
            parent::__construct($data);
        }

        static function getTable()
        {
            return TABLE_SESSION; //константа, задающая имя таблицы сессий
        }
    }
?>

Пока все предельно просто. О переменной $m_new поговорим позже.

Теперь собственно реализация класса, управляющего се