Сессии в php примеры. Сессии. Подробное описание работы и объяснение механизма

Прежде чем мы дадим определение термину "сессия", давайте немного рассмотрим предысторию, зачем вообще возникла потребность в сессиях, рассмотрим одну особенность протокола HTTP.

Одной из основных особенностей протокола HTTP является то, что он не обязывает сервер сохранять информацию о клиенте между запросами, то есть идентифицировать клиента. Это так называемый stateless-протокол. Связь между клиентом и сервером заканчивается как только завершается обработка текущего запроса. Каждый новый запрос к серверу подразумевается как абсолютно уникальный и независимый, даже если он был отправлен повторно от одного и того же источника.

Что, если оставить stateless-природу протокола HTTP и не идентифицировать пользователя? Без состояний сеанса можно легко обойтись, если на вашем сайте представлена статичная (обезличенная) информация, например, новостная статья, состоящая из текста и изображений. В таком контексте совершенно необязательно ассоциировать несколько запросов с одним пользователем. Ведь содержание статьи никак не изменится, будь то десять запросов с одного устройства, либо десять запросов от разных людей с разных устройств.

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

Вот как раз в таких ситуациях, когда требуется персонализировать запросы от одного клиента, мы будем использовать сессии.

Сессия (session) - это некоторый отрезок во времени, в пределах которого веб-приложение может определять все запросы от одного клиента.

Когда клиент впервые передает персональные данные в запросе, на сервере создается новая сессия для этого клиента. В период времени жизни сессии все запросы от этого клиента будут однозначно распознаны и связаны с ним. По истечении этого времени связь с клиентом будет потеряна, и очередной запрос от него будет обрабатываться как абсолютно уникальный, никак не связанный с предыдущими.

Например, при совершении покупки в онлайн магазине персональная информация пользователя сохраняется в сессии, пока он путешествует по сайту. Это выбранные товары в корзине, адрес доставки, контактные данные и так далее.

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

  1. скрытые поля на HTML-форме (hidden form fields)
  2. куки (cookies)
  3. сессия (session, session State)

Попробуем их реализовать, используя платформу ASP.NET. Давайте кратко рассмотрим первые два механизма, и особое внимание уделим третьему, как более надежному, удобному и безопасному.

Скрытые поля на HTML-форме (hidden form fields)

Суть данного подхода состоит в том, что мы обеспечиваем навигацию по сайту при помощи стандартных html-форм. И при каждом следующем запросе мы сохраняем данные из предыдущего в скрытых полях на форме. Например:

@using (Html.BeginForm("Forms2", "Home", FormMethod.Post)) {

Заказ блюда

}
public ActionResult Forms2() { ViewBag.UserName = Request.Form["userName"]; return View(); }
@using (Html.BeginForm("Forms3", "Home", FormMethod.Post)) {

@($"Добрый день {ViewBag.UserName}! Что будете заказывать?")

}

В данном примере мы на первой html-форме получаем имя пользователя. Далее в контроллере в методе Forms2() мы извлекаем это значение из коллекции Form и передаем в представление посредством объекта ViewBag . В этом представлении генерируется код новой формы и в скрытом поле сохраняется имя пользователя. Таким образом, значение имени пользователя будет передано уже на третью формы вместе с дополнительной информацией - значением поля с именем "foodName" . И так далее.

Давайте рассмотрим особенности такого подхода. Плюсов практически нет, разве что реализовать данную технику можно очень быстро. Но опять же и другие подходы тоже можно реализовать очень быстро. А вот минусы есть, и довольно существенные:


Куки (cookies)

public ActionResult Cookies2() { HttpCookie cookie = new HttpCookie("userName", HttpUtility.UrlEncode(Request.Form["userName"])); cookie.Expires = DateTime.UtcNow.AddHours(1); Response.Cookies.Add(cookie); return View(); }
@using (Html.BeginForm("Cookies3", "Home", FormMethod.Post)) {

@($"Добрый день {HttpUtility.UrlDecode(Request.Cookies["userName"]?.Value)}! Что будете заказывать?")

}

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

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

Таким образом, передавать первыми двумя способами важные и секретные данные крайне не рекомендуется, такие как логины, пароли, номера карт, счетов, данные паспорта, места жительства и т.д.

Серверный механизм управления сессией (Session, SessionState)

Разберем, как работает механизм сессии со стороны сервера и со стороны клиента.

