Механизм сессий в PHP. Сессии в PHP

Автор: V. Nagaradjane
Перевод: А.Панин

Сессии на основе кук

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

Таблица 1: Функции PHP для управления сессиями

Стандартный процесс создания сессии начинается с вывода страницы с двумя полями ввода для имени пользователя и пароля. Следующий HTML-код используется для формирования страницы входа в систему (внешний вид этой страницы показан на Рисунке 3):

Login


Рисунок 3: Страница входа в систему

Вход в систему

Имя пользователя и пароль передаются сценарию PHP с именем login.php . Этот сценарий использует глобальную переменную $_POST для получения строк, введенных в поля имени пользователя и пароля. После этого устанавливается соединение с базой данных "session" и из нее извлекаются соответствующие имени пользователя идентификатор пользователя и пароль. Если имя пользователя обнаруживается, пароль, хранимый в базе данных, сравнивается с паролем, введенным пользователем. Если пароли не совпадают, попытка входа в систему отклоняется. В противном случае осуществляется вход. Ниже представлен код сценария login.php :

User %s not found


Go to login page
", $username); return false; } if(mysql_result($result, 0, "pass") != $password) { printf("

Login attempt rejected for %s!


Go to login page
", $username); return false; } session_start(); $_SESSION["username"] = $username; $_SESSION["id"] = mysql_result($result,0,"id"); mysql_close($conn); return true; } if(check_login($_POST["username"], $_POST["passwd"])) printf("

Welcome %s!



n",$_SESSION["username"]); print("Check status!
View Protected Image
Logout
n"); ?>

В случае, если имя пользователя и пароль корректны, вызывается функция session_start() , которая в свою очередь отправляет куки с идентификатором сессии пользователя клиенту. Данные кук показаны на Рисунке 4. После этого становится возможным доступ к данным с помощью вызовов $_SESSION["username"] или $_SESSION["id"] для получения или сохранения данных сессии. В данном случае в массиве $_SESSION сохраняются имя и идентификатор пользователя.


Рисунок 4: Куки сессии (PHPSESSID) показаны в списке кук браузера Firefox

Созданный с помощью функции session_start() идентификатор сессии хранится в куках на машине клиента. Вы можете исследовать куки, воспользовавшись пунктами меню Firefox "Правка->Настройки", выбрав вкладку "Приватность" и нажав на ссылку "удалить отдельные куки". После этого будет выведен список кук, отсортированный по имени сервера. В данном случае в качестве имени сервера используется адрес 127.0.0.1 и в качестве имени переменной кук используется строка "PHPSESSID" - вы можете заметить ее в поле "Содержимое" ("Content") в области вывода информации. Страница приветствия, показанная после входа в систему, изображена на Рисунке 5.


Рисунок 5: Страница приветствия, выводящаяся после успешного входа

Состояние сессии

После открытия сессии вы можете проверить постоянство значений имени и идентификатора пользователя. Давайте создадим для этого небольшой сценарий с именем status.php . Этот сценарий вызывает функцию session_start() . Так как куки сессии доступны на клиентской машине, при вызове функции session_start() происходит получение идентификатора сессии и загрузка соответствующих переменных сессии вместе с их значениями на стороне сервера. Следовательно, вызов $_SESSION["username"] или $_SESSION["id"] вернет данные, сохраненные в файле сценария login.php . Сценарий status.php выглядит следующим образом:

invalid session!


nLogin"); exit(); } printf("
Welcome %s! Your id is: %d",$_SESSION["username"],$_SESSION["id"]); printf("
Logout %s
",$_SESSION["username"]); ?>

Этот сценарий проверки состояния доступен при переходе по ссылке с именем "Check Status!" на странице приветствия. Он выводит имя и идентификатор пользователя, полученные из массива данных сессии. Таким образом, выполняется основное требование, предъявляемое к сессиям и заключающееся в постоянстве данных при переходе между различными страницами после входа в систему.

Создание защищенных страниц

