Хранение сеансов в MySQL: менеджер сеансов PHP

Задача
Вам требуется хранилище сеансов для сценариев на PHP.

Решение
PHP 4 поддерживает управление сеансами. По умолчанию он использует для хранения временные файлы, но вы можете задать и хранение в MySQL.

Обсуждение
В PHP 4 есть собственный менеджер сеансов. В этом разделе показано, как его использовать и как расширить его возможности, реализовав модуль хранения данных сеанса в MySQL. Если PHP сконфигурирован так, что оба параметра track_vars и register_globals установлены, то переменные сеанса будут доступны в сценарии как одноименные глобальные переменные. (Пара-метр track_vars автоматически включен в версии PHP 4.0.3 и выше; в более ранних версиях необходимо включить его явно.) Если параметр register_glo-bals отключен, вам придется обращаться к переменным сеанса как к элемен-там глобального массива $HTTP_SESSION_VARS или суперглобального массива
$_SESSION. Это не так удобно, как просто положиться на register_globals, но зато более надежно. (В рецепте 18.5 рассказано о глобальном и суперглобальном массивах PHP и о соображениях безопасности в связи с register_globals.)

Интерфейс управления сеансами PHP 4
Управление сеансами в PHP обеспечивается небольшим набором функций, описанных в руководстве по PHP.


Перечислим те из них, которые имеют наибольший шанс пригодиться вам в вашей повседневной работе:

session_start ()
Открывает сеанс и извлекает переменные, ранее сохраненные в нем, делая их доступными в глобальном пространстве имен сценария. Напр-мер, переменная сеанса x становится доступна как $SESSION["x"] или $HTTP_SESSION_VARS["x"]. Если параметр register_globals включен, x доступна и как глобальная переменная $x.

session_register (var_name)
Регистрирует переменную в сеансе, устанавливая соответствие между записью сеанса и переменной вашего сценария. Например, зарегистрируем $count:

session_register ("count");

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

session_register ($count); # неверно
session_register (&$count); # неверно

Можно одновременно зарегистрировать несколько переменных, передав вместо одного имени массив, содержащий несколько имен:

session_register (array ("count", "timestamp"));

Регистрация переменной неявно начинает сеанс, то есть если сценарий вызывает session_register(), то ему не нужно предварительно вызывать session_start().


Однако session_register() имеет силу, только если включен параметр register_globals. Чтобы не зависеть от register_globals, сле-дует явно вызывать session_start() и получать переменные сеанса из мас-сива $_SESSION или $HTTP_SESSION_VARS.

session_unregister (var_name)
Отменяет регистрацию переменной, так что она не сохраняется в записи сеанса.

session_write_close ()
Записывает данные сеанса и закрывает его. Обычно эта функция не вызывается, так как PHP автоматически сохраняет открытый сеанс при завершении сценария. Явное сохранение и закрытие сеанса может понадобиться, если вы хотите изменить переменные сеанса так, чтобы изменения не отразились в данных сеанса. В этом случае вызовите данную функцию
для закрытия сеанса перед выполнением изменений.

session_destroy ()
Удаляет сеанс и все связанные с ним данные.

session_name ($name)
Менеджер сеансов PHP узнает, какой сеанс использовать, по идентификатору сеанса. Он ищет идентификатор в глобальной переменной $PHPSESSID; в переменной PHPSESSID cookies, методах GET и POST; или в параметре URL в форме PHPSESSID=значение.


(Если ни в одном из этих мест идентификатор не обнаружен, менеджер сеансов генерирует новый идентификатор и начинает новый сеанс.) Имя идентификатора по умолчанию – PHPSESSID, но вы можете изменить его. Для выполнения глобального изменения (в масштабе сайта) отредактируйте директиву конфигурации session.name в php.ini.

Если же вы хотите внести изменения только для отдельного сценария, вызовите перед началом сеанса session_name($name), где $name указывает имя используемого сеанса. Для определения имени идентификатора те-кущего сеанса вызовите session_name() без аргумента.

Рассмотрим пример простейшего применения сеанса – вывод счетчика запросов, полученных к данному моменту в рамках сеанса:

session_start ();
session_register ("count");
if (!isset ($count))
$count = 0;
++$count;
printf ("This session has been active for %d requests.", $count);

Функция session_start() открывает сеанс и извлекает его содержимое в глобальное пространство имен сценария. (Для первого запроса это не делается, так как сеанс пуст.) Функция session_register() регистрирует переменную сеанса count для изменения соответствующей переменной PHP $count с от-слеживанием в данных сеанса.