При стандартных настройках работы состояния сеанса для отслеживания серии запросов от одного клиента используется т.н. сессионная куки (session cookie). Алгоритм следующий:

  1. Абсолютно для каждого нового запроса на сервер (неважно, разные это клиенты или один) ASP.NET генерирует уникальный идентификатор сессии.
    Идентификатор сессии представляет собой случайно сгенерированное число, закодированное с помощью специального алгоритма в строку длиной 24 символа. Строка состоит из литералов от A до Z в нижнем регистре, а также чисел от 0 до 5. Пример идентификатора - hjnyuijl1pam3vox2h5i41in
  2. Если в течение текущего запроса данные клиента НЕ сохраняются для дальнейшей работы с ним, то и время жизни сессии этого клиента заканчивается (фактически не начавшись). При этом ранее сгенерированный идентификатор сессии становится недействительным (так как не был использован). В ответ на такой запрос клиент не получает ничего, чтобы связало его с новой сессией.
  3. Если же данные клиента (например, имя, адрес доставки товара) сохраняются на сервере, ASP.NET связывает сохраненные данные с ранее сгенерированным идентификатором сессии. Далее создается специальная сессионная куки, и в нее записывается также этот идентификатор. Эта куки добавляется в ответ на запрос и сохраняется в браузере клиента. Таким образом, создается связь клиента и его персонализированной информации на сервере. Новая сессия для данного клиента создана.
  4. При каждом следующем запросе клиент передает на сервер персональный идентификатор сессии через куки. Сервер сопоставляет идентификаторы и «узнает» клиента в рамках текущей сессии.
  5. До тех пор пока клиент передает свой персональный ключ, сессия считается активной. Сессия может закончиться по разным причинам, например, вручную на стороне сервера или по истечении какого-то установленного времени (таймаут).

От теории перейдем к практике. Давайте запрограммируем данный алгоритм и посмотрим, как он выполняется. Для этого используем специальный класс HttpSessionState . При работе в контроллере можно воспользоваться свойством HttpContext.Session . Работать с сессией очень просто, как с любой NameValueCollection :

Session["userName"] = Request.Form["userName"]; bool isSessionNew = Session.IsNewSession; string sessionId = Session.SessionID;

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

В браузере клиента можно наблюдать соответствующую куки и идентификатор его сессии:

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

String userName = Session["userName"].ToString(); //обработка запроса... Session.Abandon();

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

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

Item - возвращает элемент данных по его индексу
Item - возвращает элемент данных по его ключу
Remove(index) - удаляет элемент данных по его индексу
Remove(key) - удаляет элемент данных по его ключу
Clear() - удаляет все данные
Count - возвращает общее количество элементов данных для текущей сессии
Abandon() - принудительно завершить сессию
SessionID - возвращает идентификатор текущей сессии
IsNewSession - возвращает true если сессия была создана в рамках текущего запроса
Timeout - возвращает число минут, допустимое между запросами, перед тем как сессия завершится по причине таймаута (по умолчанию, 20 минут)

Изменить настройки для сессии можно либо программно в коде посредством членов класса HttpSessionState , либо через конфигурацию приложения (). Например:

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

И еще одно важное замечание в плане безопасности. Когда вы завершаете сессию пользователя методом Session.Abandon(); сессионная куки, хранящая идентификатор сессии SessionId, в браузере пользователя не удаляется. Это означает, что если пользователь начнет новую сессию в ближайшее время, не закрывая браузер, то его новой сессии будет присвоен тот же SessionId. Желательно каждой новой сессии всегда присваивать новый уникальный идентификатор, для этого нам нужно вручную удалять сессионную куки после закрытия сессии:

Session.Clear(); //очищаем сессию Session.Abandon(); //отменяем сессию //вручную очищаем куки так Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", "")); //или сокращаем время жизни Response.Cookies["ASP.NET_SessionId"].Expires = DateTime.Now.AddYears(-30); //ASP.NET_SessionId - это стандартное название сессионной куки, у вас может быть свое

Вот таким образом происходит отслеживание состояния сеанса пользователя на платформе ASP.NET, с использованием сессий. Этот подход является стандартом и рекомендуется к использованию, когда необходимо сохранять информацию о пользователе и идентифицировать его между запросами на сервер.

Сессии - это на самом деле очень просто. Надо только понимать, для чего они нужны и как устроены. Ответим сначала на первый вопрос.
Возможно Вы знаете, что веб-сервер не поддерживает постоянного соединения с клиентом, и каждый запрос обрабатывается, как новый, без связи с предыдущими.

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

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

В принципе, довольно несложно сделать собственный аналог сессий, не такой функциональный, как встроенный в PHP, но похожий по сути. На cookies и базе данных.

При запросе скрипта смотрим, пришла ли cookies с определенным именем. Если cookies нет, то ставим ее и записываем в базу новую строку с данными пользователя. Если cookies есть, то читаем из базы данные. Еще одним запросом удаляем из базы старые записи и вот у нас готов механизм сессий. Совсем несложно. Но есть некоторые нюансы, которые делают предпочтительным использование именно встроенного механизма сессий.

