Зберігання сесії у базі даних
Незважаючи на те, що стандартний спосіб зберігання даних сесії підходить для більшості завдань, з якими можуть зіткнутися php-розробники, іноді вам все ж таки доведеться шукати альтернативу. Найчастішими причинами для зберігання даних сесії у базі даних є:
Ваш сайт розбитий на кілька частин, які зберігаються на декількох серверах і щоб бути впевненим, що сесія працює правильно вам необхідно зберігати дані сесії в базі даних, спільної для всіх серверів.
Ваш сайт знаходиться на одному сервері з іншими сайтами і ви хочете уникнути проблем безпеки, пов'язаних з цим.
Ваш сайт має дуже великі запити до швидкості роботи і тому вам потрібний швидший спосіб зберігання даних сесії. Існує безліч методик з прискорення читання з бази даних, які можуть бути використані в даному випадку.
На щастя, PHP робить це завдання простим.
Зберігання даних сесії.
Перш ніж ви зможете зберігати дані сесії у базі даних, вам необхідно створити таблицю. Ось приклад для MySQL:
CREATE TABLE sessions ( id varchar(32) NOT NULL, access int(10) unsigned, data text, PRIMARY KEY (id) );
Це найпростіший приклад, ви можете змінити таблицю на власний розсуд, щоб зберігати, наприклад, час створення сесії або унікальний ідентифікатор для підвищення безпеки.
Після того, як ви створили таблицю, давайте подивимося, як її використовувати.
PHP має вбудовану функцію, яка дозволяє змінити механізм сесії, заданий за умовчанням. З її допомогою ви можете задавати свої функції для різних завдань механізму сесії. Ця стаття організована відповідно до списку функцій, які вам потрібно буде написати. Для кожної функції я покажу вам приклад(використовуючи MySQL) і все докладно поясню.
Функціяsession_set_save_handler()приймає шість параметрів, кожен з яких – це ім'я функції, яку вам доведеться написати. Ці функції відповідатимуть за такі завдання:
Відкриття місця зберігання даних сесії
Закриття місця зберігання сесії
Читання даних сесії
Запис даних сесії
Знищення всіх даних сесії
Видалення даних попередньої сесії
Для зручності, у цій статті ми приймемо такі імена для цих функцій:
session_set_save_handler ('_open', '_close', '_read', '_write', '_destroy', '_clean');
цей рядок повинен стояти до виклику session_start(), але самі функції ви можете оголосити будь-де.
Перевага даного способу в тому, що в коді ви можете продовжувати робити те ж саме, як і при стандартному механізмі зберігання даних сесії. Масив $_SESSION все той же і веде себе так само, php все генерує і передає ключ сесії. Все що вам необхідно зробити – це додати один рядок, вказаний вище.
Також дуже важливо зрозуміти, що роблять функції, на випадок непередбачених помилок.
Ці функції взаємопов'язані, вони використовуються для відкриття та закриття місця зберігання даних сесії відповідно. Якщо ви зберігаєте дані сесії у файловій системі, ці функції відкривають та закривають файли (швидше за все вам знадобиться глобальна змінна керування файлом, щоб інші функції могли її використовувати).
Оскільки ви використовуєте базу даних, _open() і _close() можуть бути настільки прості, як, наприклад:
function _open() < mysql_connect('127.0.0.1', 'myuser', 'mypass'); mysql_select_db('sessions'); > function _close() < mysql_close(); > ?>
Такий варіант має недолік: коли змінна керування базою даних не створена для функцій mysql_select_db() і mysql_query(), MySQL використовує останнє з'єднання, тобто якщо десь у коді сайту ви використовуєте mysql_select_db щоб вибрати іншу базу даних, запис у сесію може не статися , тому що останнє з'єднання буде з іншою базою даних. Таку помилку буде дуже складно відстежити, незважаючи на це, вона зустрічається досить часто.
Уникнути такої помилки можна двома способами: ви можете використовувати окреме з'єднання для запису даних сесії або ви можете звичку використовувати mysql_select_db() перед кожною функцією, якій необхідна певна база даних, це включає себе як механізм зберігання сесії, так і код сайту. Це все, звичайно, за умови, що ви використовуєте більше однієї бази даних у своєму коді.
У цій статті я використовуватиму перший спосіб – використовувати окреме з'єднання для механізму сесії. Назвемо цю змінну $_sess_db, і тоді код наших функцій буде виглядати так:
function _open() < global $_sess_db; $_sess_db = mysql_connect('127.0.0.1', 'myuser', 'mypass'); mysql_select_db('sessions', $_sess_db); > function _close() < global $_sess_db; mysql_close($_sess_db); > ?>
Я використовую знак підкреслення на початку імені змінної як вказівку, що ця змінна не повинна змінюватися в наступному коді.
Я хочу внести ще одну зміну. Більшість вбудованих php функцій повертають TRUE, якщо помилок немає і FALSE, якщо при виконанні виникла помилка. Ми можемо змусити наші функції робити те саме:
function _open() < global $_sess_db; if ($_sess_db =mysql_connect('127.0.0.1', 'myuser', 'mypass')) < return mysql_select_db('sessions', $_sess_db); > return FALSE; > function _close() < global $_sess_db; return mysql_close($_sess_db); > ?>
Перейдемо до наступної функції.
Ця функція викликається, коли необхідно записати дані в сесію. Це відбувається відразу після виклику _open(), який, у свою чергу, викликається за допомогою session_start().
PHP передає в _read() ідентифікат сесії:
function _read($id) < global $_sess_db; $ > $sql = “SELECT data FROM sessions WHERE”; if ($result = mysql_query($sql, $_sess_db)) < if (mysql_num_rows($result)) < $record = mysql_fetch_assoc($result); return $record['data']; > > return ''; > ?>
Обробник, який використовує PHP для серіалізації даних, задається session.serialize_handler параметром конфігурації php. За умовчанням він має значення PHP.
Функція _write() викликається коли необхідно записати дані в сесію, зазвичай, у самому кінці скрипта.
PHP передає ідентифікатор сесії та дані сесії. Ви можете не хвилюватися про формат даних, оскільки php серіалізує ці дані, вони являють собою рядок. Незважаючи на це вам необхідно переконатися, що рядок не містить небезпечних елементів, перш ніж використовувати його в запиті.
function _write($id, $data) < global $_sess_db; $acess = time(); $ > $access = mysql_real_escape_string($access); $data = mysql_real_escape_string($data); $sql = “REPLACE INTO sessions VALUES ('$id','$access','$data')”; return mysql_query($sql, $_sess_db); > ?> Я використовував REPLACE, тому що так ми робимо теж, що і використовуючи INSERT,але у випадках, коли переданий індентифікатор сесії вже існує, REPLACE видалить старий запис перш ніж записувати новий. Таким чином відпадає необхідність перевірки на наявність у таблиці запису з переданим ідентифікатором сесії. Необхідно врахувати, що REPLACE працює в MySQL, але в інших типах баз даних такої команди може не бути._destroy()Функція _destroy() викликається, коли PHP необхідно знищити всі дані поточної сесії. Найочевидніший приклад, коли викликається session_destroy().
PHP передає у функцію ідентифікатор сесії. function _destroy($id)
global $_sess_db; $ > $sql = “DELETE FROM sessions WHERE”; return $result = mysql_query($sql, $_sess_db); > ?> Функція _destroy() стирає лише запис у базі даних, не торкаючись масив $_SESSION._clean()
Функція _clean() викликається періодично видалення старих записів у таблиці сесій. Точніше, як часто ця функція викликається двома параметрами конфігурації php: session.gc_probability і session.gc_divisor. Їх значення за замовчуванням 1 і 100 відповідно, що означає, що ймовірність виклику функції _clean() за сесію дорівнює 1 поділити на 1000 = 0.1%.
Так як функція _write() записує в таблицю для кожного запису точний час останнього доступу в колонку access, це може бути використано, щоб визначити які записи видаляти. PHP передає максимальну кількість секунд після яких сесія вважається простроченою:
function _clean($max) < global $_sess_db; $old = time() - $max; $old = mysql_real_escape_string($old); $sql = “DELETE FROM sessions WHERE access return $result = mysql_query($sql, $_sess_db); > ?>
Кількість секунд, які PHP передає вцю функцію – це значення параметра session.gc_maxlifetime із конфігурації PHP. У разі потреби можна змінити це значення.
Тепер у вас є всі необхідні інструменти, щоб змінювати механізм зберігання даних сесії. Також, я сподіваюся, ви отримали краще розуміння призначення цих шести функцій і готові вирішити будь-які проблеми, які можуть виникнути в процесі.
Автор Chris Shiflett Переклад Олександр Білковець