Главной целью механизма сессий является создание защищенных страниц. Простой сценарий PHP, приведенный ниже, позволяет защитить изображения от публичного доступа. Файл сценария protectedimage.php вызывает функцию require_once("status.php") в самом начале. С помощью нее происходит однократное исполнение сценария проверки состояния. Сценарий проверки состояния проверяет работоспособность сессии и позволяет выполнение последующих функций в случае действительной сессии, либо прекращает работу сценария в ином случае. Код для защиты изображения показан ниже:

"); ?>

Защищенное изображение, которое выводится после корректного открытия сессии, показано на Рисунке 6, а на Рисунке 7 показана та же самая страница (http://127.0.0.1/protectedimage.php ), загруженная без предварительного открытия сессии. Посмотрите на URL в адресной строке браузера на обоих рисунках - страница с одним и тем же URL содержит картинку в случае доступных данных сессии и запрещает доступ к картинке если данные сессии недоступны.


Рисунок 6: Картинка является защищенным содержимым страницы


Рисунок 7: Доступ к защищенному содержимому страницы запрещен если данные сессии недоступны

Завершение сессий

Теперь, когда мы разобрались в том, как осуществляется защита содержимого страниц, самое время рассмотреть операцию закрытия сессии. Операция закрытия сессии реализована в сценарии с именем logout.php . Сценарий вызывает функцию session_destroy() , которая удаляет куки и переменные сессии. Страница завершения сессии показана на Рисунке 8. Сценарий завершения сессии выглядит следующим образом:

Good Bye %s!


Go to login page!
Get Statusn",$_SESSION["username"]); session_destroy(); ?>


Рисунок 8: Страница завершения сессии

Мы можем проверить, действительно ли сессия завершилась, вызвав файл status.php и узнав в том, доступны ли все еще имя и идентификатор пользователя. Сообщение, приведенное на Рисунке 9, указывает на то, что сессия недействительна. Имя и идентификатор пользователя недоступны после завершения сессии. Следовательно, включение сценария status.php в начало каждой защищенной страницы позволяет быть уверенным в том, что доступ к странице будет возможен только после корректного входа в систему, в противном случае все запросы с данным URL будут завершены в самом начале сценария.


Рисунок 9: Сообщение о состоянии сессии после ее завершения

Достоинства и недостатки механизма управления сессиями на основе кук

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

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

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

И браузер при клике на любую ссылку, или при нажатии на кнопку в форме, пошлет в запросе нужную нам переменную - идентификатор сессии!
По очевидным причинам идентификатор добавляется только к относительным ссылкам.

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

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

Фух. С передачей идентификатора закончили.
Теперь осталось привязать к нему файл с данными на стороне сервера.
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. Например, проверка авторизации будет выглядеть примерно так:
session_start ();
if ($_SESSION [ "authorized" ]<> 1 ) {
header ("Location: /auth.php" );
exit;
}

Удаление переменных из сессии.
Если у вас register_globals=off , то достаточно написать
unset($_SESSION [ "var" ]);
Если же нет, то тогда рядом с ней надо написать
session_unregister ("var" );

Самыми распространенными ошибками, которые выдает РНР при попытке работать с сессиями, являются такие:
Две из них,
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
И не забыть перезагрузить апач после этого.

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

Следующей по распространенности проблемой при работе с сессиями является тяжелое наследие register_globals. НЕ давайте переменным скрипта имена, совпадающие с индексами массива $_SESSION!
При register_globals=on значения будут перезаписывать друг друга, и вы запутаетесь.
А при register_globals=off появится другая ошибка: "Your script possibly relies on a session side-effect which existed until PHP 4.2.3.", в случае, если в скрипте есть переменная сессии не имеющая значения, и глобальная переменная с тем же именем. Чтобы от неё избавиться, надо всегда инициализировать переменные перед использованием (или хотя бы проверять на существование) и не давать глобальным переменным имена, совпадающие с индексами массива $_SESSION.

Если не работает, но и никаких сообщений не выводится, то добавьте в самое начало скрипта две строчки, отвечающие за вывод ВСЕХ ошибок на экран - вполне возможно, что ошибки есть, но вы их просто не видите.
ini_set ("display_errors" , 1 );
error_reporting (E_ALL );

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

Если вы уверены, что ошибок нет, но приведенный пример не работает все равно, то, возможно, в PHP не включена передача ид через урл, а куки по каким-то причинам не работают .
Смотрите, что у вас с куками.
Вообще, если у вас "не работают" сессии, то сначала попробуйте передать идентификатор сессии руками, то есть, сделать ссылку и приписать к ней идентификатор:
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 ).
Если же заработает - то проблема в куках. Отслеживайте - что за куку ставит сервер браузеру, возвращает ли браузер ее. Искать очень полезно, просматривая просматривая обмен HTTP-заголовками между браузером и сервером.
Объяснение принципа работы кук выходит за рамки этого и так уж слишком большого текста, но хотя бы убедитесь, что сервер куку с идентификатором посылает, а браузер - возвращает. И при этом идентификаторы совпадают друг с другом =)
Установка куки должна выглядеть, как
Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6;
или как
Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; path=/
(если вы запрашиваете скрипт не из корневого каталога)
Ответ сервера должен выглядеть, как
Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6
либо
Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; b=b
если браузер возвращает другие куки, кроме идентификатора сессии.

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

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