Для начала надо как-то идентифицировать браузер. Для этого надо выдать ему уникальный идентификатор и попросить передавать его с каждым запросом. Стыдно признаться, но когда я впервые узнал о сессиях, я думал, что это какой-то особый механизм, некий новый способ общения браузера с сервером - "сессии". Что идентификатор сессии передается каким-то особым образом. Но, разочарование было жестоким...

Сессии используют стандартные, хорошо известные способы передачи данных. Собственно, других-то просто и нет.
Идентификатор - это обычная переменная. По умолчанию ее имя - PHPSESSID.
Задача PHP отправить ее браузеру, чтобы тот вернул ее со следующим запросом. Из уже упоминавшегося раздела FAQ ясно, что переменную можно передать только двумя способами: в cookies или POST/GET запросом.
PHP использует оба варианта.

За это отвечают две настройки в php.ini:

session.use_cookies - если равно 1, то PHP передает идентификатор в cookies, если 0 - то нет.
session.use_trans_sid если равно 1, то PHP передает его, добавляя к URL и формам, если 0 - то нет.

Менять эти и другие параметры сессий можно так же, как и другие настройки PHP - в файле php.ini, а так же с помощью команды ini_set() или в файлах настройки веб-сервера

Если включена только первая, то при старте сессии (при каждом вызове session_start () ) клиенту устанавливается cookies. Браузер исправно при каждом следующем запросе эту cookies возвращает и PHP имеет идентификатор сессии. Проблемы начинаются, если браузер cookies не возвращает. В этом случае, не получая cookies с идентификатором, PHP будет все время стартовать новую сессию, и механизм работать не будет.

Если включена только вторая, то cookies не выставляется. А происходит то, ради чего, в основном, собственно, и стоит использовать встроенный механизм сессий. После того, как скрипт выполняет свою работу, и страница полностью сформирована, PHP просматривает ее всю и дописывает к каждой ссылке и к каждой форме передачу идентификатора сессии. Это выглядит примерно так:

Index

превращается в

Index

а к формам добавляется скрытое поле

Теоретически, в наших с вами самодельных сессиях на cookies и базе, можно самому, руками приписать ко всем ссылками передачу ид - и тогда наши собственные сессии будут работать независимо от cookies. Но, согласитесь - приятнее, когда эту работу делает кто-то другой? ;-)

По умолчанию в последних версиях PHP включены обе опции. Как PHP поступает в этом случае? Кука выставляется всегда. А ссылки автодополняются только если РНР не обнаружил cookies с идентификатором сессии. Когда пользователь в првый раз за этот сеанс заходит на сайт, ему ставится cookies, и дополняются ссылки. При следующем запросе, если cookies поддерживаются, PHP видит cookies и перестает дополнять ссылки. Если cookies не работают, то PHP продолжает исправно добавлять ид к ссылкам, и сессия не теряется.
Пользователи, у которых работают cookies, увидят длинную ссылку с ID только один раз.

С передачей идентификатора закончили. Теперь осталось привязать к нему файл с данными на стороне сервера. PHP это сделает за нас. Достаточно просто написать:

session_start ();
$_SESSION [ "test" ]= "Hello world!" ;

И PHP запишет в файл, связанный с этой сессией, переменную test.

Здесь очень важное замечание.

Массив $_SESSION - особенный.
В нем, собственно, и находятся переменные, которые мы ходим сделать доступными в различных скриптах.
Чтобы поместить переменную в сессию, достаточно присвоить ее элементу массива $_SESSION.
Чтобы получить ее значение - достаточно обратиться к тому же элементу. Пример будет чуть ниже.

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

session_start ();

echo "Вы обновили эту страницу " . $_SESSION [ "counter" ]++. " раз. " ;
echo "
обновить" ;
?>

Мы проверяем, есть ли у нас в сессии переменная counter, если нет, то создаем ее со значением 0, а дальше выводим ее значение и увеличиваем на единицу. Увеличенное значение запишется в сессию, и при следующем вызове скрипта переменная будет иметь значение 1, и так далее. Все очень просто.

Для того, чтобы иметь доступ к переменным сессии на любых страницах сайта, надо написать ТОЛЬКО ОДНУ(!) строчку в самом начале КАЖДОГО файла, в котором нам нужны сессии:

session_start ();

session_start ();
if ($_SESSION [ "authorized" ]<> 1 ) {
header ("Location: /auth.php" );
exit;
}

Удаление переменных из сессии. Если у вас register_globals=off , то достаточно написать

unset($_SESSION [ "var" ]);

Если же нет, то тогда рядом с ней надо написать:

session_unregister ("var" );

Очень важно понимать, для чего сессии стоит использовать, а для чего - нет.

Во-первых, помните, что сессии можно применять только тогда, когда они нужны самому пользователю, а не для того, чтобы чинить ему препятствия. Ведь он в любой момент может избавиться от идентификатора!
Скажем, при проверке на то, что заполняет форму человек, а не скрипт, пользователь сам заинтересован в том, чтобы сессия работала - иначе он не сможет отправить форму! А вот для ограничения количества запросов к скрипту сессия уже не годится - злонамеренный скрипт просто не будет возвращать идентификатор.

