Л. № 12 16 Сохранение состояния с помощью функций управления сессией В предыдущей главе было рассказано о методе сохранения состояния с помощью cookie. Однако в РНР4 есть для этого гораздо больше средств: имеются встроенные функции для работы с сессиями. В этих функциях используются методы, похожие на описанные в предыдущей главе. Такие методы встроены в РНР4, сводя работу по организации сессии к простому вызову функций. Функции управления сессией базируются на тех же концепциях, с которыми вы ознакомились ранее. Эти функции присваивают пользователям уникальные идентификаторы, и их можно использовать для получения информации о текущей сессии. Различие заключается в том, что большая часть работы выполняется за вас автоматически. Если пользователь обращается к странице, ему будет присвоен новый идентификатор или переприсвоен старый, использовавшийся ранее. Все глобальные переменные, которые были связаны с сессией, будут доступны вашей программе. Метод передачи информации, рассмотренный в предыдущей главе, автоматически поддерживается функциями управления сессией языка РНР4. Cookie используются по умолчанию, однако вы можете быть уверены в успехе, используя идентификатор сессии во всех ссылках на страницах, работающих с сессиями. Состояние сессии обычно сохраняется во временном файле, однако, существуют модули для работы с популярными базами данных. Создание сессии с помощью функции session_start() Необходимо явно объявлять начало и конец сессии, если не изменялся файл настройки php.ini. По умолчанию сессия не создается автоматически, т.к. в файле php.ini стоит такая строка: session.auto_start = 0 Для создания сессии необходимо вызывать функцию session_start(). После этого, вы автоматически получите доступ к идентификатору сессии пользователя с помощью функции session_id(). Функция session_id() позволяет вам как задавать, так и получать значение идентификатора сессии. В листинге 16.1 создается сессия, идентификатор которой выводится в окно браузера. Когда эта программа запускается в первый раз, создается идентификатор сессии. Если страница перезагружается или посещается повторно, пользователю присваивается тот же идентификатор сессии. Это, конечно, предполагает, что использование cookie разрешено на браузере пользователя. 1 Листинг 16.1. Создание или открытие ceccии <?php session_start(); ?> <html> <head> <title>Листинг 16.1. Создание или открытие ceccии</title> </head> <body> <?php print "<р>3дравствуйте, ваш идентификатор сессии " .session_id(); ?> </body> </html> Поскольку функция start_session() пытается установить cookie во время первой инициализации сессии, необходимо, чтобы эта функция вызывалась до того, как вы пошлете что-либо другое браузеру. Обратите внимание, что для этого cookie не задается время, через которое он будет уничтожен. Указанное означает, что сессия будет активной только до тех пор, пока браузер остается активным и cookie не будет сохраняться при перезагрузке браузера. Это можно изменить, отредактировав в файле php.ini значение переменной session.cookie_lifetime. По умолчанию значение данной переменной равно 0, однако вы можете задать период в секундах, по истечении которого cookie будет уничтожен. Это значение будет установлено для всех cookie в текущей сессии, которые посылаются браузеру. Работа с переменными сессии Возможность обращаться к уникальному идентификатору каждого из ваших документов РНР является только частью возможностей работы с сессиями языка РНР4. Вы можете зарегистрировать любое количество глобальных переменных в данной сессии и затем обращаться к этим переменным с любой страницы данной сессии. Для того чтобы зарегистрировать переменную в текущей сессии, вы должны использовать функцию session_register(). Функции session_register() передается строка, которая содержит одно или несколько имен переменных. Эта функция возвращает true, если регистрация прошла нормально. При вызове данной функции передается только имя переменной, а не сама переменная. 2 В листинге 16.2 регистрируются две переменные. Листинг 16.2. Регистрация переменных в ceccии <?php session_start(); ?> <html> <head> <title>Листинг 16.2. Регистрация переменных в ceccии</title> </head> <body> <?php session_register("product1"); session_register("product2"); $product1 = "AMD Athlon"; $product2 = "nVIDIA"; print session_encode(); print "Товары были зарегистрированы"; ?> </body> </html> «Магия» программы из листинга 16.2 не проявит себя, пока пользователь не перейдет на другую страницу. В листинге 16.3 создается отдельная РНРпрограмма, которая обращается к переменным, зарегистрированным в листинге 16.2. Листинг 16.3. Обращение к зарегистрированным переменным <?php session_start(); ?> <html> <head> <title> Листинг 16.3. Обращение к зарегистрированным переменным</title> </head> <body> <?php print "Вы выбрали такие товары:"; print "<ul><li>$product1 <li>$product2</ul>"; ?> </body> </html> 3 В результате имеется доступ к переменным $product1 и $product2 на абсолютно другой странице. РНР4 автоматически создает временный файл. Где хранится этот файл — вы можете узнать с помощью функции session_save_path(). Функция session_save_path() принимает необязательный параметр, в котором содержится путь к каталогу, где будут сохраняться все файлы сессии. Если этой функции не передавать аргументов, она вернет строку, содержащую путь к каталогу, в котором в данный момент сохраняются файлы сессии. Заглянув в указанный каталог, можно увидеть файлы с приблизительно такими именами: sess_2638864e9216fee10fcb8a61db382909 sess_4652d68f8edd8654833487edf879ac79 Открыв файл, имя которого совпадает с идентификатором сессии, выделенным во время первого запуска программы из листинга 16.1, можно увидеть, как сохраняются зарегистрированные переменные сессии: product1|s:17:"AMD Athlon";product2|s:8:"nVIDIA"; Когда вызывается функция session_register(), РНР записывает имя и значение переменной в файл. Этот файл можно в последующем считывать и восстанавливать значения необходимых переменных. После регистрации переменной с помощью функции session_register() вы можете изменять значение переменной на протяжении всей программы, и это значение будет отражено в файле сессии. Пример из листинга 16.2 демонстрирует процесс регистрации переменных в сессии. Однако эта программа не очень гибкая. В идеале у вас должна быть возможность регистрировать любое количество значений. Вы можете, например, захотеть дать пользователям возможность выбирать товары из списка. К счастью, вы можете передать имя массива функции session_register(), и этот массив будет хранить для вас данные в закодированном виде. В листинге 16.4 создается форма, которая позволяет пользователю выбирать несколько наименований. Затем вы можете использовать переменные сессии для создания корзины покупателя. Мы создаем или открываем сессию с помощью функции session_start(). Это дает нам возможность обращаться ко всем ранее установленным переменным сессии. В HTML-форме нами устанавливаются свойства ACTION элемента FORM так, чтобы они указывали на текущий документ. Затем мы создаем элемент SELECT под названием form_products(), который содержит элементы OPTION с именами товаров. Помните, что элементы HTML-формы, позволяющие сделать выбор из нескольких вариантов, должны 4 иметь квадратные скобки после аргументов NAME. Это дает возможность занести выбранные пользователем значения в массив. Листинг 16.4. Регистрация массива в сессии <?php session_start(); ?> <html> <head> <title>Листинг 16.4. Регистрация массива в ceccии</title> </head> <body> <h1>Страница выбора товара</h1> <?php if (isset($form_products)) { $products = $form_products; session_register("products"); print "<р>Ваш товар был зарегистрирован"; } ?> <p><form method="POST"> <select name="form_product[ ]" multiple size=3> <option> AMD Athlon <option> nVIDIA <option> SDRAM DIMM 512Mb <option> CD-RW ASUS <option> FDD SONY </select> <p><input type="submit" value="Выбрать"> </form> <p><a href ="ls16-5.php">Корзина</а> </body> </html> В блоке, в котором находится РНР программа, мы для начала проверяем, существует ли массив $form_products. Если такой массив существует, мы решаем, что форма была получена. Нами присваивается значение этой переменной другой переменной, с именем $products, которая затем регистрируется с помощью функции session_register(). Мы не регистрируем саму переменную $form_products, поскольку это вызовет конфликт с переменной POST, которая была переслана с формой. 5 Внизу данной страницы есть ссылка на другую страницу, которая будет использована для отображения выбранных пользователем товаров. Эта новая программа приведена в листинге 16.5. Листинг 16.5. Обращение к переменным сессии <?php session_start(); print session_encode(); ?> <html> <head> <title>Листинг 16.5. Обращение к переменным ceccии</title> </head> <body> <h1>Просмотр выбранных товаров</h1> <?php if (isset($products)) { print "<b>Ваша корзина:</b><оl>"; foreach($products as $p) print "<li>$p"; print "</ol>"; } ?> <a href="ls16-4.php">Haзад на страницу выбора товара</а> </body> </html> В этой программе нами снова используется функция session_start() для открытия сессии. Мы проверяем наличие переменной $products. Если эта переменная существует, то просматриваем ее в цикле, выводя каждое из выбранных пользователем наименований в окно браузера. В настоящей программе обработки набора покупателя вы, конечно, должны хранить информацию в базе данных, а также проверять данные, введенные пользователем, вместо того, чтобы вслепую сохранять и выводить эту информацию. Однако не стоит забывать, что листинги 16.4 и 16.5 демонстрируют простоту использования функций управления сессией для обращения к переменным, которые были созданы на других страницах. Завершение сессии и уничтожение переменных Для завершения сессии можно воспользоваться функцией session_destroy(), что также приведет к уничтожению всех переменных 6 сессии. Функции session_destroy() не нужно передавать каких-либо аргументов. Для правильной работы этой функции нужно только чтобы сессия существовала. Приведенный фрагмент программы открывает сессию и сразу уничтожает ее: session_start(); session_destroy(); Когда вы перейдете на другие страницы, уничтоженная сессия станет недоступной, поэтому придется создавать новую сессию. Все зарегистрированные переменные будут утеряны. Однако функция session_destroy() не сразу уничтожает зарегистрированные переменные. Эти переменные доступны программе, в которой была вызвана функция session_destroy(), пока страница не перезагрузится. Приведенный ниже фрагмент программы открывает или инициализирует сессию и регистрирует переменную под названием $test, которой присваивается значение 5. Уничтожение сессии не приводит к немедленному уничтожению зарегистрированной переменной: session_start(); session_register()("test"); $test=5; session_destroy(); print $test; //выводит 5 Для того чтобы уничтожить все зарегистрированные переменные, вы должны воспользоваться функцией session_unset(). Эта функция уничтожает все переменные, связанные с сессией, — как в файле сессии, так и в вашей программе. Данной функцией нужно пользоваться с осторожностью. session_start(); session_register()("test"); $test=5; session_unset(); session_destroy(); print $test; //ничего не выводит, //переменной $test больше не существует Перед тем как уничтожить сессию, мы вызываем функцию session_unset(), которая полностью стирает переменную $test и остальные переменные из памяти. Передача идентификатора сессии в строке запроса Ранее вы полагались на cookie, сохраняя состояние сессии между обращениями к программам. Сам по себе этот метод не является самым надежным способом сохранения состояния, поскольку у вас нет уверенности, что браузер пользователя принимает cookie. Однако вы можете перестраховаться, передавая 7 идентификатор сессии от программы к программе, «прошив» его в строку запроса. РНР автоматически делает пару «имя/значение» доступной в константе с именем SID, если cookie, соответствующий данному идентификатору сессии, не был найден. Вы можете добавить эту строку в любую ссылку HTML во всех доступных для данной сессии страницах: <a href="another_page.html?<? print SID; ?>"> Другая страница</а> Этот запрос будет получен браузером в таком виде: <а href="another_page.html? PHPSESSID=55865282d654e69658f88a68746d86c8"> Другая страница</а> Идентификатор сессии, передаваемый таким образом, будет автоматически распознан получающей страничкой при вызове функции session_start(), а вы сможете обращаться к переменным сессии как обычно. Если РНР4 был скомпилирован с установленным параметром --enable-trans-sid, эта строка запроса автоматически добавится к каждой ссылке на вашей странице. Данный параметр по умолчанию отключен, поэтому явное добавление константы SID к ссылкам сделает вашу программу более гибкой. Кодирование и декодирование переменных сессии Вы уже увидели, как РНР кодирует и сохраняет переменные сессии, когда открывали файл сессии. Кроме того, у вас есть возможность получить доступ к закодированной строке в любой момент с помощью функции session_encode(). Это может быть полезно при отладке доступных в сессии переменных. Вы имеете возможность использовать функцию session_encode() для определения состояния всех переменных сессии: session_start(); print session_encode()."<br>"; // вывод: // products|a:2:{i:0;s:8:"AMD Athlon";s:1;s:6:"nVIDIA";} Благодаря этому простому фрагменту программы вы можете увидеть сохраненные переменные сессии. Можно использовать эту информацию для проверки того, что эти переменные были зарегистрированы и изменены так, как вы ожидали. Кроме того, функция session_encode() может быть полезна, если вам нужно «заморозить» переменную для ее сохранения в базе данных или файле. 8 После получения закодированной строки у вас есть возможность декодировать и восстановить ее значения с помощью функции session_decode(). Приведенный ниже фрагмент программы демонстрирует этот процесс: session_start(); session_unset(); //теперь точно нет никаких переменных сессии session_decode("products|a:2:{i:0;s:8:"AMD Athlon"; s:1;s:6:"nVIDIA";}"); foreach ($products as $p) { print "$p<br>"; } //Вывод: //AMD Athlon //nVIDIA Нами начинается сессия как обычно. Чтобы убедиться в том, что мы начинаем с нуля, используем функцию session_unset() для уничтожения всех переменных сессии. Затем передаем кодированную строку функции session_decode(). Функция session_decode() не возвращает значений, а заполняет переданную ей переменную декодированным значением. Для того чтобы убедиться в этом, мы создаем цикл, в котором в окно браузера выводятся новые значения переменной $products. Проверка регистрации переменной Вы можете проверить, существует ли переменная в программе, с помощью функции isset(). В добавление к этому, использовав функцию session_is_registered(), можно проверить, является ли переменная зарегистрированной. Эта функция принимает строку, в которой должно находиться имя переменной, и возвращает true, если переменная является зарегистрированной. if (session_is_registered("products")) print "'products' зарегистрированы!"; Указанное будет полезным, если вам нужно узнать происхождение переменной. У вас может появиться необходимость убедиться, что переменная, с которой вы работаете, доступна как переменная сессии, если данные передавались как часть запроса GET. 9