Портал Belkin-labs»PHP классы»Статья
welcome!

И, все-таки, сессии PHP жутко интересная штука!

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

Опыт с созданием сессии ( функция session_start())

Опыт № 1

<?php
 
session_start();
$_SESSION['test'] = 'test';
 
?>

Здесь делается буквально следующее:

  • создается ид сессии в виде строки;
  • посылается кука с именем PHPSESSID, которое можно заменить, и со значением ид сессии;
  • В массив $_SESSION записывается некоторое значение.

Что значит "посылается кука"? Буквально это означает то, что сервер в заголовки ответа вставляет соответствующий заголовок для создания куки. Это также означает, что сработает это действие только в тот момент, когда страница будет вызвана в следующий раз и в заголовки запроса браузером будет вставлена эта самая кука. Для работы скрипта, который открывает сессию никакая кука не нужна.

И, наконец, по окончании скрипта будет создан файл сессии в специальной папке.

Опыт № 2

<?php
 
session_start();
$_SESSION['test'] = 'test2';
 
session_start();
 
?>

Повторное открытие уже открытой сессии игнорируется с Notice-ом.

Что делает функция session_destroy()?

Эта функция удаляет файл сессии с диска и закрывает сессию. Что означает "закрывает сессию"? Лично я пока не понял. Но после того, как сессия закрыта, статус сессии принимает значение PHP_SESSION_NONE, ид сессии становится пустой строкой.

Но массив $_SESSION не удаляется! Кука тоже остается и в массиве $_REQUEST, и в $_COOKIE, и в браузере.

Опыт № 3

<?php
 
session_start();
// Сессия, которая до этого была у нас сохранена, открывается и  $_SESSION['test'] = 'test'
 
session_destroy();
// Сессия закрыта (хотя смысл этого понятия пока не очень понятен) и файл сессии с диска пропал
 
session_start();
// Сессия создается опять. При этом у нее ид старый (!!!) тот самый,
// который в куке и в $_REQUEST['PHPSESSID'] продолжается оставаться
 
?>

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

Опыт № 4

<?php
 
session_start();
// Сессия, которая до этого была у нас сохранена, открывается и  $_SESSION['test'] = 'test'
 
session_destroy();
// Сессия закрыта, хотя смысл этого понятия пока не очень понятен, и файл сессии с диска пропал
 
unset ($_COOKIE['PHPSESSID']);
 
session_start();
// Сессия создается опять. При этом у нее ид новый (!!!)
 
?>

Очевидно, после выполнения скрипта на диске появился файл сессии. Он пуст и у него новое имя.

Что делает функция session_write_close()?

Судя по документации, эта функция скидывает массив $_SESSION в файл сессии и закрывает сессию.

Опыт № 5

<?php
 
session_start();
// Сессия, которая до этого была у нас сохранена, открывается и  $_SESSION['test'] = 'test'
 
$_SESSION['test'] = 'test1';
// Записали значение в глобальную переменную
 
session_write_close();
// Записали все, что было в массиве $_SESSION и сессию закрыли
 
session_start();
// Сессия создается опять. При этом у нее ид старый (!!!) тот самый,
// который в куке и в $_COOKIE['PHPSESSID'] продолжается оставаться
// $_SESSION['test'] содержит значение 'test1'.
 
?>

Что делает функция session_regenerate_id()?

Судя по дукументации и по комментариям пользователей к этой документации, эта функция равноценна session_destroy() + session_start(). И, если это действительно так, то это очень удобно в случае, когда сессия кончается по таймауту, но сайт создан так, что без некоторых сессионных переменных работать не может в принципе. В этом случае нам надо убить сессию, но тут же, прямо на следующей строчке кода, опять создать ее новую. И чтобы новая кука в браузере была! И хотим чтобы сессия получила новые актуальные данные. Хотя все зависит от реализации сайта. У меня на сайте новая сессия, которая создается после разрушения по таймауту, должна быть полностью новой. Новая кука, новый сессионный ид и новые (свежие) данные.