Во-вторых. Важно четко себе представлять тот факт, что сессия - это сеанс работы с сайтом, так как его понимает человек. Пришел, поработал, закрыл браузер - сессия завершилась. Как сеанс в кино. Хочешь посмотреть еще один – покупай новый билет. Стартуй новый сеанс. Этому есть и техническое объяснение. Гарантированно механизм сессий работает только именно до закрытия браузера. Ведь у клиента могут не работать cookies, а в этом случае, естественно, все дополненные идентификатором ссылки пропадут с его закрытием.

Правда, сессия может пропасть и без закрытия браузера. В силу ограничений, рассмотренных в этой статье, механизм сессий не может определить тот момент, когда пользователь закрыл браузер. Для этого используется таймаут – заранее определенное время, по истечении которого мы считаем, что пользователь ушел с сайта. По умолчанию этот параметр равен 24 минутам.

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

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

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

К тому же, возьмем поисковик, который индексирует ваш сайт. Если поисковый робот не поддерживает cookies, то PHP по умолчанию будет поставлять к ссылкам PHPSESSID, что может не сильно понравится поисковику, который, по слухам, и так-то динамические ссылки не жалует, а тут вообще при каждом заходе - новый адрес!

Если сессии используются для ограничения доступа к закрытому разделу сайта, то все просто поисковик и не должен его индексировать. Если же приходится показывать одну и ту же страницу как авторизованным, так и не авторизованным пользователям, то тут поможет такой трюк – стартовать сессию только тем, кто ввел пароль, или тем, у кого уже стартовала сессия.

Для этого в начало каждой страницы вместо просто session_start () пишем:

if (isset($_REQUEST [ session_name ()])) session_start ();

таким образом, Мы стартуем сессию только тем, кто прислал идентификатор.
Соответственно, надо еще в первый раз отправить его пользователю – в момент авторизации.

Если имя и проль верные – пишем session_start () !

Самыми распространенными ошибками, которые выдает РНР при попытке работать с сессиями, являются такие:
Две из них,

Warning: Cannot send session cookie - headers already sent
Warning: Cannot send session cache limiter - headers already sent

вызваны одной и той же причиной, решение описано в этом факе

Warning: open(/tmp\sess_SID, O_RDWR) failed: No such file or directory (2) in full_script_path on line number

ранее она выглядела, как

Warning: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/tmp) ,

если перевести ее с английского, подробно объясняет проблему: недоступен указанный в php.ini путь к каталогу, в который пишутся файлы сессий. Эту ошибку исправить проще всего. Просто прописать каталог, который существует, и доступен на запись, например,

session.save_path = c:\windows\temp

И не забыть перезагрузить Apache после этого.

Как выясняется, сообразительность людская не имеет пределов, и поэтому я вынужден пояснить:
сообщение о третьей ошибке (невозможно найти каталог) НЕИЗБЕЖНО приведет к появлению первых двух, поскольку сообщение об ошибке - это вывод в браузер и после него заголовками пользоваться нельзя. Поэтому не спешите искать преждевременный вывод, а сначала пропишите правильный путь!

Следующей по распространенности проблемой при работе с сессиями является тяжелое наследие register_globals. НЕ давайте переменным скрипта имена, совпадающие с индексами массива $_SESSION!

При register_globals=on значения будут перезаписывать друг друга, и вы запутаетесь.

Если не работает, но и никаких сообщений не выводится, то добавьте в самое начало скрипта две строчки, отвечающие за вывод ВСЕХ ошибок на экран - вполне возможно, что ошибки есть, но вы их просто не видите.

ini_set ("display_errors" , 1 );
error_reporting (E_ALL );

или смотрите ошибки в error_log. Вообще, тема отображения сообщений об ошибках выходит за рамки данной статьи, поэтому просто убедитесь хотя бы, что вы можете их видеть. Чуть продробнее о поиске ошибок можно прочитать в этом разделе .

Если вы уверены, что ошибок нет, но приведенный пример не работает все равно, то, возможно, в PHP не включена передача ид через урл, а cookies по каким-то причинам не работают .
Смотрите, что у вас с cookies.

Вообще, если у вас "не работают" сессии, то сначала попробуйте передать идентификатор сессии руками, то есть, сделать ссылку и приписать к ней идентификатор:

session_start ();
if (!isset($_SESSION [ "counter" ])) $_SESSION [ "counter" ]= 0 ;
echo "Вы обновили эту страницу " . $_SESSION [ "counter" ]++. " раз.

обновить" ;
?>

