- •Тема 1 Основы cgi-программирования
- •1.1 Методы передачи данных
- •1.2 Передача документа пользователю
- •1.3 Передача информации cgi-сценарию
- •Тема 2 Характеристика языка php
- •2.1 Принцип работы php
- •2.2 Переменные, константы, выражения
- •Тема 3 Работа с данными формы
- •3.1 Передача данных
- •3.2 Трансляция полей формы в переменные
- •Тема 4 Конструкции языка
- •4.1 Условные инструкции
- •4.2 Инструкции циклов
- •4.3 Инструкции включения
- •Тема 5 Ассоциативные массивы
- •5.1 Списки и ассоциативные массивы
- •5.2 Операции над массивами
- •5.3 Списки и строки
- •5.4 Сериализация
- •Тема 6 Работа с массивами
- •6.1 Сортировка массивов
- •6.2 Функции для работы с массивами
- •Тема 7 Функции и области видимости
- •7.1 Формат определения функции, передача параметров
- •7.2 Глобальные, локальные, статические переменные
- •7.3 Рекурсия, вложенные и условно-определяемые функции
- •7.4 Передача функций по ссылке и возврат функцией ссылки
- •Тема 8 Строковые функции
- •8.1 Функции работы со строками
- •8.2 Работа с блоками текста
- •Тема 9 Математические функции
- •9.1 Встроенные константы
- •9.2 Встроенные функции
- •Тема 10 Работа с файлами и каталогами,
- •10.1 Функции работы с файлами
- •10.2 Блокирование файла
- •10.3 Функции работы с каталогами
- •10.4 Запуск внешних программ
- •Тема 11 Работа с датами и временем,
- •11.1 Представление времени в формате timestamp
- •11.2 Работа с датами, григорианский календарь
- •11.3 Посылка писем через php
- •Тема 12 Работа с www
- •12.1 Установка заголовков ответа
- •12.2 Работа с Cookies
- •Тема 13 Управление интерпретатором
- •13.1 Управление интерпретатором
- •13.2 Управление сессиями
- •Тема 14 Работа с базой данных mysql
- •14.1 Соединение с базой данных
- •14.2 Выполнение запросов к базе данных
- •Тема 15 Загрузка файлов на сервер
- •15.1 Multipart-формы, тег выбора файла
- •15.2 Поддержка закачки в php
- •Учебное издание
- •Разработка программного обеспечения на платформе net: php.Net
- •246019 Г. Гомель, ул. Советская, 104
13.2 Управление сессиями
Сессии представляют собой механизм, позволяющий хранить некоторые (и произвольные) данные, индивидуальные для каждого пользователя (например, его имя и номер счета), между запусками сценария. Термин «сессия» является транслитерацией от английского слова session, что в буквальном переводе должно бы означать «сеанс». Фактически, сессия – это некоторое место долговременной памяти (обычно часть на жестком диске и часть – в Cookies браузера), которое сохраняет свое состояние между вызовами сценариев одним и тем же пользователем. Поместив в сессию переменную (любой структуры), при следующем запуске сценария получим ее в целости и сохранности.
Зачем нужны сессии? В Web-программировании есть класс задач, который может вызвать много проблем, если писать сценарии «в лоб». Речь идет о невозможности запустить программу на длительное время, позволив ей при этом обмениваться данными с пользователями.
Сценарии должны запускаться, моментально выполняться и возвращать управление системе. Пусть нужно написать форму, содержащую большое число полей, которую было бы глупо поместить на одну страницу. Нужно разбить процесс заполнения формы на несколько этапов, и представить их в виде отдельных HTML-документов. В первом документе с диалогом у пользователя может запрашиваться его имя и фамилия, во втором (если первый был заполнен верно) – данные о его месте жительства, и в третьем – номер кредитной карточки.
В любой момент можно вернуться на шаг назад, чтобы исправить те или иные данные. Если все в порядке, накопленная информация обрабатывается – например, помещается в базу данных.
Реализация такой схемы оказывается для Web-приложений довольно нетривиальной проблемой. Действительно, придется хранить все ранее введенные данные в каком-нибудь временном хранилище, которое должно аннулироваться, если пользователь вдруг передумает и «уйдет» с сайта. Для этого можно использовать функции сериализации и файлы. Однако ими проблема решается только наполовину: нужно также привязывать конкретного пользователя к конкретному временному хранилищу. Эти проблемы решаются с применением сессий PHP.
Механизм работы сессий. Должен существовать механизм, который бы позволил PHP идентифицировать каждого пользователя, запустившего сценарий. То есть при следующем запуске PHP нужно однозначно определить, кто его запустил: тот же человек, или другой. Делается это путем присвоения клиенту так называемого уникального идентификатора сессии. Чтобы этот идентификатор был доступен при каждом запуске сценария, PHP помещает его в Cookies браузера. Использовать Cookies не обязательно, существует и другой способ.
Зная идентификатор (будем называть его SID), PHP может определить, в каком же файле на диске хранятся данные пользователя. Чтобы сохранять переменную (обязательно глобальную) в сессии нужно ее зарегистрировать с помощью специальной функции. После регистрации при следующем запуске сценария тем же пользователем она получит то же самое значение, которое было у нее при предыдущем завершении программы. Это произойдет потому, что при завершении сценария PHP автоматически сохраняет все переменные, зарегистрированные в сессии, во временном хранилище. Можно в любой момент аннулировать переменную – «вычеркнуть» ее из сессии, или же уничтожить все данные сессии. Чтобы задать промежуточное хранилище, которое использует PHP, можно написать соответствующие функции и зарегистрировать их как обработчики сессии. Однако В PHP существуют обработчики по умолчанию, которые хранят данные в файлах.
Инициализация сессии. Прежде, чем работать с сессией, ее необходимо инициализировать. Делается это путем вызова специальной функции session_start().
void session_start()
Функция инициализирует механизм сессий для текущего пользователя, запустившего сценарий. По ходу инициализации она выполняет ряд действий:
1. Если посетитель запускает программу впервые, у него устанавливается Cookies с уникальным идентификатором, и создается временное хранилище, ассоциированное с этим идентификатором.
2. Определяется, какое хранилище связано с текущим идентификатором пользователя.
3. Если в хранилище имеются какие-то переменные, их значения восстанавливаются (создаются глобальные переменные, которые были сохранены в сессии при предыдущем завершении сценария).
Регистрация переменных. Чтобы сохранить переменную в сессии, ее предварительно нужно зарегистрировать. Для этого предназначена функция session_register().
bool session_register(mixed $name
[, mixed $name1, ...])
Функиця принимает в параметрах одно или несколько имен переменных (имена задаются в строках, без знака $ слева), регистрирует их в текущей запущенной сессии и возвращает значение «истина», если все прошло корректно. В функцию можно передавать не одну строку в каждом параметре, а сразу список строк. Каждая такая строка будет регистрировать отдельную переменную с соответствующим именем. Элементом списка может быть список строк, и т. д. Нет ничего страшного, если дважды зарегистрировать одну и ту же переменную в сессии. Так и происходит при повторном запуске сценария.
Пример работы с сессиями:
<?
session_start();
session_register("count");
$count=@$count+1;
?>
<body>
<h2>Счетчик</h2>
В текущей сессии работы с браузером Вы открыли эту страницу <?=$count?> раз(а). Закройте браузер, чтобы обнулить счетчик.
</body>
Идентификатор сессии и имя группы. На одном и том же сайте могут сосуществовать сразу несколько сценариев, которые нуждаются в услугах поддержки сессий PHP. Они «ничего не знают» друг о друге, поэтому временные хранилища для сессий должны выбираться не только на основе идентификатора пользователя, но и на основе того, какой из сценариев запросил обслуживание сессии.
Имя группы сессий. Пусть разработчик A написал сценарий счетчика. Он использует переменную $count, и не имеет никаких проблем, до тех пор, пока разработчик B, ничего не знающий о сценарии A, не создал систему статистики, которая тоже использует сессии. Он также регистрирует переменную $count, не зная о том, что она уже «занята». В результате пользователь, запустив сначала сценарий разработчика B, а потом – A, видит, что данные счетчиков перемешались.
Нужно разграничить сессии, принадлежащие одному сценарию, от сессий, принадлежащих другому. Для этого используются группы сессий. Можно давать группам сессий непересекающиеся имена, и сценарий, знающий имя своей группы сессии, сможет получить к ней доступ. Теперь разработчики A и B могут оградить свои сценарии от проблем с пересечениями имен переменных. Достаточно в первой программе указать PHP, что мы хотим использовать группу с именем, скажем, sesA, а во второй – sesB.
string session_name([string $newname])
Функция устанавливает или возвращает имя группы сессии, которая будет использоваться PHP для хранения зарегистрированных переменных. Если $newname не задан, то возвращается текущее имя. Если же этот параметр указан, то имя группы будет изменено на $newname, при этом функция вернет предыдущее имя.
Session_name() лишь сменяет имя текущей группы и сессии, но не создает новую сессию и временное хранилище! Нужно в большинстве случаев вызывать session_name (имя_группы) еще до ее инициализации – вызова session_start().
Если функция session_name() не была вызвана до инициализации, PHP будет использовать имя по умолчанию – PHPSESID.
Имя группы сессий, устанавливаемое рассматриваемой функцией, – это имя Cookie, который посылается в браузер клиента для его идентификации. Таким образом, пользователь может одновременно активизировать две и более сессий – с точки зрения PHP он будет выглядеть как два или более различных пользователя. Следует помнить, что, случайно установив в сценарии Cookie, имя которого совпадает с одним из имен группы сессий, Cookie «затрется». Пример:
<?
session_name("CounterScript"
session_start();
session_register("count");
$count=@$count+1;
?>
В текущей сессии Вы открыли эту страницу
<?=$count?> раз(а).
Лучше всегда указывать имя группы сессии вручную, не полагаясь на значение по умолчанию.
Идентификатор сессии. Идентификатор сессии (SID) фактически является именем временного хранилища, которое будет использовано для хранения данных сессии между запусками сценария. Итак, один SID – одно хранилище. Нет SID, нет и хранилища, и наоборот.
Как же соотносится идентификатор сессии и имя группы? Имя – это собирательное название для нескольких сессий (то есть, для многих SID), запущенных разными пользователями. Один и тот же клиент никогда не будет иметь два различных SID в пределах одного имени группы. Но его браузер вполне может работать с несколькими SID, расположенными логически в разных «пространствах имен».
Итак, все SID уникальны и однозначно определяют сессию на компьютере, выполняющем сценарий – независимо от имени сессии. Имя же задает «пространство имен», в которое будут сгруппированы сессии, запущенные разными пользователями. Один клиент может иметь сразу несколько активных пространств имен (то есть несколько имен групп сессий).
string session_id([string $sid])
Функция возвращает текущий идентификатор сессии SID. Если задан параметр $sid, то у активной сессии изменяется идентификатор на $sid. Делать это не рекомендуется. Фактически, вызвав ses-sion_id() до session_start(), можем подключиться к любой (в том числе и «чужой») сессии на сервере, если знаем ее идентификатор.
Другие функции.
bool session_is_registered(string $name)
Функция session_is_registered() возвращает значение true, если переменная с именем $name была зарегистрирована в сессии, иначе возвращается false.
bool session_unregister(struing $name)
Функция отменяет регистрацию для переменной с именем $name для текущей сессии. При завершении сценария все будет выглядеть так, словно переменная с именем $name и не была никогда зарегистрирована. Возвращает true, если все прошло успешно, и false – в противном случае. После вызова функции session_unregister() глобальная переменная, которая была «аннулирована», не уничтожается, а сохраняет свое значение.
void session_unset()
Функция session_unset(), в отличие от session_unregister(), не только отменяет регистрацию переменных (всех переменных сессии, а не какой-то одной), но и уничтожает глобальные переменные, которые были зарегистрированы в сессии.
string session_save_path([string $path])
Функция возвращает имя каталога, в котором будут помещаться файлы – временные хранилища данных сессии. В случае, если указан параметр, активное имя каталога будет переустановлено на $path. При этом функция вернет предыдущий каталог.
Установка обработчиков сессии.
Если стандартные обработчики сессии не устраивают, например, нужно хранить переменные сессии в базе данных или еще где-то. В этом случае достаточно будет переопределить обработчики своими собственными функциями.
Обзор обработчиков. Всего существует 6 функций, связанных с сессиями, которые PHP вызывает в тот или иной момент работы механизма обработки сессий.
bool handler_open(string $save_path, string $session_name)
Функция вызывается, когда вызывается session_start(). Обработчик должен взять на себя всю работу, связанную с открытием базы данных для группы сессий с именем $session_name. В параметре $save_path передается то, что было указано при вызове session_save_path() или же путь к файлам-хранилищам данных сессий по умолчанию.
bool handler_close()
Этот обработчик вызывается, когда данные сессии уже записаны во временное хранилище и его нужно закрыть.
string handler_read(string $sid)
Вызов обработчика происходит, когда нужно прочитать данные сессии с идентификатором $sid из временного хранилища. Функция должна возвращать данные сессии в специальном формате, который выглядит так:
имя1=значение1; имя2=значение2; ...;
Здесь имяN задает имя очередной переменной, зарегистрированной в сессии, а значениеN – результат вызова функции Seria-lize() для этой переменной. Пример: foo|i:1;count|i:10;
Она говорит о том, что из временного хранилища были прочитаны две целые переменные, первая из которых равна 1, а вторая – 10.
string handler_write(string $sid, string $data)
Обработчик предназначен для записи данных сессии с идентификатором $sid во временное хранилище – например, открытое ранее обработчиком handler_open(). Параметр $data задается задается аналогично описаному выше. Действия этой функции сводятся к записи в базу данных строки $data без каких-либо ее изменений.
bool handler_destroy(string $sid)
Обработчик вызывается, когда сессия с идентификатором $sid должна быть уничтожена.
bool handler_gc(int $maxlifetime)
Обработчик вызывается при завершении работы сценария. Если пользователь окончательно «покинул» сервер, значит, данные сессии во временном хранилище можно уничтожить. Ей передается в параметрах то время (в секундах), по прошествии которого PHP принимает решение о необходимости «собрать мусор» (garbage collection) – т. е., это максимальное время существования сессии. Если храним данные сессии в базе данных, должны удалить из нее все записи, доступ к которым не осуществлялся более, чем $maxlifetime секунд. Таким образом, «застарелые» временные хранилища будут иногда очищаться.
Регистрация обработчиков.
void session_set_save_handler($open, $close, $read, $write, $destroy, $gc)
Функция регистрирует подпрограммы, имена которых переданы в ее параметрах, как обработчики текущей сессии. Параметр $open содержит имя функции, которая будет вызвана при инициализации сессии, а $close – функции, вызываемой при ее закрытии. В $read и $write нужно указать имена обработчиков для чтения и записи во временное хранилище. Функция с именем, заданным в $destroy, будет вызвана при уничтожении сессии. Обработчик, определяемый параметром $gc, используется как сборщик мусора. Функцию можно вызывать только до инициализации сессии, иначе она игнорируется.
Сессии и Cookies. До сих пор подразумевалось, что использование сессий немыслимо без Cookies. Действительно, Cookies представляют собой наиболее простое решение задачи идентификации каждого подключившегося пользователя, что необходимо для связи временного хранилища и данных сессии. Но как быть, если пользователи отключили Cookies в своих браузерах? На любом браузере нужен механизм, позволяющий отказаться от использования Cookies при управлении сессиями. Такой механизм существует в PHP, и основная его идея состоит в том, чтобы передавать идентификатор сессии не в Cookies, а например, в данных запроса GET.
Явное использование константы SID. В PHP существует специальная константа с именем SID. Она содержит имя группы текущей сессии и ее идентификатор в формате имя=идентификатор. Достаточно передать значение константы SID в сценарий, чтобы он «подумал», что данные пришли из Cookies.
Пример использования сессий без Cookies
<?
session_name("test");
session_start();
session_register("count");
$count=@$count+1;
?>
<body>
<h2>Счетчик</h2>
В текущей сессии работы с браузером Вы открыли эту страницу <?=$count?> раз(а). Закройте браузер, чтобы обнулить этот счетчик.<hr>
<a href=sesget.php?<?=SID?>>Click here!</a>
</body>
Если набрать в браузере адрес:
http://www.somehost.ru/sesget.php
то создастся новая сессия с уникальным идентификатором. Если сразу же нажать кнопку Обновить, счетчик не увеличится, потому что при каждом запуске будет создаваться новое временное хранилище – у PHP просто нет информации об идентификаторе пользователя. В предпоследней строчке передаются в сценарий, запускаемый через гиперссылку, данные об идентификаторе текущей сессии. Теперь с его точки зрения они якобы пришли из Cookies…
Все будет работать так, как описано, только в том случае, если в браузере действительно отключены Cookies. Если же они включены, PHP просто не будет генерировать константу SID (она будет пустой) и задействует Cookies.
Неявное изменение гиперссылок. Если в гипессылке по ошибке пропустить <?=SID?>, PHP вставит его автоматически. Причем так, чтобы это не повредило другим параметрам, уже присутствующим в URL. Если запустить следующий сценарий в браузере, навести мышь на гиперссылку и посмотреть строку состояния,
<?session_start()?>
<body>
<a href=/path/some.php>Click here!</a><br>
<a href=/path/some.html?a=a&b=b>Click here!</a><br>
<a href=/>Click here!</a><br>
</body>
то получим следующие адреса этих ссылок с точки зрения браузера:
http://www.some.ru/path/some.php?PHPSESSID=816a921f
http://www.some.ru/path/some.html?a=a&b=b&PHPSESSID=86a20
http://www.some.ru/?PHPSESSID=8114536a920bfb2a
Во втором адресе идентификатор корректно вставился в конец обычных параметров страницы. В третьем адресе идентификатор сессии прикрепляется к URL независимо от типа документа, на который он указывает. Таким образом, константа SID – это устаревший прием передачи идентификатора сессии.
Неявное изменение формы. PHP умеет не только изменять гиперссылки, он также и добавляет скрытые поля в формы, которые формирует сценарий, чтобы передать идентификатор сессии вызываемому документу! Пример сценария, который выводит пустую форму, и в ней появляется дополнительное скрытое поле с идентификатором сессии.
<?session_start()?>
<form action=aaa method=post>
</form>
То, что выдается в браузере (Internet Explorer) после запуска этого сценария и выбора в меню пункта Просмотр в виде HTML:
<form action="aaa" method="post">
<INPUT TYPE=HIDDEN NAME="PHPSESSID"
VALUE="0a717e848e91db11b524a">
</form>
PHP добавил в форму скрытое поле с нужным именем и значением. Он также заключил в кавычки значения атрибутов тэга <form>.
Примечание. Сценарию, рассчитанному на сессии все равно, включены Cookies в браузере пользователя, или нет. PHP автоматически добавляет идентификатор сессии ко всем ссылкам и формам, которые он встретит, сценарии все равно будут продолжать работать, даже если Cookies будет отключены, только их URL (да и всех других документов) немного удлинятся.
