Анонсы:
|
Сессии в PHPПодробное описание работы и объяснение механизма работы с сессиями PHP. Введение Сессии - это на самом деле очень просто. Надо только понимать, для чего они нужны и как устроены. Ответим сначала на первый вопрос.Возможно Вы знаете, что веб-сервер не поддерживает постоянного соединения с клиентом, и каждый запрос обрабатывается, как новый, без связи с предыдущими. То есть, нельзя ни отследить запросы от одного и того же посетителя, ни сохранить для него переменные между просмотрами отдельных страниц. Вот для решения этих двух задач и были изобретены сессии. Собственно, сессии, если в двух словах - это механизм, позволяющий однозначно идентифицировать браузер и создающий для этого браузера файл на сервере, в котором хранятся переменные сеанса. Подробно расписывать нужду в таком механизме я не буду. Это такие случаи, как корзина покупок в интернет магазине, авторизация, а так же, и не совсем тривиальные проблемы, такие, например, как защита интерактивных частей сайта от спама. В принципе, довольно несложно сделать собственный аналог сессий, не такой функциональный, как встроенный в PHP, но похожий по сути. На cookies и базе данных. При запросе скрипта смотрим, пришла ли cookies с определенным именем. Если cookies нет, то ставим ее и записываем в базу новую строку с данными пользователя. Если cookies есть, то читаем из базы данные. Еще одним запросом удаляем из базы старые записи и вот у нас готов механизм сессий. Совсем несложно. Но есть некоторые нюансы, которые делают предпочтительным использование именно встроенного механизма сессий Как устроены, и как работают сессии? Для начала надо как-то идентифицировать браузер. Для этого надо выдать ему уникальный идентификатор и попросить передавать его с каждым запросом. Стыдно признаться, но когда я впервые узнал о сессиях, я думал, что это какой-то особый механизм, некий новый способ общения браузера с сервером - "сессии". Что идентификатор сессии передается каким-то особым образом. Но, разочарование было жестоким... Сессии используют стандартные, хорошо известные способы передачи данных. Собственно, других-то просто и нет. Идентификатор - это обычная переменная. По умолчанию ее имя - PHPSESSID. Задача PHP отправить ее браузеру, чтобы тот вернул ее со следующим запросом. Из уже упоминавшегося раздела FAQ ясно, что переменную можно передать только двумя способами: в cookies или POST/GET запросом. PHP использует оба варианта. За это отвечают две настройки в php.ini: session.use_cookies - если равно 1, то PHP передает идентификатор в cookies, если 0 - то нет. Менять эти и другие параметры сессий можно так же, как и другие настройки PHP - в файле php.ini, а так же с помощью команды ini_set() или в файлах настройки веб-сервера Если включена только первая, то при старте сессии (при каждом вызове session_start ()) клиенту устанавливается cookies. Браузер исправно при каждом следующем запросе эту cookies возвращает и PHP имеет идентификатор сессии. Проблемы начинаются, если браузер cookies не возвращает. В этом случае, не получая cookies с идентификатором, PHP будет все время стартовать новую сессию, и механизм работать не будет. Если включена только вторая, то cookies не выставляется. А происходит то, ради чего, в основном, собственно, и стоит использовать встроенный механизм сессий. После того, как скрипт выполняет свою работу, и страница полностью сформирована, PHP просматривает ее всю и дописывает к каждой ссылке и к каждой форме передачу идентификатора сессии. Это выглядит примерно так: <a href="/index.php">Index</a> превращается в <a href="/index.php?PHPSESSID=9ebca8bd62c830d3e79272b4f585ff8f">Index</a> а к формам добавляется скрытое поле. <input name="PHPSESSID" type="hidden" value="00196c1c1a02e4c37ac04f921f4a5eec" /> И браузер при клике на любую ссылку, или при нажатии на кнопку в форме, пошлет в запросе нужную нам переменную - идентификатор сессии! Теоретически, в наших с вами самодельных сессиях на cookies и базе, можно самому, руками приписать ко всем ссылками передачу ид - и тогда наши собственные сессии будут работать независимо от cookies. Но, согласитесь - приятнее, когда эту работу делает кто-то другой? ;-) По умолчанию в последних версиях PHP включены обе опции. Как PHP поступает в этом случае? Кука выставляется всегда. А ссылки автодополняются только если РНР не обнаружил cookies с идентификатором сессии. Когда пользователь в првый раз за этот сеанс заходит на сайт, ему ставится cookies, и дополняются ссылки. При следующем запросе, если cookies поддерживаются, PHP видит cookies и перестает дополнять ссылки. Если cookies не работают, то PHP продолжает исправно добавлять ид к ссылкам, и сессия не теряется. Пользователи, у которых работают cookies, увидят длинную ссылку с ID только один раз. С передачей идентификатора закончили. Теперь осталось привязать к нему файл с данными на стороне сервера. PHP это сделает за нас. Достаточно просто написать: session_start(); И PHP запишет в файл, связанный с этой сессией, переменную test. Здесь очень важное замечание. Массив $_SESSION - особенный. В нем, собственно, и находятся переменные, которые мы ходим сделать доступными в различных скриптах. Чтобы поместить переменную в сессию, достаточно присвоить ее элементу массива $_SESSION. Чтобы получить ее значение - достаточно обратиться к тому же элементу. Пример будет чуть ниже. Cборкой мусора - удалением устаревших файлов PHP тоже занимается сам. Как и кодированием данных и кучей всяких других нужных вещей. В результате этой заботы работа с сессиями оказывается очень простой. Вот мы, собственно, и подошли к примеру работы сессий. Пример очень маленький: <?php Мы проверяем, есть ли у нас в сессии переменная counter, если нет, то создаем ее со значением 0, а дальше выводим ее значение и увеличиваем на единицу. Увеличенное значение запишется в сессию, и при следующем вызове скрипта переменная будет иметь значение 1, и так далее. Все очень просто. Для того, чтобы иметь доступ к переменным сессии на любых страницах сайта, надо написать ТОЛЬКО ОДНУ(!) строчку в самом начале КАЖДОГО файла, в котором нам нужны сессии: session_start(); И далее обращаться к элементам массива $_SESSION. Например, проверка авторизации будет выглядеть примерно так: Удаление переменных из сессии. Если у вас register_globals=off, то достаточно написать:
Если же нет, то тогда рядом с ней надо написать: Очень важно понимать, для чего сессии стоит использовать, а для чего - нет. Во-первых, помните, что сессии можно применять только тогда, когда они нужны самому пользователю, а не для того, чтобы чинить ему препятствия. Ведь он в любой момент может избавиться от идентификатора! Скажем, при проверке на то, что заполняет форму человек, а не скрипт, пользователь сам заинтересован в том, чтобы сессия работала - иначе он не сможет отправить форму! А вот для ограничения количества запросов к скрипту сессия уже не годится - злонамеренный скрипт просто не будет возвращать идентификатор. Во-вторых. Важно четко себе представлять тот факт, что сессия - это сеанс работы с сайтом, так как его понимает человек. Пришел, поработал, закрыл браузер - сессия завершилась. Как сеанс в кино. Хочешь посмотреть еще один - покупай новый билет. Стартуй новый сеанс. Этому есть и техническое объяснение. Гарантированно механизм сессий работает только именно до закрытия браузера. Ведь у клиента могут не работать cookies, а в этом случае, естественно, все дополненные идентификатором ссылки пропадут с его закрытием. Правда, сессия может пропасть и без закрытия браузера. В силу ограничений, рассмотренных в этой статье, механизм сессий не может определить тот момент, когда пользователь закрыл браузер. Для этого используется таймаут -; заранее определенное время, по истечении которого мы считаем, что пользователь ушел с сайта. По умолчанию этот параметр равен 24 минутам. Если вы хотите сохранять пользовательскую информацию на более длительный срок, то используйте cookies и, если надо - базу данных на сервере. В частности, именно так работают все популярные системы авторизации: - по факту идентификации пользователя стартует сессия и признак авторизованности передается в ней. В-третьих, не стоит стартовать сессии без разбору, каждому входящему на сайт. Это создаст совершенно лишнюю нагрузку. Не используйте сессии по пустякам к примеру, в счетчиках. То, что спайлог называет сессиями, считается, конечно же, на основе статистики заходов, а не с помощью механизма сессий, аналогичного PHP. К тому же, возьмем поисковик, который индексирует ваш сайт. Если поисковый робот не поддерживает cookies, то PHP по умолчанию будет поставлять к ссылкам PHPSESSID, что может не сильно понравится поисковику, который, по слухам, и так-то динамические ссылки не жалует, а тут вообще при каждом заходе - новый адрес! Если сессии используются для ограничения доступа к закрытому разделу сайта, то все просто поисковик и не должен его индексировать. Если же приходится показывать одну и ту же страницу как авторизованным, так и не авторизованным пользователям, то тут поможет такой трюк - стартовать сессию только тем, кто ввел пароль, или тем, у кого уже стартовала сессия. Для этого в начало каждой страницы вместо просто #0000bb;">session_start() пишем: Если имя и проль верные - пишем session_start()! Возможные проблемы и их устранение Самыми распространенными ошибками, которые выдает РНР при попытке работать с сессиями, являются такие: Две из них, Ошибку эту исправить несложно. Часто такое же сообщение появляется при старте сессий, в немного другой формулировке: Для начала узнаем, как вообще общается броузер с сервером. Происходит это по специальному протоколу HTTP. К примеру, когда ты набраешь адрес, или нажимаешь на ссылку, броузер посылает HTTP запрос серверу. Сервер отвечает. Первыми в ответе ВСЕГДА идут HTTP заголовки. Хоть один. И только потом уже сервер посылает, а броузер принимает, текст, или картинку, или файл - в общем, что было запрошено. Cобственно, из-за этого правила - сначала заголовок, а потом информация, и происходит данная ошибка. РНР, для твоего удобства, посылает заголовки автоматически, как только скрипт начинает выдавать броузеру информацию. Соответственно, если хоть один пробел был уже передан пользователю, заголовки уже ушли, и снова их послать уже никак не можно. А, как ты уже, наверное, догадался, команды header(), setcookie, session_start(), посылают HTTP заголовки. Разберем теперь это предупреждение. Все ясно написано. "Не могу послать заголовок, поезд уже ушел" - пишет нам РНР. Дальше РНР сообщает, в каком скрипте и в какой его строке (output started at /www/script.php:5>) произошел вывод информации, вызвавший автоматическую посылку заголовков. Очень легко найти и исправить. Может быть, там html теги, может быть, echo, а может и просто незамеченая пустая строка или пробел перед первым тегом <br /> . Очень часто такую ошибку вызывает файл, подключаемый через include, в котором либо есть какой-то вывод, либо пустая строка после закрывающего PHP тега - обнаружить ее очень трудно. Для решения этой проблемы нужно функцию header() (или session_start(), setcookie) и всю логику, которая ее вызывает, поместить ДО любого вывода в броузер. Просто перенести повыше в скрипте. Ведь вы всё равно перенаправляете браузер. То есть, никакой текст всё равно не будет выведен! Значит, и выводить что-то одновременно с заголовком Location нет смысла. Правильно планируйте структуру своего скрипта: блок, который обрабатывает POST, не должен ничего выводить в браузер. Иногда вы проверили ВСЁ - нигде ничего нет. Смените редактор. Посмотрите свой файл в другой программе. К примеру, Windows Блокнот при использовании кодировки Unicode добавляет в начало вашего файла служебный символ Byte Order Mark, никак при этом не ставя вас в известность. Откройте скрипт в другом редакторе и удалите посторонние символы. И смените Блокнот на другой редактор. Третья, И не забыть перезагрузить Apache после этого. Как выясняется, сообразительность людская не имеет пределов, и поэтому я вынужден пояснить: сообщение о третьей ошибке (невозможно найти каталог) НЕИЗБЕЖНО приведет к появлению первых двух, поскольку сообщение об ошибке - это вывод в браузер и после него заголовками пользоваться нельзя. Поэтому не спешите искать преждевременный вывод, а сначала пропишите правильный путь! Следующей по распространенности проблемой при работе с сессиями является тяжелое наследие register_globals. НЕ давайте переменным скрипта имена, совпадающие с индексами массива $_SESSION!> При register_globals=on значения будут перезаписывать друг друга, и вы запутаетесь. Если не работает, но и никаких сообщений не выводится, то добавьте в самое начало скрипта две строчки, отвечающие за вывод ВСЕХ ошибок на экран - вполне возможно, что ошибки есть, но вы их просто не видите. Вообще, если у вас "не работают" сессии, то сначала попробуйте передать идентификатор сессии руками, то есть, сделать ссылку и приписать к ней идентификатор: При этом следует убедится, что не включена директива session.use_only_cookies, которая запрещает PHP принимать идентификатор сессии, если он был передан через URL Если этот пример не заработает, то проблема либо в банальных опечатках (половина "проблем" с сессиями происходит от неправильно написанного имени переменной), либо в слишком старой версии PHP: поддержка сессий появилась в версии 4.0, а массив $_SESSION - в 4.1 (До этого использовался $HTTP_SESSION_VARS). Если же заработает - то проблема в cookies. Отслеживайте - что за cookies ставит сервер браузеру, возвращает ли браузер ее. Искать очень полезно, просматривая обмен HTTP-заголовками между браузером и сервером. Объяснение принципа работы cookies выходит за рамки этого и так уж слишком большого текста, но хотя бы убедитесь, что сервер cookies с идентификатором посылает, а браузер - возвращает. И при этом идентификаторы совпадают друг с другом =). Установка cookies должна выглядеть, как Ответ сервера должен выглядеть, как Если пример отсюда работает, а ваш собственный код - нет, то проблема, очевидно, не в сессиях, а в алгоритме. Ищите, где потеряли переменную, по шагам отлаживайте свой скрипт. Еще одна проблема может возникнуть, если вы используете перенаправление через header или навигацию с помощью JavaScript. Дело в том, что РНР автоматически дописывает идентификатор сессии только к ссылкам, но не делает этого для header-ов, яваскрипта, мета-тегов. Поэтому надо добавлять идентификатор руками, например, так: Так же, весьма редкая, и совершенно непонятно, откуда появляющаяся, проблема бывает в том, что настройка session.save_handler имеет значение, отличное от files. Если это не так - исправляйте.
|
Погода в Рудне на 10 Ноя 2024 г. 704 - Вьетнамских донгов - 1 |