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

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

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

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # app/config/config.yml
    services:
        # ...
    
        Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
            public:    false
            arguments:
                - 'mysql:dbname=mydatabase'
                - { db_username: myuser, db_password: mypassword }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <services>
            <service id="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler" public="false">
                <argument>mysql:dbname=mydatabase</argument>
                <argument type="collection">
                    <argument key="db_username">myuser</argument>
                    <argument key="db_password">mypassword</argument>
                </argument>
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // app/config/config.php
    use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
    
    $storageDefinition = $container->register(PdoSessionHandler::class)
        ->setArguments(array(
            'mysql:dbname=mydatabase',
            array('db_username' => 'myuser', 'db_password' => 'mypassword')
        ))
    ;
    

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

  • YAML
    1
    2
    3
    4
    5
    # app/config/config.yml
    framework:
        session:
            # ...
            handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
    
  • XML
    1
    2
    3
    4
    5
    <!-- app/config/config.xml -->
    <framework:config>
        <!-- ... -->
        <framework:session handler-id="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler" cookie-lifetime="3600" auto-start="true"/>
    </framework:config>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // app/config/config.php
    use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
    
    // ...
    $container->loadFromExtension('framework', array(
        // ...
        'session' => array(
            // ...
            'handler_id' => PdoSessionHandler::class,
        ),
    ));
    

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

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

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # app/config/config.yml
    services:
        # ...
    
        Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
            public:    false
            arguments:
                - 'mysql:dbname=mydatabase'
                - { db_table: sessions, db_username: myuser, db_password: mypassword }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!-- app/config/config.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler" public="false">
                <argument>mysql:dbname=mydatabase</argument>
                <argument type="collection">
                    <argument key="db_table">sessions</argument>
                    <argument key="db_username">myuser</argument>
                    <argument key="db_password">mypassword</argument>
                </argument>
            </service>
        </services>
    </container>
    
  • PHP
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    // app/config/config.php
    
    use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
    // ...
    
    $container->register(PdoSessionHandler::class)
        ->setArguments(array(
            'mysql:dbname=mydatabase',
            array('db_table' => 'sessions', 'db_username' => 'myuser', 'db_password' => 'mypassword')
        ))
    ;
    

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

db_table (по умолчанию sessions):
Имя таблицы сессии в вашей БД;
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).

Совместное использование информации о соединениях вашей БД

С заданной конфигурацией, установки соединения базы данных определеяются тольок для соединения хранилища сессии. Это нормально, когда вы испошльзуете отдельную БД для данных сессии.

Но если вы хотите хранить данные сесси в той же БД, что и все остальные данные вашего проекта, вы можете использовать установки соединений из файла parameters.yml путём обращения к параметрам, относящимся к БД, определённых там:

  • YAML
    1
    2
    3
    4
    5
    6
    7
    8
    services:
        # ...
    
        Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler:
            public:    false
            arguments:
                - 'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%'
                - { db_username: '%database_user%', db_password: '%database_password%' }
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd">
    
        <services>
            <service id="Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler" public="false">
                <argument>mysql:host=%database_host%;port=%database_port%;dbname=%database_name%</argument>
                <argument type="collection">
                    <argument key="db_username">%database_user%</argument>
                    <argument key="db_password">%database_password%</argument>
                </argument>
            </service>
        </services>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    // ...
    $container->register(PdoSessionHandler::class)
        ->setArguments(array(
            'mysql:host=%database_host%;port=%database_port%;dbname=%database_name%',
            array('db_username' => '%database_user%', 'db_password' => '%database_password%')
        ))
    ;
    

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

Перед тем, как сохранять сессии в БД, вы должны создать таблицу, которая будет хранить информацию. Следующий раздел содержит некоторые примеры выражений SQL, которые вы можете захотеть использовать для определённого движка БД.

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 в качестве движка БД, вы можете также активировать режим строгого SQL, чтобы получать уведомления, когда будет происходить такая ошибка.

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.