Pull to refresh

Codeigniter: делаем сессии наконец стабильными (прежде всего для авторизаций)

Reading time2 min
Views15K
Сессии в Codeigniter хороши всем. Правда, очень удобно сделаны, особенно когда вы храните сессии в БД (что я считаю единственно верным). Куки шифрованные, в куках ничего, кроме идентификатора нету. Они привязываются к user_agent и, опционально, к IP. Красиво, безопасно.

Но есть у них очень существенный недостаток: жизнь сессии считается от поля last_activity. Это значит, что если у вас стоит expire сессии в двое суток, то при обращении к сессии, у которой last_activity < time()-172800, она ликвидируется и начинется новая. Следственно, для того что бы пользователям не приходилось каждый раз логиниться на сайт, last_activity нужно поддерживать в акутальном состоянии.
Поле last_activity обновляется в двух случаях: когда вы записываете что-то новое в сессию, либо когда сессия обновляется (по-умолчанию каждые 5 минут, опять же, относительно last_activity; указывается в конфиге). И вот главная проблема в том, что при обновлении сессии меняется session_id и текущая сессия у пользователя сессия прерывается, стартует новая.

Откровенно говоря, подобное поведение сессий привело меня в состояние… удивления. В таких реалиях использование родных сессий в качестве инструмента поддержки авторизации кажется невозможным…

Проблема «животрепещущая», о ней часто вспоминают на форумах Codeigniter, но толкового решения там нигде я так и не увидел.

Но голь, как известно, на выдумки хитра, поэтому простое решение таки нашлось.

Первое, что нужно сделать, это в config/config.php указать периодичность обновления сессии равным времени ее expire'а:
================
$config['sess_time_to_update'] = $config['sess_expiration'];
================
Затем, включить хуки:
================
$config['enable_hooks'] = TRUE;
================

Затем, в config/hooks.php:
================
$hook['post_controller_constructor'] = array(
'class' => '',
'function' => 'sess_update',
'filename' => 'sess_update.php',
'filepath' => 'hooks'
);

================
(точку хука можно, в принципе, любую, главное, что бы он выполнялся при каждом открытии страницы)

И в hooks создаем sess_update.php:
================
<?php
function sess_update()
{
$CI =& get_instance();
if ($CI->session->userdata('last_activity')< time() - 300) {
$CI->session->set_userdata('last_activity', time());
}
}

================
Функция проста, как 5 копеек: получаем ссылку на суперобъект codeigniter'а, смотрим, не прошло ли 5 минут с момента последнего обновления сессии (что бы не штормить базу лишними запросами каждый раз) и, если прошло, вручную устанавливаем пол last_activity равным текущему времени.

По сути, получается тот же эффект, что указание 5 минут в $config['sess_time_to_update'], но при этом сама сессия остается невредимой, данные никуда не деваются и, ваш авторизированный пользователь, прийдя на сайт на следующий день, или через два (в зависимости от значения $config['sess_expiration']) останется авторизированным.
Tags:
Hubs:
Total votes 33: ↑24 and ↓9+15
Comments38

Articles