При этом следует убедится, что не включена директива session.use_only_cookies , которая запрещает PHP принимать идентификатор сессии, если он был передан через URL

Если этот пример не заработает, то проблема либо в банальных опечатках (половина "проблем" с сессиями происходит от неправильно написанного имени переменной), либо в слишком старой версии PHP: поддержка сессий появилась в версии 4.0, а массив $_SESSION - в 4.1 (До этого использовался $HTTP_SESSION_VARS ).

Если же заработает - то проблема в cookies. Отслеживайте - что за cookies ставит сервер браузеру, возвращает ли браузер ее. Искать очень полезно, просматривая просматривая обмен HTTP-заголовками между браузером и сервером.

Объяснение принципа работы cookies выходит за рамки этого и так уж слишком большого текста, но хотя бы убедитесь, что сервер cookies с идентификатором посылает, а браузер - возвращает. И при этом идентификаторы совпадают друг с другом =)
Установка cookies должна выглядеть, как

Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6;

Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; path=/

(если вы запрашиваете скрипт не из корневого каталога)
Ответ сервера должен выглядеть, как

Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6

Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; b=b

если браузер возвращает другие cookies, кроме идентификатора сессии.

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

Еще одна проблема может возникнуть, если вы используете перенаправление через header или навигацию с помощью JavaScript.
Дело в том, что РНР автоматически дописывает идентификатор сессии только к ссылкам вида
, но не делает этого для header-ов, яваскрипта, мета-тегов.

Поэтому надо добавлять идентификатор руками, например, так:

header ("Location: /script.php?" . session_name (). "=" . session_id ());

Так же, весьма редкая, и совершенно непонятно, откуда появляющаяся, проблема бывает в том, что настройка session.save_handler имеет значение, отличное от files. Если это не так - исправляйте.

  • Кроме cookies, механизм сессий посылает еще и заголовки, запрещающие кэширование страниц (тот самый cache limiter). Для html это правильно и необходимо. Но вот когда вы пытаетесь скриптом, проверяющим авторизацию, отдать файл, то интернет эксплорер отказывается его скачивать. Именно из-за этого заголовка. Вызов
    session_cache_limiter ("private" );
    перед стартом сессии должен решить проблему.
  • Как это ни кажется странным, но в массиве $_SESSION нельзя использовать числовые индексы - $_SESSION [ 1 ], $_SESSION [ "10" ] - cессии работать не будут.
  • Где-то между версиями 4.2 и 5.0 невозможно было установить session.use_trans_sid с помощью ini_set () . Начиная с 5.0 уже можно снова.
  • До версии 4.3.3 cookies PHP отправлял cookies только если при старте сессии в запросе отсутстввал идентификатор. Теперь же cookies посылается при каждом вызове session_start

    Есть еще вопросы или что-то непонятно - добро пожаловать на наш

Как уже известно, протокол HTTP позволяет веб-приложениям устанавливать "сессии" - диалог между клиентом и сервером, причём состояние этого диалога сохраняется от запроса к запросу.

Язык PHP, являясь в основном языком для веб-программирования, предоставляет возможность пользоваться механизмом сессий HTTP, беря на себя большую часть забот при организации и хранении данных сессий. Напомню, что необходимо для работы механизма сессий HTTP:

  • Сервер должен сгенерировать уникальный номер сессии.
  • Номер сессии должен быть передан клиенту (обычно посредством Cookies).
  • Сервер должен уметь сохранять данные сессии в файлах или в базе данных, так чтобы их можно было восстановить, зная номер сессии, который клиент присылает серверу при последующих запросах (тоже посредством Cookies).

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

  • Проверяет, не прислал ли клиент номер уже существующей сессии в Cookie или в параметрах запроса. Если клиент прислал номер сессии, то данные этой сессии загружаются из места постоянного хранения (например, файла) в память, и становятся доступны программе через массив $_SESSION. Если клиент не прислал номера сессии или такой сессии не существует на сервере - создаётся новая сессия с новым номером, а её данные также доступны через массив $_SESSION, который в случае новой сессии будет пустым. Номер вновь созданной сессии помещается в поле заголовка ответа сервера Set-Cookie.
  • Обеспечивает сохранение данных сессии. После того, как PHP-программа обработала запрос, текущее состояние массива $_SESSION сохраняется в месте постоянного хранения, чтобы вновь стать доступным при следующем запросе клиента.

Теперь, зная подробности, которые скрываются за session_start(), можем поиграть с этим механизмом. Пример ниже хранит в сессии одно число, которое увеличивается на единицу с каждым запросом клиента:

При первом заходе на эту страничку, сервер пришлёт браузеру куки с номером сессии:

Set-Cookie : PHPSESSID=4ftvca7jmmnm04q95r3sdsk6r6; path=/