Код без использования session_regenerate_id()

<?php
 
session_start();
 
if (надо пересоздать сессию) {
    session_destroy();   // Удалили файл сессии
    delete_cookie();     // Удалили куку с помощью функции setcookie(). Это условная функция. Ее реализация не показана
    unset($_COOKIE['PHPSESSID']);  // Очистили значение куки, чтобы при следующем старте
                                   // сессии не появилась сессия со старым ид
    session_start();     // Создана совершенно новая сессия с новым ид. В браузер послана новая кука.
}
 
// Вот здесь идут обычные действия по созданию или обновлению элементов безопасности и тд.
 
?>

Опыт №6. Испытываем функцию session_regenerate_id() для реализации функционала, приведенного выше

<?php
 
session_start(); // У нас сессия была. Мы знаем ее ид (посмотрели содержимое куки в браузере)
 
var_dump(session_status(), $_SESSION);
 
session_regenerate_id(true);    // Открываем сессию с новым ид и с заменой файла сессии
 
var_dump(session_status(), $_SESSION);
exit;
 
?>

О ЧУДО!

  • Новая кука послана без удаления старой (посмотрели заголовки ответа сервера)
  • Сессионный ид поменялся соответственно.
  • Файл сессии изменил название соответственно.
  • Данные в массиве $_SESSION остались неизменны.
  • Содержимое элемента $_COOKIE['PHPSESSID'] тоже осталось неизменным, то есть содержит сессионный ид убитой только что сессии. Нужно не забыть очистить его, если нужно будет переоткрывать сессию, то есть повторно вызывать session_start().

Очень полезная функция! Буду теперь эту функцию использовать, чего и всем желаю.

Так что же означает термин "закрыть сессию"?

Кажется я понял! Нужно просто термин "сессия" поменять на термин "файл сессии". Тогда все становится на свои места. Мы открываем сессию - значит мы открываем файл сессии и оставляем его открытым. При этом он блокируется на запись для всех других процессов пользователя той же сессии. Закрывая сессию мы просто закрываем файл сессии. Только после закрытия сессии мы можем этот файл удалить. Сессионный ид тоже пропадает по закрытию файла сессии. Развивая мысль дальше можно считать, что сам термин "сессия" означает либо "файл сессии", либо в более широком смысле данные сессии. В стандартном файле сессии они сериализованные, а в массиве $_SESSION в реальном виде. Больше ничего термин "сессия", похоже, не означает.

Удаление сессии - физическое удаление файла сессии, либо данных, если использован другой механизм обработки этих данных.

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

Более того! Термины "сеанс" и "сессия", похоже, разные и не взаимозаменяемые. Они не синонимы. Сейчас мне кажется, что они вообще совсем разные вещи обозначают. Так сессия, как мы уже решили, обозначает просто файл или в более широком смысле данные. Сеанс же обозначает временной промежуток жизни сессионной куки. Начинается сеанс при первом входе на сайт, заканчивается при закрытии браузера. Необязательно именно такой промежуток времени, но, скажем, более вероятный.

И еще одно!

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

  1. Собственно система сессий. Включает в себя механизм поддержки закачки данных в хранилище и взятие их оттуда. И некоторые другие.
  2. Система глобальных переменных. Переменная $_SESSION на самом низком уровне не является частью системы сессий. Это просто глобальный массив, в котором хранятся данные, выкачанные из хранилища механизмом сессий. Как только данные из сессии выкачаны в этот массив, он сразу становится просто глобальной переменной, и теряет связь с сессией. И этот массив так и живет отдельно от сессии до тех пор, пока не придет пора обновлять данные сессии по тем данным, которые в нем хранятся.
  3. Система поддержки кук. Эта система тоже весьма узко используется для связи сеанса с сессией.

Вот и все! Лично я многое понял в процессе написания этого поста! Надеюсь, что и случайным посетителям моего сайта эта информация будет полезна!
Дмитрий Белкин.

Статья создана 30.04.2015
Похожие материалы - отбираем по ключевым словам