При первом запросе в сеансе нет такой переменной, что выявляется проверкой isset(), инициализирующей счетчик.

(При последующих запросах регистрация count будет приводить к тому, что $count получит значение, присвоенное в предыдущем запросе.) Затем значение счетчика увеличивается и выводится. При завершении сценария PHP неявно вызывает функцию session_write_close(), которая автоматически сохраняет новое значение счетчика в сеансе.

В примере использована функция session_register(), то есть считается, что параметр register_globals включен. Далее мы поговорим о том, как обойти это ограничение.

Применение пользовательского модуля хранения
Только что описанный интерфейс управления сеансами PHP не ссылается ни на какое хранилище данных. То есть в описании ничего не говорится о том, как же на самом деле сохраняется информация сеанса. По умолчанию PHP хранит данные сеанса во временных файлах, но интерфейс сеанса является расширяемым, так что можно определить другие модули хранения.

Для того чтобы подменить метод хранения по умолчанию и задать хранение данных в MySQL, необходимо выполнить следующие операции:

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


Это делается один раз, перед созданием любых сценариев, использующих новый модуль.

• Сообщить PHP о том, что вы предоставляете пользовательский менеджер хранения. Можно сделать это глобально в php.ini (один раз) или в отдельных сценариях (тогда придется выражать свое намерение в каждом сценарии).

• Зарегистрировать функции модуля хранения в каждом сценарии, который планирует использовать модуль.

Создание таблицы сеанса
Любому модулю хранения в MySQL необходима таблица базы данных, в которой будет храниться информация о сеансе. Создадим таблицу php_session с такими столбцами:

CREATE TABLE php_session
(id CHAR(32) NOT NULL,
data BLOB,
t TIMESTAMP NOT NULL,
PRIMARY KEY (id)
);

По своей структуре таблица очень похожа на таблицу sessions, используемую модулем Perl Apache::Session. Столбец id хранит идентификаторы сеансов – уникальные 32-символьные строки (они подозрительно напоминают идентификаторы Apache:Session, что неудивительно, поскольку PHP использует значения MD5, как и модуль Perl). Столбец data хранит информацию о сеансе. PHP сериализует данные сеанса в строку перед сохранением, так что в таблице php_session нужен только большой общий строковый столбец для получения результирующего сериализованного значения. Столбец t от-носится к типу TIMESTAMP и автоматически обновляется MySQL при каждом обновлении записи сеанса. Этот столбец не обязателен, но полезен для реализации «сбора мусора» («garbage collection») на основе времени последне-го обновления каждого сеанса.

Для обработки содержимого таблицы php_session в том виде, в котором мы ее создали, достаточно небольшого набора запросов:

• Для извлечения данных сеанса используйте простой запрос по идентифи-катору сеанса:
SELECT data FROM php_session WHERE id = 'идентификатор_сеанса';
• Для записи данных сеанса выполните REPLACE – будет обновлена существующая запись или создана новая, если запись не существовала ранее:

REPLACE INTO php_session (id,data) VALUES('идентификатор_сеанса','данные_сеанса');

REPLACE обновляет и временную метку записи при ее изменении или создании, что важно для сбора мусора.

Некоторые менеджеры хранения используют INSERT с переходом к UPDATE в случае неудачи INSERT из-за существования записи с указанным идентификатором сеанса (или UPDATE с переходом к INSERT при неудаче UPDATE из-за того, что запись с таким идентификатором не существует). В MySQL нет необходимости в двух запросах, REPLACE выполняет поставленную за-дачу в одном запросе.

• Для уничтожения сеанса удалите соответствующую запись:

DELETE FROM php_session WHERE id = 'идентификатор_сеанса';

• Сбор мусора выполняется посредством удаления старых записей. Следующий запрос удаляет записи, значение временной метки которых превышает время_жизни_сеанса в секундах:

DELETE FROM php_session
WHERE t < DATE_SUB(NOW(),INTERVAL время_жизни_сеанса SECOND);

Эти запросы являются основой функций, образующих наш модуль хранения в MySQL. Главное, что должен делать этот модуль, – открывать и закрывать соединения с MySQL и выдавать соответствующие запросы в нужное время. Создание функций модуля хранения
Интерфейс пользовательского модуля хранения данных сеансов реализован как набор функций обработчика, которые вы регистрируете вместе с менеджером сеансов PHP, вызывая session_set_save_handler() и указывая в качест-ве аргументов имена функций обработчика в строковом формате:

