Работа с сессиями в PHP
Отредактировано: 04 Февраля 2019
Сессия, механизм php, созданный для возможности передачи данных предназначенных конкретному пользователю при повторных запросах (веб-сервер не поддерживает постоянного соединения с клиентом, и каждый запрос обрабатывается, как новый, без какой-либо связи с предыдущими).
Принцип работы сессий: сервер выдает браузеру уникальный идентификатор, и просит передавать его с каждым запросом. Передача происходит стандартными способами, либо через куки, либо через переменные POST/GET.
Идентификатор сессии — это обычная переменная, по умолчанию ее имя — PHPSESSID. Можно изменить директивой session.name в php.ini.
На сервере за передачу информации о сессиях отвечают две настройки в php.ini:
session.use_cookies
— если равно 1, то PHP передает идентификатор в куках, если 0 — то нет.session.use_trans_sid
— если равно 1, то PHP передает его, добавляя к URL и формам, если 0 — то нет.
Соответственно, если включена только первая настройка и браузер отдает куки, то идентификатор передается через них, если не отдает, то сессия обнуляется при каждом запросе.
Если включена только вторая, то PHP дописывает к каждой относительной ссылке и к каждой форме передачу идентификатора сессии, примерно так:
// в ссылках
<a href="/index.php?PHPSESSID=9ebca8bd62c830d3e79272b4f585ff8f">Index</a>
// в формах
<input type="hidden" name="PHPSESSID" value="00196c1c1a02e4c37ac04f921f4a5eec" />
Если включены обе, то браузеру выставляется кука, а ссылки и формы дополняются только если кука найдена не была.
Вся информация о сессии храниться в глобальном массиве $_SESSION.
Запись данных в сессию работает так:
// запускаем новую, либо возобновляем существующую сессию
session_start();
// передаем в массив сессий переменную с названием test и данными Hello world
$_SESSION['test']='Hello world!';
// если в качестве имени переменной хотим использовать значение переменной -
// пишем без кавычек или используем двойные
$var = name;
$_SESSION["$var"]='Hello world!';
Используем например так:
// обычное условие проверки
if(!$_SESSION[$var]){
echo "session variable is empty"
}
// можно получить id текущей сессии или ее имя
session_id();
session_name();
Удаление переменных из сессии:
unset($_SESSION[$var]);
// Если register_globals = on, надо добавить строку
session_unregister($var);
//Если надо сбросить все переменные сессии
session_unset();
Для закрытия сессии используется функция:
session_destroy()
Данные из глобального массива $_SESSION php хранит либо в файлах, путь к которым указывается в session.save_path в php.ini, либо в БД.
Для управления HTTP-заголовками отвечающими за кэш, используется функция session_cache_limiter(). Установка nocache, например, отменяет кэширование на стороне клиента.
Во время начала запроса режим кеширования сбрасывается до значения по умолчанию, хранящегося в session.cache_limiter. Таким образом, вам необходимо вызывать session_cache_limiter() для каждого запроса (перед тем, как вызвана функция session_start()).
Возможные значения:
Значение | Посылаемый заголовок |
---|---|
public | Expires: (когда-нибудь в будущем, в зависимости от session.cache_expire) Cache-Control: public, max-age=(когда-нибудь в будущем, в зависимости от session.cache_expire) Last-Modified: (временная метка последнего сохранения сессии) |
private_no_expire | Cache-Control: private, max-age=(session.cache_expire в будущем), pre-check=(session.cache_expire в будущем) Last-Modified: (временная метка последнего сохранения сессии) |
private | Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: private, max-age=(session.cache_expire в будущем), pre-check=(session.cache_expire в будущем) Last-Modified: (временная метка последнего сохранения сессии) |
nocache | Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache |
Возможные проблемы
- Вспомогательными вещами, вроде кодирования данных и удаления старых сессий, php занимается сам, и если возникает проблема с удалением информации о них, проверьте в php.ini строку session.gc_probability. Для того чтобы php мог самостоятельно удалять файлы сессий, должно быть установлено 1.
- 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, указать правильный каталог, который существует и доступен для записи (не забудьте перезагрузить апач). - Warning: Cannot send session cookie — headers already sent.
Warning: Cannot send session cache limiter — headers already sent.
Warning: Cannot add header information — headers already sent.
эти ошибки возникают в том случае, если браузер ранее уже получил заголовки для страницы. Функции header(), session_start(), setcookie() и вся логика, которая их вызывает, должны обрабатываться до любого вывода в браузер. - Если давать переменным скрипта имена, совпадающие с индексами массива $_SESSION, возможны проблемы. При register_globals=on значения будут перезаписывать друг друга. При register_globals=off, в случае, если в скрипте есть переменная сессии не имеющая значения, и глобальная переменная с тем же именем, появится ошибка «Your script possibly relies on a session side-effect which existed until PHP 4.2.3.». Для предотвращения этой ошибки, надо инициализировать переменные перед использованием или проверять на существование, и стараться не давать глобальным переменным имена, совпадающие с индексами массива $_SESSION.
- Если вы используете перенаправление через header или навигацию с помощью JavaScript, PHP не пропишет необходимый идентификатор, т.к. он работает только со статичными ссылками. В этом случае надо проставлять идентификатор самостоятельно:
header("Location: /script.php?".session_name().'='.session_id());
- Если один скрипт стартует сессию и долго выполняется, а другой пытается в это время стартовать её с тем же идентификатором, то он зависнет. Поэтому в долго выполняющихся скриптах следует стартовать сессию только тогда, когда она нужна, и тут же закрывать её, с помощью session_write_close().
Более детальный обзор можно найти на сайте phpfaq.ru