Как использовать PdoSessionHandler для хранения сессий в DB

Дата оновлення перекладу 2023-07-05

Как использовать PdoSessionHandler для хранения сессий в DB

Хранилище сессий Symfony по умолчанию хранит информацию о сессиях в файлах. Большинство средних и крупных веб-сайтов используют DB для хранения значений сессий, вместо файлов, поскольку базы данных легче использовать и масштабировать в среде множества веб-серверов.

Symfony имеет встроенное решение для хранения сессий в базах данных, под названием PdoSessionHandler. Чтобы использовать его, зарегистрируйте новый сервис-обработчик:

1
2
3
4
5
6
7
8
9
10
11
12
# config/services.yaml
services:
    # ...

    Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
        arguments:
            - 'mysql:dbname=mydatabase'
            - { db_username: myuser, db_password: mypassword }

            # Если вы используете Doctrine и хотите использовать это соединение повторно, тогда:
            # прокомментируйте 2 строки выше и уберите комментарий из строки ниже
            # - !service { class: PDO, factory: 'database_connection:getWrappedConnection' }

Далее, скажите Symfony использовать ваш сервис в качестве обработчика сессии:

1
2
3
4
5
# config/packages/framework.yaml
framework:
    session:
        # ...
        handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler

Конфигурация имён таблицы и столбцов

Для этого необходима таблица sessions с некоторым количеством различных столбцов. Имя таблицы, а также все имена столбцов, могут быть сконфигурированы путем передачи второго массива аргументов в PdoSessionHandler:

1
2
3
4
5
6
7
8
# config/services.yaml
services:
    # ...

    Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
        arguments:
            - 'mysql:dbname=mydatabase'
            - { db_table: sessions, db_username: myuser, db_password: mypassword }

Вот параметры, которые вы можете сконфигурировать:

db_table (по умолчанию sessions):
Имя таблицы сессии в вашей DB;
db_id_col (по умолчанию sess_id):
Имя столбца id в вашей таблице сессии (VARCHAR(128));
db_data_col (по умолчанию sess_data):
Имя столбца значения в вашей таблице сессии (BLOB);
db_time_col (по умолчанию sess_time):
Имя столбца времени в вашей таблице сессии (INTEGER);
db_lifetime_col (по умолчанию sess_lifetime):
Имя столбца жизненного цикла в вашей таблице сессии (INTEGER).

Подготовка DB для хранения сессий

Перед тем, как сохранять сессии в DB, вы должны создать таблицу, которая будет хранить информацию. Обработчик сессий предоставляет метод под названием createTable() для установки этой таблицы за вас, в соответствии с используемым движком DB:

1
2
3
4
5
try {
    $sessionHandlerService->createTable();
} catch (\PDOException $e) {
    // таблица не могла быть создана по какой-то причине
}

Если вы предпочитаете устанавливать таблицу самостоятельно, то вот некоторые примеры утверждений SQL, которые вы можете использовать в соответствии с вашим конкретным движком DB.

Отличным способом запустить это в производство будет сгенерировать пустую миграцию, а затем добавить внутрь этот SQL:

1
$ php bin/console doctrine:migrations:generate

Найдите правильный SQL ниже и поместите его внутри этого файла. Далее, выполните его из:

1
$ php bin/console doctrine:migrations:migrate

MySQL

1
2
3
4
5
6
CREATE TABLE `sessions` (
    `sess_id` VARCHAR(128) NOT NULL PRIMARY KEY,
    `sess_data` BLOB NOT NULL,
    `sess_time` INTEGER UNSIGNED NOT NULL,
    `sess_lifetime` MEDIUMINT NOT NULL
) COLLATE utf8_bin, ENGINE = InnoDB;

Note

Тип столбца BLOB может хранить максимум 64 килобита. Если данные, хранящиеся в в сессии пользователя, превысят это значение, может быть вызвано исключение, или сессия будет тихо восстановлена. Рассмотрите использование MEDIUMBLOB, если вам нужно больше места.

PostgreSQL

1
2
3
4
5
6
CREATE TABLE sessions (
    sess_id VARCHAR(128) NOT NULL PRIMARY KEY,
    sess_data BYTEA NOT NULL,
    sess_time INTEGER NOT NULL,
    sess_lifetime INTEGER NOT NULL
);

Сервер Microsoft SQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE [dbo].[sessions](
    [sess_id] [nvarchar](255) NOT NULL,
    [sess_data] [ntext] NOT NULL,
    [sess_time] [int] NOT NULL,
    [sess_lifetime] [int] NOT NULL,
    PRIMARY KEY CLUSTERED(
        [sess_id] ASC
    ) WITH (
        PAD_INDEX  = OFF,
        STATISTICS_NORECOMPUTE  = OFF,
        IGNORE_DUP_KEY = OFF,
        ALLOW_ROW_LOCKS  = ON,
        ALLOW_PAGE_LOCKS  = ON
    ) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

Caution

Если данные сессии не помещаются в столбцы данных, они могут быть усечены движком базы данных. Чтобы усугубить ситуацию, когда данные сессии искажаются, PHP начинает игнорировать данные, не предупреждая об этом.

Если приложение хранит большие объемы данных сессии, эта проблема может быть решена путем увеличения размера столбца (используйте BLOB или даже MEDIUMBLOB). В случае использования MySQL в качестве движка DB, вы можете также активировать режим строгого SQL, чтобы получать уведомления, когда будет происходить такая ошибка.