session_set_save_handler (
"mysql_sess_open", # функция открытия сеанса
"mysql_sess_close", # функция закрытия сеанса
"mysql_sess_read", # функция чтения данных сеанса
"mysql_sess_write", # функция записи данных сеанса
"mysql_sess_destroy", # функция уничтожения сеанса
"mysql_sess_gc" # функция сбора мусора
);

Функции обработчика можно называть как угодно, их именами не обязательно должны быть mysql_sess_open(), mysql_sess_close() и т. п. Но в отличие от имен, сами функции должны отвечать указанным требованиям:

mysql_sess_open ($save_path, $sess_name)

Выполняет все действия, необходимые для начала сеанса. $save_path – это путь к каталогу хранения сеансов, используется только при сохранении вфайлах. $sess_name указывает имя идентификатора сеанса (например, PHPSESSID). Для менеджера хранения в MySQL можно игнорировать оба аргумента. Функция должна возвращать TRUE или FALSE соответственно при успешном или неуспешном открытии сеанса.

mysql_sess_close ()

Закрывает сеанс, возвращая TRUE в случае успеха, FALSE – при неудаче.

mysql_sess_read ($sess_id)

Извлекает данные, связанные с идентификатором сеанса, и возвращает их в виде строки. Если такой сеанс не существует, функция должна возвращать пустую строку. В случае ошибки функция должна возвращать FALSE.

mysql_sess_write ($sess_id, $sess_data)

Сохраняет данные, связанные с идентификатором сеанса, возвращая TRUE в случае успеха, FALSE – при неудаче. PHP сам занимается сериализацией и десериализацией содержимого сеанса, поэтому функции чтения и записи имеют дело только с сериализованными строками.

mysql_sess_destroy ($sess_id)

Уничтожает сеанс и все связанные с ним данные, возвращая TRUE в случае успеха, FALSE – при неудаче. При хранении данных сеанса в MySQL уничтожение сеанса выражается в удалении записи, соответствующей идентификатору сеанса, из таблицы php_session.

mysql_sess_gc ($gc_maxlife)

Выполняет сбор мусора для удаления старых сеансов. Эта функция вызывается с определенной вероятностью. Когда PHP получает запрос на страницу, использующую сеансы, он вызывает утилиту сбора мусора с вероятностью, указанной директивой конфигурации session.gc_probability в файле php.ini. Например, если вероятность равна 1 (то есть 1%), PHP вы-зывает сборщика мусора приблизительно один раз на сто запросов. Если значение вероятности равно 100, сборщик вызывается для каждого запроса, что может привести к нежелательно большому увеличению нагрузки.

Аргумент $gc_maxlife – это максимальное время жизни сеанса в секундах. Более старые сеансы являются кандидатами на удаление. Функция должна возвращать TRUE в случае успеха, FALSE – при неудаче.

Функции обработчика регистрируются при помощи вызова session_set_sa-ve_handler(), выполняемого совместно с уведомлением PHP о том, что вы бу-дете применять пользовательский модуль хранения. Метод хранения данных сеансов по умолчанию определяется конфигурационной директивой session.save_handler. Можно изменить метод глобально, отредактировав инициализационный файл php.ini, или только для отдельного сценария:

• Для глобального изменения метода хранения отредактируйте файл php.ini. Установка директивы по умолчанию задает использование файлового хранилища для сеансов:
session.save_handler = files;

Измените директиву, указав, что сеансы будут обрабатываться пользовательским механизмом:

session.save_handler = user;

Если вы используете PHP как модуль Apache, то после редактирования php.ini потребуется перезапустить Apache, чтобы изменения вступили в силу.

Проблема глобального изменения – оно подразумевает, что каждый сценарий PHP, использующий сеансы, предоставит собственные функции работы с хранилищем. Возможны неожиданные побочные эффекты для других создателей сценариев, не знающих об изменении. Например, другие разработчики, использующие веб-сервер, могут предпочитать хранить данные сеансов в файловом хранилище.

• Альтернативой глобальным изменениям является задание для отдельно-го сценария собственного метода хранения посредством вызова ini_set():

ini_set ("session.save_handler", "user");

В отличие от изменения глобальной конфигурации вызов функции ini_set() не приводит к побочным эффектам. Созданный нами менеджер хранения использует ini_set(), так что хранение сеансов в базе данных будет производиться только для тех сценариев, которые это запросят.