Еще одна проблема может возникнуть, если вы используете перенаправление через header или навигацию с помощью JavaScript.
Дело в том, что РНР автоматически дописывает идентификатор сессии только к ссылкам вида , но не делает этого для header-ов, яваскрипта, мета-тегов.
Поэтому надо добавлять идентификатор руками, например, так:
header ("Location: /script.php?" . session_name (). "=" . session_id ());

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

Безопасность
Безопасность сессий - тема обширная. Поэтому остановлюсь на нескольких основных моментах.
Самый хрестоматийный - не передавать идентификатор через адресную строку. Об этом написано даже в php.ini, но это ограничивает функциональность сессий. Если вы решите последовать этому совету, то кроме session.use_trans_sid = 0 не забудьте session.use_only_cookies = 1
Желательно привязывать сессию к IP адресу: таким образом, если идентификатор будет украден, то злодей все равно не сможет им воспользоваться в большинстве случаев.
Рекомендуется пользоваться директивой session.save_path, с помощью которой задать собственный каталог для сохранения файлов сессий. Это более безопасно, чем когда они хранятся в общем временном каталоге сервера по умолчанию.

Дополнительная информация:

  • Кроме кук, механизм сессий посылает еще и заголовки, запрещающие кэширование страниц (тот самый 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 куку PHP отправлял куку только если при старте сессии в запросе отсутстввал идентификатор. Теперь же кука посылается при каждом вызове session_start ()

    Пример авторизации с помощью сессий
    Проиллюстрируем все вышенаписанное небольшим примером:
    создадим файл auth.php:
    if (isset($_POST [ "auth_name" ]))
    {
    $sql = "SELECT * FROM users WHERE name=?s" ;
    $row = $db -> getRow ($sql , $_POST [ "auth_name" ]);
    if ($row && password_verify ($_POST [ "auth_pass" ], $row [ "pass" ])) {
    $_SESSION [ "user_id" ] = $row [ "id" ];
    }
    header ("Location: http://" . $_SERVER [ "HTTP_HOST" ]. $_SERVER [ "REQUEST_URI" ]);
    exit;
    }

    if (isset($_GET [ "action" ]) AND $_GET [ "action" ]== "logout" ) {
    session_start ();
    session_destroy ();
    header ("Location: http://" . $_SERVER [ "HTTP_HOST" ]. "/" );
    exit;
    }

    if (!isset($_SESSION [ "user_id" ])) {
    ?>








    exit;
    }

    Теперь достаточно написать во всех защищаемых скриптах строчку
    require "auth.php" ;
    В данном примере предполагается, что сессия уже стартовала и соединение с БД создано, с использованием Класс для безопасной и удобной работы с MySQL . Также предполагается, что пароль хэширован с использованием рекомендованной функции password_hash .
    Пример защищаемого файла:

    session_start ();
    include "safemysql.class.php" ;
    $db = new safemysql ([ "db" => "test" ]);
    include "auth.php" ;
    ?>
    secret

    logout

    ОПС! Очень Полезные Ссылки:
    http://www.php.net/manual/ru/ref.session.php - самая последняя и свежая информация о поддержке сессий в PHP в официальной документации, плюс многочисленные комментарии пользователей. Настоятельно рекомендуется к прочтению.
    http://phpclub.ru/manrus/f/ref.session.html - ВЕСЬМА устаревший перевод этой главы на русский, из документации в переводе Александра Пирамидина.
    http://phpclub.ru/detail/article/sessions
    Статья с пафосным названием "Правда о сессиях". Двойственное впечатление оставляет. Вначале автор ОЧЕНЬ доступно рассказывает о механизме сессий, но методы, которые он предлагает к концу статьи - совершенно мутные.

    Хрестоматийная статья Дмитрия Бородина с сайта
    http://php.spb.ru/ настоятельно НЕ рекомендуется.
    Ребята, она страшно устарела. Мало того, что в ней есть фактические неточности, так с сессиями в PHP уже давно просто не работают.
    Огромное Диме спасибо за нее, это была первая статья по сессиям на русском языке, я сам по ней учился, но сейчас надо ее отправить на заслуженный отдых.
    Так же, устарели к сожалению, и многие другие статьи, лежащие в интернете и не обновлявшиеся годами.

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

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

    Идентификатор сессии, хранящийся на компьютере пользователя, это файл cookie .

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

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

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

    // инициировать сессию session_start();

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

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

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

    PHP

    echo "Имя сессии: ".session_name(). " Идентификатор сессии: ".session_id(); // Имя сессии: PHPSESSID Идентификатор сессии: mceu820l02id3ds0vcvtgnht04

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

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

    $_SESSION["nick"] = $_POST["name"];

    Уничтожаем переменные сессии и саму сессию

    1 . Удалить переменную сессии можно следующим образом:

    Unset($_SESSION["nick"]);

    Этим мы предотвратим повторное использование информации.

    Но лучше просто очистить массив $_SESSION (удалить все переменные сессии):

    //очистить массив $_SESSION $_SESSION = array();

    2 . Также необходимо сделать следующее:

    Установить файл cookie сессии недействительным:

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

    Имя сессии ссылается на session id в куках и URL

    3 . Уничтожить (завершить) сессиию

    Session_destroy();

    Буферизация вывода

    Если у вас уже есть какой-либо вывод, вы можете воспользоваться фукцией ob_start() . Данная функция делает буферизацию вывода. Теперь вывод не будет отправлен браузеру, пока вы не отправите его принудительно при помощи функции ob_end_flush() .

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

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

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

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

    Механизм работы сессий


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

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

    $_SESSION["start"] = time(); // временная метка авторизации пользователя $now = time(); // текущее время $time_limit = 1000; // максимально допустимое время бездействия пользователя в сек. if ($now > $_SESSION["start"] + $time_limit) { echo "Ваше время истекло"; //....... // и удаляем сессию и ее cookie } else { $_SESSION["start"] = time(); } // если порядок, обновляем

    Как сделать время жизни сессии вечной?

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

    Когда клиент пришел вновь - надо начать новую сессию, но загрузить в неё данные о клиенте, основываясь на уникальной для клиента куке, которая надолго устанавливается ему при выборе галочки, например, "запомнить меня".

    Работа с сессией при отключенных куках

    Если для настройки session.use_trans_sid установить 1 , то при отключенных куках PHP будет передавать PHPSESSID методом GET в строке запроса.