И этот же номер сессии браузер будет отправлять обратно серверу при каждом последующем запросе. Теперь, если в браузере очистить куки, на сервере будет создана новая сессия с другим номером, и счёт в нашем тестовом скрипте начнётся заново.

Более реальный пример: логин пользователя

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

array("password" => "123", "title" => "Администратор",), "user" => array("password" => "qwe", "title" => "Пользователь",),); return isset($users[$login])? $users[$login]: null; } function getCurrentUser() { $user = isset($_SESSION["user"])? $_SESSION["user"]: null; return $user; } function setCurrentUser($user) { $_SESSION["user"] = $user; } ?>

Привет, !
Ссылка1 Ссылка2

Выйти Вы еще не зашли на сайт. Введите логин и пароль:
Логин: Пароль:

Эта программка запрашивает логин и пароль, причём можно войти с логином user , qwe или admin , 123 . Залогиненному пользователю показывается приветствие. При логине отображается сообщение, если имя пользователя или пароль указаны неверно.

Как только удалось зайти на этот "сайт", можно покликать по ссылкам (Ссылка1, Ссылка2), оставаясь при этом залогиненным пользователем.

Какие данные можно хранить в сессии?

По умолчанию PHP хранит данные сессии во временном файле в виде текста. В этом можно убедиться, заглянув в директорию с временными файлами PHP. Эта директория указана в phpinfo() в разделе Environment, TEMP. В этой директории вы найдёте файлы вида sess_4ftvca7jmmnm04q95r3sdsk6r6 , где 4ftvca7jmmnm04q95r3sdsk6r6 - номер сессии, переданный в Cookie. Загляните в этот файл: если вы запустили самый первый пример выше, то в файле обнаружится примерно такое содержимое: "value|i:2;". Этот текст представляет собой сериализованное представление содержимого сессии, где хранится всего лишь одна переменная с числом.

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

К счастью, в PHP сериализовать можно не только простые значения вроде чисел и строк, но так же и сложные структуры вроде массивов и объектов:

"; print_r($_SESSION); echo ""; $_SESSION["testArray"] = array(1, 2, 3, "one", "two", "three", "child" => array(5, 6, 7),); $obj = new stdClass(); $obj->x = 1234; $obj->y = 4567; $_SESSION["testObject"] = $obj;

Этот пример запишет в файл сессии такие данные:

TestArray|a:7:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;s:3:"one";i:4;s:3:"two";i:5;s:5:"three";s:5:"child";a:3:{i:0;i:5;i:1;i:6;i:2;i:7;}}testObject|O:8:"stdClass":2:{s:1:"x";i:1234;s:1:"y";i:4567;}

Хранение объектов в сессии

В сессии, как видно, можно хранить объекты. Но при этом следует помнить, что сохраняя в сессии объекты, ссылающиеся каким-либо образом на ваши "самодельные" классы, или объекты-экземпляры ваших классов, необходимо, чтобы объявление этих классов делалось до момента вызова session_start(). То есть, PHP должен знать класс до того, как встретит упоминание о нём при десериализации данных сессии.

При сохранении объектов бывают ситуации, когда стандартная сериализация объекта по каким-либо причинам неприемлема или вовсе невозможна. В таких случаях можно реализовать сериализацию вручную, объявив в классе "волшебные" методы __sleep() и __wakeup() .

Кстати , сериализацию возможно осуществлять и "вручную", причём не обязательно для сохранения/загрузки данных сессии. Понадобиться это может, когда некоторые данные в приложении надо сохранить для использования позже, или передать по сети. Функции, которые могут пригодиться при сериализации/десериализации - serialize() , unserialize() , json_encode() , json_decode() .

Что нельзя хранить в сессии?

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

Дополнительные возможности

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

Для ускорения процесса сохранения и загрузки данных сессии на высоко нагруженных сайтах может использоваться сервер Memcached, который хранит данные в памяти. Поддержка этого способа хранения сессий встроена в PHP и настраивается через файл конфигурации php.ini.

Можно задать имя параметра Сookie, через который передаётся номер сессии, указав его имя, время жизни, домен и другие параметры.

Эти и многие другие возможности настройки сессий HTTP в PHP доступны через функции session_*.

Мы рассмотрели принцип работы с куки в PHP. Назначение сессий практически такое же - сохранение некоторых данных после завершения работы скрипта для последующего использования. Однако, у двух этих методов есть существенное различие. Куки хранятся на стороне клиента и поэтому пользователь может без труда прочитать и даже изменять их. Допустим, на нашем сайте существует форма авторизации. Войдя под администраторской учетной записью пользователь получает дополнительные привилегии на сайте, к примеру, доступ к администраторской панели. Чтобы после каждого перехода пользователю не вводить заново пароль, необходимо каким-то образом запомнить факт того, что данный пользователь авторизован с административными правами. Используя куки задача решается следующим образом: после удачной авторизации пользователю устанавливается некая куки admin=1 . При серфинге по страницам сайта проверяемся, есть ли у пользователя данная куки. Если есть, то пользователь - администратор. С точки зрения безопасности такое решение является в корне неправильным, так как любой посетитель может самостоятельно добавить в своем браузере куки admin=1 и автоматически стать администратором на вашем сайте. Используя сессии такой номер не пройдет, потому что сессионные параметры хранятся на стороне веб-сервера.