Для упрощения доступа к альтернативному модулю хранения данных сеансов создадим библиотечный файл Cookbook_Session.php. Тогда единственное, что нужно будет сделать сценарию для использования библиотечного файла, – включить его в себя до начала сеанса. Файл будет приблизительно таким:

include_once "Cookbook.php";
# Определяем функции обработчика.
function mysql_sess_open ($save_path, $sess_name) ...
function mysql_sess_close () ...
function mysql_sess_read ($sess_id) ...
function mysql_sess_write ($sess_id, $sess_data) ...
function mysql_sess_destroy ($sess_id) ...
function mysql_sess_gc ($gc_maxlife) ...
# Инициализируем идентификатор соединения, выбираем пользовательский
# обработчик сеансов и регистрируем его функции.
$mysql_sess_conn_id = FALSE;
ini_set ("session.save_handler", "user");
session_set_save_handler (
"mysql_sess_open",
"mysql_sess_close",
"mysql_sess_read",
"mysql_sess_write",
"mysql_sess_destroy",
"mysql_sess_gc"
);
?>

Библиотечный файл включает в себя Cookbook.php, поэтому для установки соединения с базой данных cookbook он может обращаться к функции соеди-нения. Затем он определяет функции обработчика (поговорим о них подробнее чуть позже). Наконец, он инициализирует идентификатор соединения, сообщает PHP о том, что следует подготовиться к использованию пользова-тельского механизма хранения сеансов, и регистрирует функции обработчи-ка. Тогда сценарий PHP, который хочет хранить данные сеансов в MySQL, выполняет все необходимые настройки, просто присоединяя файл Cookbo-ok_Session.php:

include_once "Cookbook_Session.php";

Интерфейс, предоставляемый библиотечным файлом Cookbook_Session.php, определяет глобальную переменную идентификатора соединения с базой данных ($mysql_sess_conn_id), набор функций обработчика с именами
mysql_sess_open(), mysql_sess_close() и т. д. Сценарии, использующие библио-теку, не должны применять эти глобальные имена в других целях.

Теперь давайте посмотрим, как реализована каждая функция обработчика. Открытие сеанса. PHP передает этой функции два аргумента: путь сохра-нения и имя сеанса. Путь сохранения нужен файловым хранилищам, а имя сеанса нам знать необязательно, так что для нас оба аргумента не имеют значения и могут быть проигнорированы. Поэтому функция долж-на только открывать соединение с MySQL:

function mysql_sess_open ($save_path, $sess_name)
{
global $mysql_sess_conn_id;
# открыть соединение с MySQL, если еще не установлено
$mysql_sess_conn_id or $mysql_sess_conn_id = cookbook_connect ();
return (TRUE);
}
Закрытие сеанса. Обработчик закрытия проверяет, открыто ли соединение
с MySQL, и закрывает его, если открыто:
function mysql_sess_close ()
{
global $mysql_sess_conn_id;
if ($mysql_sess_conn_id) # закрыть соединение, если оно открыто
{
mysql_close ($mysql_sess_conn_id);
$mysql_sess_conn_id = FALSE;
}
return (TRUE);
}

Чтение данных сеанса. Функция mysql_sess_read() возвращает запись сеанса, найденную по ее идентификатору. Если запись не существует, возвра-щается пустая строка:

function mysql_sess_read ($sess_id)
{
global $mysql_sess_conn_id;
$sess_id = addslashes ($sess_id);
$query = "SELECT data FROM php_session WHERE id = '$sess_id'";
if ($res_id = mysql_query ($query, $mysql_sess_conn_id))
{
list ($data) = mysql_fetch_row ($res_id);
mysql_free_result ($res_id);
if (isset ($data))
return ($data);
}
return ("");
}

Запись данных сеанса. Функция mysql_sess_write() обновляет запись сеанса (или создает ее, если запись ранее не существовала):

function mysql_sess_write ($sess_id, $sess_data)
{
global $mysql_sess_conn_id;
$sess_id = addslashes ($sess_id);
$sess_data = addslashes ($sess_data);
$query = "REPLACE php_session (id, data) VALUES('$sess_id','$sess_data')";
return (mysql_query ($query, $mysql_sess_conn_id));
}

Уничтожение сеанса. Когда сеанс больше не нужен, функция mysql_sess_de-stroy() удаляет соответствующую запись:

function mysql_sess_destroy ($sess_id)
{
global $mysql_sess_conn_id;
$sess_id = addslashes ($sess_id);
$query = "DELETE FROM php_session WHERE id = '$sess_id'";
return (mysql_query ($query, $mysql_sess_conn_id));
}

Сбор мусора. Столбец t типа TIMESTAMP для каждой записи сеанса указывает, когда сеанс обновлялся в последний раз. Функция mysql_sess_gc() исполь-зует это значение при сборе мусора. Аргумент $sess_maxlife показывает, насколько старыми могут быть записи (в секундах). Более ранние записи считаются устаревшими и являются кандидатами на удаление. Удаляют-ся записи сеансов, временная метка которых отличается от текущей бо-лее чем на разрешенную величину срока жизни:

function mysql_sess_gc ($sess_maxlife)
{
global $mysql_sess_conn_id;
$query = sprintf ("DELETE FROM php_session
WHERE t < DATE_SUB(NOW(),INTERVAL %d SECOND)",
$sess_maxlife);
mysql_query ($query, $mysql_sess_conn_id);
return (TRUE); # игнорировать ошибки
}

Использование модуля хранения
Установите файл Cookbook_Session.php в общий библиотечный каталог, до-ступный вашим сценариям. (Я помещаю библиотечные файлы PHP в ката-лог /usr/local/apache/lib/php.) Для опробования модуля поместите предла-гаемый ниже сценарий sess_track.php в дерево документов и вызовите его несколько раз, чтобы посмотреть, как изменяется информация (точнее, что-бы увидеть, меняется ли она; как вы вскоре узнаете, в определенных случаях сценарий не будет работать):

# sess_track.php - вывод количества запросов в сеансе и временных меток
# (считаем, что register_globals включен)
include_once "Cookbook_Session.php";
include_once "Cookbook_Webutils.php"; # необходимо для make_unordered_list()
$title = "PHP Session Tracker";
# Открыть сеанс и зарегистрировать переменные сеанса.
session_start ();
session_register ("count");session_register ("timestamp");
# Если сеанс новый, то инициализировать переменные.
if (!isset ($count))
$count = 0;
if (!isset ($timestamp))
$timestamp = array ();
# Увеличить счетчик, добавить текущую временную метку в массив.
++$count;
$timestamp[] = date ("Y-m-d H:i:s T");
if ($count >= 10) # очистить переменные сеанса после 10 вызовов
{
session_unregister ("count");
session_unregister ("timestamp");
}
# Сформировать страницу вывода.
?>


<?php print ($title); ?>

printf ("

This session has been active for %d requests.

\n", $count);
print ("

The requests occurred at these times:

\n");
print make_unordered_list ($timestamp);
?>



Сценарий присоединяет библиотечный файл Cookbook_Session.php для рабо-ты с модулем хранения в MySQL, затем стандартным образом использует интерфейс менеджера сеансов PHP. Сначала он открывает сеанс, регистрирует переменные сеанса и инициализирует их для нового сеанса. Скалярная пе-ременная $count устанавливается в ноль, а не скалярная переменная $times-tamp – в пустой массив. Затем сценарий увеличивает счетчик, добавляет текущую временную метку в конец массива и формирует страницу вывода, отображающую счетчик и время обращения.

Если выполнено предельно допустимое количество вызовов – 10, то сцена-рий отменяет регистрацию переменных сеанса, в результате чего $count и $timestamp не сохраняются в записи сеанса. При следующем запросе сеанс на-чинается заново.

Сценарий sess_track.php явно не вызывает session_write_close(); PHP авто-матически сохраняет сеанс при завершении сценария. Страница вывода формируется только после обновления записи сеанса, так как может оказаться, что необходимо отправить клиенту cookies с иденти-фикатором сеанса. Необходимо сделать это до начала формирования тела страницы, так как cookies отправляются в заголовках.

Проблема предложенного сценария sess_track.php в том, что он работает только в том случае, если установлен параметр конфигурации PHP regis-ter_globals. Тогда регистрация переменных сеанса count и timestamp приво-дит к тому, что их значения становятся доступны как глобальные перемен-ные PHP $count и $timestamp. Однако если параметр register_globals не включен, то session_register() ничего не делает, и сценарий sess_track.php будет работать неправильно (счетчик всегда будет равен единице, будет выводить-ся только одна временная метка).

Этот момент очень важен, так как разработчики PHP не рекомендуют включать параметр register_globals из соображений безопасности. Это значит, что session_register() фактически выходит из употребления, и что существую-щие приложения, использующие эту функцию для работы с сеансами, будут выходить из строя по мере того, как все большее количество сайтов будет следовать рекомендациям отключения register_globals. Для того чтобы ре-шить проблему и написать код, который работал бы вне зависимости от уста-новки register_globals, необходимо получать переменные сеанса другим спо-собом. Есть две возможности: использовать глобальный массив $HTTP_SESSI-ON_VARS или (начиная с PHP 4.1) суперглобальный массив $_SESSION. Например, переменная сеанса count будет доступна как $HTTP_SESSION_VARS["count"] или $_SESSION["count"].

Можно достаточно легко изменить сценарий sess_track.php так, чтобы он не полагался на установку register_globals, но позволял работать с простыми именами переменных для манипулирования переменными сеанса:

• Не используйте session_register(). Вместо этого скопируйте переменные сеанса из глобального массива непосредственно в переменные $count и $timestamp.

• После того как работа с переменными сеанса завершена, скопируйте их обратно в массив переменных сеанса. Выполните копирование до записи сеанса, если вы явно вызываете session_write().

Этот подход требует от вас указания того, какой глобальный массив следует использовать для хранения переменных сеанса (что может зависеть от вер-сии PHP). Вместо того чтобы делать это каждый раз при обращении к пере-менной сеанса, удобнее написать пару функций, которые все сделают сами:

function get_session_val ($name)
{
global $HTTP_SESSION_VARS;
unset ($val);
if (isset ($_SESSION[$name]))
$val = $_SESSION[$name];
else if (isset ($HTTP_SESSION_VARS[$name]))$val = $HTTP_SESSION_VARS[$name];
return (@$val);
}
function set_session_val ($name, $val)
{
global $HTTP_SESSION_VARS;
if (PHP_VERSION >= "4.1")
$_SESSION[$name] = $val;
$HTTP_SESSION_VARS[$name] = $val;
}

Эти функции включены в библиотечный файл Cookbook_Webutils.php наря-ду с функциями, получающими значения других веб-параметров (см. ре-цепт 18.5). Они хранятся в Cookbook_Webutils.php, а не в Cookbook_Sessi-on.php, так что вы сможете вызвать их, даже если не захотите использовать модуль хранения сеанса в MySQL, реализуемый Cookbook_Session.php.

Рассмотрим сценарий sess_track2.php, показывающий, как избежать применения register_globals, лишь слегка изменив основную логику:

# sess_track2.php - вывод количества запросов сеанса и временных меток
# (без использования register_globals)
include_once "Cookbook_Session.php";
include_once "Cookbook_Webutils.php"; # требуется для make_unordered_list(),
# get_session_val(), set_session_val()
$title = "PHP Session Tracker";
# Открыть сеанс и извлечь значения сеанса.
session_start ();
$count = get_session_val ("count");
$timestamp = get_session_val ("timestamp");
# Если сеанс новый, инициализировать переменные.
if (!isset ($count))
$count = 0;
if (!isset ($timestamp))
$timestamp = array ();
# Увеличить счетчик, добавить текущую временную метку в массив.
++$count;
$timestamp[] = date ("Y-m-d H:i:s T");
if ($count < 10) # сохранить измененные значения в массиве переменных сеанса
{
set_session_val ("count", $count);
set_session_val ("timestamp", $timestamp);
}
else # очистить переменные сеанса после 10 вызовов{
session_unregister ("count");
session_unregister ("timestamp");
}
# сформировать страницу
?>


<?php print ($title); ?>

(body bgcolor="white")
printf ("

This session has been active for %d requests.

\n", $count);
print ("

The requests occurred at these times:

\n");
print make_unordered_list ($timestamp);
?>
(/body)


Сценарий sess_track2.php практически идентичен sess_track.php, есть всего два отличия:

• sess_track.php вызывает session_start() для открытия сеанса, но это не-обязательно, так как используется функция session_register(), которая неявно открывает сеанс. Сценарий sess_track2.php не использует sessi-on_register(). Он получает значения переменных напрямую из глобально-го хранилища переменных сеанса. В данном случае необходимо сначала вызывать функцию session_start() для явного открытия соединения.

• Если предельное количество запросов в сеансе (10) еще не достигнуто, то sess_track2.php явно сохраняет значения сеанса $count и $timestamp в глобальных массивах переменных сеанса, вызывая функцию set_sessi-on_val().

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела MySQL на эту тему:
Хранение сеансов в MySQL: приложения на Perl
Хранение сеансов в MySQL: Tomcat