Рассмотрим принцип работы сессий в PHP. Для инициализации новой или возобновления ранее созданной необходимо вызвать PHP-функцию session_start() . Данную функцию необходимо вызывать до вывода контента в коде. Сессионные параметры находятся в глобальном массиве $_SESSION . Рассмотрим пример:

session_start () ; if ( ! isset ($_SESSION [ "test" ] ) ) { echo "Сохраняем значение...
"
; $_SESSION [ "test" ] = "Hello, world" ; } echo $_SESSION [ "test" ] ;

При первом выполнении скрипта создастся новая сессия функцией session_start() . Условие выполнится, так как сессионной переменной test не существует и при этом будет создана данная сессионная переменная. При последующих выполнениях функция session_start() будет возобновлять ранее созданную сессию, условие выполняться не будет, а будет лишь выводиться значение переменной test.

При создании сессии PHP создает специальный временный файл, в котором хранит сессионные переменные. Для каждой сессии создается отдельный файл. Чтобы определить, какая сессия к какому клиенту относится, при создании сессии клиенту устанавливается куки вида:

PHPSESSID=

Это так называемый идентификатор сессии . Существует также способ передачи идентификатора сессии в GET-параметрах, но данный способ я считаю слишком устаревшим. Имя параметра можно изменить в конфигурационном файле PHP php.ini:

Session.name = PHPSESSID

По умолчанию сессия уничтожается при закрытии клиентом браузера. Но можно задать и конкретное время жизни сессии в php.ini (указывается время в секундах):

Session.cookie_lifetime = 0

В скрипте сессию можно принудительно уничтожить функцией session_destroy() .

И напоследок рассмотрим еще один пример. Небольшой скрипт, эмулирующий авторизацию пользователя на сайте. Формы ввода логина и пароля нет, есть просто две кнопки "войти" и "выйти".

//--Создаем новую либо возобновляем созданную сессию session_start () ; //--Процедуры входа и выхода if ( isset ($_POST [ "do" ] ) ) { if ( $_POST [ "do" ] == "login" ) { $_SESSION [ "logined" ] = "yes" ; header ("location: " . $_SERVER [ "PHP_SELF" ] ) ; exit () ; } if ( $_POST [ "do" ] == "logout" ) { session_destroy () ; header ("location: " . $_SERVER [ "PHP_SELF" ] ) ; exit () ; } } //--Форма авторизации $login_form = << END ; //--Форма выхода $logout_form = << END ; //--Если пользователь авторизован if ( isset ($_SESSION [ "logined" ] ) && $_SESSION [ "logined" ] == "yes" ) { echo "Приветствуем Вас, авторизованный пользователь!
"
; //--Выводим форму выхода echo $logout_form ; } else { echo "Приветствуем Вас, гость!
"
; //--Выводим форму выхода echo $login_form ; } ?>

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

Что такое сессия? Сессии позволяют сделать своего рода связь между самим сайтом и пользователем, при помощи идентификатора сессии. Все переменные сессии и их значения хранятся исключительно на сервере. У пользователя, а также на сервере хранятся только идентификаторы сессии, которые генерируются рандомным образом, они как раз таки и позволяют установить эту самую связь сервер - клиент.

Идентификатор сессии, хранящийся на стороне клиента (на его компьютере) - это файл cookie . Куки хранятся в браузере пользователя, но при этом файл соответствующий создается также и на сервере.

Давайте перейдем непосредственно к практике.

Создаем сессию:

Самый элементарный способ здесь, применить функцию session_start:

1 2 // Запустить сессию session_start () ;

// Запустить сессию session_start();

Данная функция проверяет, есть ли идентификатор сессии, если его нет, то создает его. А если же, он имеется, то загружает зарегистрированные переменные из имеющейся сессии.

Такая конструкция должна быть вызвана только один раз для каждой страницы и до любого вывода (данное правило также подходит и для setcookie()).

Приведу пример, когда сессия создается в браузере, то кука там имеет следующий вид

Когда создается сессия в браузер ‛прилетает“ кука следующего вида:

1 2 echo "Название сессии: " . session_name () . " Идентификатор сессии: " . session_id () ; // Название сессии: PHPSESSID Идентификатор сессии: mceu371l97id3sa0vcbjqnht06

echo "Название сессии: ".session_name(). " Идентификатор сессии: ".session_id(); // Название сессии: PHPSESSID Идентификатор сессии: mceu371l97id3sa0vcbjqnht06

Создадим переменную сессии:

Переменную сессии можно создать добавив какое-то значение суперглобальному элементу массива $_SESSION:

unset($_SESSION["login"]);

Способ выше хорош, но можно очистить весь массив $_SESSION , тем самым мы удалим все переменные из сессии:

1 2 // Чистим наш массив $_SESSION $_SESSION = array () ;

// Чистим наш массив $_SESSION $_SESSION = array();

2. Теперь нам необходимо сделать файл куки недействительным (где имя сессии ссылается при обращении на session id в куках и URL):

1 2 3 if (isset ($_COOKIE [ session_name () ] ) ) { // session_name() - вытаскиваем название текущей сессии setcookie (session_name () , "" , time () - 86400 , "/" ) ; }

if (isset($_COOKIE)) { // session_name() - вытаскиваем название текущей сессии setcookie(session_name(), "", time()-86400, "/"); }

3. Ну и следом уничтожим сессию (закроем её):

session_start(); ob_start();

Вот более подробный пример кода с использованием ранее рассмотренных кодов и функций:

1 2 3 4 5 6 7 8 9 if (isset ($_SESSION [ "login" ] ) ) { echo "Привет, " . $_SESSION [ "name" ] . " " ; unset ($_SESSION [ "login" ] ) ; if (isset ($_COOKIE [ session_name () ] ) ) { setcookie (session_name () , "" , time () - 86400 , "/" ) ; // содержимым нашей сессии является пустая строка } ob_end_flush () ; // Отправляем браузеру вывод session_destroy () ;

if (isset($_SESSION["login"])) { echo "Привет, " . $_SESSION["name"] . " "; unset($_SESSION["login"]); if (isset($_COOKIE)) { setcookie(session_name(), "", time()-86400, "/"); // содержимым нашей сессии является пустая строка } ob_end_flush(); // Отправляем браузеру вывод session_destroy();

Однако стоит обратить внимание, что использование функции ob_end_flush() не всегда является обязательным. А всё потому что интерпретатор PHP автоматически чистит ваш буфер при выполнении какого-то сценария.

Пересоздадим идентификатор сессии:

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

Принцип работы сессий:

На скриншоте ниже вы можете узреть небольшой обзор самого механизма сессий.

Уменьшим время жизни сессии:

Стандартное значение времени жизни сессии равно 0, а именно, если пользователь закроет окно браузера, то сессия закроется тоже. Но возникает иногда необходимость уничтожить сессию клиента принудительно по истечению какого-то времени, например из-за не активности с его стороны на сайте. Разберем способ подобной реализации на примере aвторизации пользователя: мы создадим какую-то переменную и сохраним в ней время используемое при авторизации пользователя, к примеру если пользователь попытается обносить страницу, то мы сравниваем время с тем временем, которое он был неактивен, и в случае превышения данного лимита он будет разлогинен и отправлен на страницу авторизации.

1 2 3 4 5 6 7 8 $_SESSION [ "start" ] = time () ; // Начало времени, когда пользователь авторизовался $timezon = time () ; // Данное время (то которое есть сейчас) $time_limit = 2000 ; // Это максимальное время не активности пользователя if ($timezon & gt; $_SESSION [ "start" ] + $time_limit ) { echo "Время закончилось" ; } else { $_SESSION [ "start" ] = time () ; } // если всё хорошо, то обновляем

$_SESSION["start"] = time(); // Начало времени, когда пользователь авторизовался $timezon= time(); // Данное время (то которое есть сейчас) $time_limit = 2000; // Это максимальное время не активности пользователя if ($timezon> $_SESSION["start"] + $time_limit) { echo "Время закончилось"; } else {$_SESSION["start"] = time();} // если всё хорошо, то обновляем

Иногда возникает у людей вопрос "Как реализовать бесконечное время жизни сессии?" , тут ответ я дам вам такой. Этого не стоит делать, это в корне идеи уже есть не правильно. Сессия на то и дана, чтобы пользователь зашел на сайта - она открылась, он ушел - она закрылась (уничтожилась). Когда он опять зашел сессия открылась новая. Однако можно использовать для сессии данные из куки, которые могут храниться достаточно долго, к примеру при использовании галочки "Запомнить меня" (Помните ведь такую на сайтах?)...

Используем сессии при отключенном cookie:

Скажите такого не бывает? Увы и такое иногда встречается. Например если для настройки session.use_trans_sid мы установим значение 1 , то при отсутствии использования cookie, PHP будет передавать параметры PHPSESSID с использованием GET метода в вашей строке запроса.

Вот и всё, статья закончена. Если у вас еще остались вопросы касательно использования сессий, а может есть какие-то дополнения или замечания, то можете оставить всё в комментариях к данной статье.



Понравилась статья? Поделиться с друзьями: