Сессии PHP (session_start, session_destroy, $_SESSION)
Почти на каждом сайте, на котором есть хоть какая-то интерактивность (регистрация, форма заказа и т.п.), используется такой способ хранение данных о посетителе, как сессии. Сессия — это механизм, который позволяет однозначно идентифицировать посетителя и хранить данные, которые связаны с ним.
Данные в сессии можно записать на одной странице сайта, а считывать на другой, лишь бы время жизни сессии не истекло между обращениями к разным страницам сайта. Данные сессии хранятся на сервере, поэтому изменить их вручную невозможно.
Создание сессии и работа с ней
Давайте попробуем инициализировать (начать) PHP сессию и записать в неё какие-нибудь данные. Для этого воспользуемся функцией с говорящим названием session_start. А затем запишем в сессию какие-нибудь данные:
'; print_r($_SESSION); echo '
'; ?>
Переменная $_SESSION является массивом. Если интересно, что в ней находится, то всегда можно распечатать этот массив через print_r. Результат выполнения кода из примера выше будет таким:
Array ( [text] => Тише, мыши, кот на крыше )
Чтение значений массива $_SESSION происходит точно также, как и чтение элементов любого другого массива.
Сессии — это удобный инструмент, потому что данные сохраняются вне зависимости от загрузки страницы сайта. Приведём простейший пример, демонстрирующий это. Сделаем скрипт, который считает, сколько раз была перезагружена страница с кодом:
else < $_SESSION['reload_counter'] ++; >echo 'Эта страница была перезагружена ' . $_SESSION['reload_counter'] . ' раз'; ?>
Теперь перезагрузим страницу с этим скриптом и увидим, как счётчик увеличивает своё значение.
Чтобы удалить данные, записанные в $_SESSION, используйте те же механизмы, которые используете для массивов, то есть:
Длительность сессии
Длительность хранения данных в сессии зависит от настроек PHP. Обычно составляет примерно 30 минут. Вы можете самостоятельно проверить длительность, получив его из настроек PHP командой:
В результате выполнения этого кода, будет выведена длительность времени жизни сессии в секундах. После окончания этого времени сессия и все данные будут удалены.
Вы можете увеличить время жизни сессии, установив значение gc_maxlifetime в настройках PHP или прописав «php_value session.gc_maxlifetime количество_секунд» в файле .htaccessхостингах.
Файлы сессий
В настройках Apache при создании задаётся путь к директории, которой будут хранится сессии сайта. Эта директория может быть похожа на /tmp/php_sessions/ваш_домен/ . Если на сайте существует функционал сессий, то можно перейти в эту директорию и обнаружить там файлы. В этих файлах будут находиться сериализованные данные всех сессий и все значения, которые записывались в сессию. Эти файлы постепенно удаляются по мере истечения срока жизни сессий.
Завершение сессии
Если сессия не нужна, то необходимо закончить её. Эта задача обычно повялется в случае, если пользователь выходит из своей учётной записи на сайте. Тогда поможет функция session_destroy:
Сколько живёт сессионная переменная?
Интересный и не такой простой вопрос, как многие думают.
Ответ складывается из двух составляющих:
- времени жизни куки
- времени срабатывания механизма сборки мусора, который удалит файл сессии с сервера
Оба этих пункта настраиваются, но мы сейчас будем говорить о дефолтных настройках.
- время жизни куки по умолчанию — «пока пользователь не закроет браузер». Раньше, когда в браузерах ещё не было вкладок, это имело смысл. Сейчас, когда даже если мы закрываем вкладку, но браузер все равно остается открытым, остаётся жить и сессионная кука. То есть при повторном открытии вкладки с тем же сайтом, сессия будет жива-живехонька.
- по умолчанию сборщик мусора убивает все файлы сессий, которые не обновлялись дольше 1440 секунд, или 24 минуты. Но это тоже не точно, поскольку сборщик мсора запускается не при каждом запросе, а с некоторой вероятностью. И на не очень посещаемом сайте старый файл сессии может валяться часами.
Сессии и куки ¶
Сессии и куки позволяют сохранять пользовательские данные между запросами. При использовании чистого PHP можно получить доступ к этим данным через глобальные переменные $_SESSION и $_COOKIE , соответственно. Yii инкапсулирует сессии и куки в объекты, что дает возможность обращаться к ним в объектно-ориентированном стиле и дает дополнительное удобство в работе.
Сессии ¶
По аналогии с запросами и ответами, к сессии можно получить доступ через session компонент приложения, который по умолчанию является экземпляром yii\web\Session.
Открытие и закрытие сессии ¶
Открыть и закрыть сессию можно следующим образом:
$session = Yii::$app->session; // проверяем что сессия уже открыта if ($session->isActive) . // открываем сессию $session->open(); // закрываем сессию $session->close(); // уничтожаем сессию и все связанные с ней данные. $session->destroy();
Можно вызывать open() и close() многократно без возникновения ошибок; внутри компонента все методы проверяют сессию на факт того, открыта она или нет.
Доступ к данным сессии ¶
Получить доступ к сохраненным в сессию данным можно следующим образом:
$session = Yii::$app->session; // получение переменной из сессии. Следующие способы использования эквивалентны: $language = $session->get('language'); $language = $session['language']; $language = isset($_SESSION['language']) ? $_SESSION['language'] : null; // запись переменной в сессию. Следующие способы использования эквивалентны: $session->set('language', 'en-US'); $session['language'] = 'en-US'; $_SESSION['language'] = 'en-US'; // Удаление переменной из сессии. Следующие способы использования эквивалентны: $session->remove('language'); unset($session['language']); unset($_SESSION['language']); // проверка на существование переменной в сессии. Следующие способы использования эквивалентны: if ($session->has('language')) . if (isset($session['language'])) . if (isset($_SESSION['language'])) . // Обход всех переменных в сессии. Следующие способы использования эквивалентны: foreach ($session as $name => $value) . foreach ($_SESSION as $name => $value) .
Информация: При получении данных из сессии через компонент session , сессия будет автоматически открыта, если она не была открыта до этого. В этом заключается отличие от получения данных из глобальной переменной $_SESSION , которое требует обязательного вызова session_start() .
При работе с сессионными данными, являющимися массивами, компонент session имеет ограничение, запрещающее прямую модификацию отдельных элементов массива. Например,
$session = Yii::$app->session; // следующий код НЕ БУДЕТ работать $session['captcha']['number'] = 5; $session['captcha']['lifetime'] = 3600; // а этот будет: $session['captcha'] = [ 'number' => 5, 'lifetime' => 3600, ]; // этот код также будет работать: echo $session['captcha']['lifetime'];
Для решения этой проблемы можно использовать следующие обходные приемы:
$session = Yii::$app->session; // прямое использование $_SESSION (убедитесь, что Yii::$app->session->open() был вызван) $_SESSION['captcha']['number'] = 5; $_SESSION['captcha']['lifetime'] = 3600; // получите весь массив, модифицируйте и сохраните обратно в сессию $captcha = $session['captcha']; $captcha['number'] = 5; $captcha['lifetime'] = 3600; $session['captcha'] = $captcha; // используйте ArrayObject вместо массива $session['captcha'] = new \ArrayObject; . $session['captcha']['number'] = 5; $session['captcha']['lifetime'] = 3600; // записывайте данные с ключами, имеющими одинаковый префикс $session['captcha.number'] = 5; $session['captcha.lifetime'] = 3600;
Для улучшения производительности и читаемости кода рекомендуется использовать последний прием. Другими словами, вместо того, чтобы хранить массив как одну переменную сессии, мы сохраняем каждый элемент массива как обычную сессионную переменную с общим префиксом.
Пользовательское хранилище для сессии ¶
По умолчанию класс yii\web\Session сохраняет данные сессии в виде файлов на сервере. Однако Yii предоставляет ряд классов, которые реализуют различные способы хранения данных сессии:
- yii\web\DbSession: сохраняет данные сессии в базе данных.
- yii\web\CacheSession: хранение данных сессии в предварительно сконфигурированном компоненте кэша кэш.
- yii\redis\Session : хранение данных сессии в redis.
- yii\mongodb\Session : хранение сессии в MongoDB.
Все эти классы поддерживают одинаковый набор методов API. В результате вы можете переключаться между различными хранилищами сессий без модификации кода приложения.
Примечание: Если вы хотите получить данные из переменной $_SESSION при использовании пользовательского хранилища, вы должны быть уверены, что сессия уже стартовала yii\web\Session::open(), в связи с тем, что обработчики хранения пользовательских сессий регистрируются в этом методе.
Чтобы узнать, как настроить и использовать эти компоненты, обратитесь к документации по API. Ниже приведен пример конфигурации yii\web\DbSession для использования базы данных для хранения сессии:
return [ 'components' => [ 'session' => [ 'class' => 'yii\web\DbSession', // 'db' => 'mydb', // ID компонента для взаимодействия с БД. По умолчанию 'db'. // 'sessionTable' => 'my_session', // название таблицы для хранения данных сессии. По умолчанию 'session'. ], ], ];
Также необходимо создать таблицу для хранения данных сессии:
CREATE TABLE session ( id CHAR(40) NOT NULL PRIMARY KEY, expire INTEGER, data BLOB )
где ‘BLOB’ соответствует типу данных предпочитаемой вами DBMS. Ниже приведены примеры соответствия типов BLOB в наиболее популярных DBMS:
- MySQL: LONGBLOB
- PostgreSQL: BYTEA
- MSSQL: BLOB
Примечание: В зависимости от настроек параметра session.hash_function в вашем php.ini, может понадобиться изменить длину поля id . Например, если session.hash_function=sha256 , нужно установить длину поля в 64 вместо 40.
Flash-сообщения ¶
Flash-сообщения — это особый тип данных в сессии, которые устанавливаются один раз во время запроса и доступны только на протяжении следующего запроса, затем они автоматически удаляются. Такой способ хранения информации в сессии наиболее часто используется для реализации сообщений, которые будут отображены конечному пользователю один раз, например подтверждение об успешной отправке формы.
Установить и получить flash-сообщения можно через компонент приложения session . Например:
$session = Yii::$app->session; // Запрос #1 // установка flash-сообщения с названием "postDeleted" $session->setFlash('postDeleted', 'Вы успешно удалили пост.'); // Запрос #2 // отображение flash-сообщения "postDeleted" echo $session->getFlash('postDeleted'); // Запрос #3 // переменная $result будет иметь значение false, так как flash-сообщение было автоматически удалено $result = $session->hasFlash('postDeleted');
Так как flash-сообщения хранятся в сессии как обычные данные, в них можно записывать произвольную информацию, и она будет доступна лишь в следующем запросе.
При вызове yii\web\Session::setFlash(), происходит перезаписывание flash-сообщений c таким же названием. Для того, чтобы добавить новые данные к уже существующему flash-сообщению, необходимо вызвать yii\web\Session::addFlash(). Например:
$session = Yii::$app->session; // Запрос #1 // добавить новое flash-сообщение с названием "alerts" $session->addFlash('alerts', 'Вы успешно удалили пост.'); $session->addFlash('alerts', 'Вы успешно добавили нового друга.'); $session->addFlash('alerts', 'Благодарим.'); // Запрос #2 // Переменная $alerts теперь содержит массив flash-сообщений с названием "alerts" $alerts = $session->getFlash('alerts');
Примечание: Старайтесь не использовать yii\web\Session::setFlash() совместно с yii\web\Session::addFlash() для flash-сообщений с одинаковым названием. Это связано с тем, что последний метод автоматически преобразует хранимые данные в массив, чтобы иметь возможность хранить и добавлять новые данные в flash-сообщения с тем же названием. В результате, при вызове yii\web\Session::getFlash() можно обнаружить, что возвращается массив, в то время как ожидалась строка.
Куки ¶
Yii представляет каждую куку как объект yii\web\Cookie. Оба компонента приложения yii\web\Request и yii\web\Response поддерживают коллекции кук через свойство cookies . В первом случае коллекция кук является их представлением из HTTP-запроса, во втором — представляет куки, которые будут отправлены пользователю.
Чтение кук ¶
Получить куки из текущего запроса можно следующим образом:
// получение коллекции кук (yii\web\CookieCollection) из компонента "request" $cookies = Yii::$app->request->cookies; // получение куки с названием "language. Если кука не существует, "en" будет возвращено как значение по-умолчанию. $language = $cookies->getValue('language', 'en'); // альтернативный способ получения куки "language" if (($cookie = $cookies->get('language')) !== null) < $language = $cookie->value; > // теперь переменную $cookies можно использовать как массив if (isset($cookies['language'])) < $language = $cookies['language']->value; > // проверка на существование куки "language" if ($cookies->has('language')) . if (isset($cookies['language'])) .
Отправка кук ¶
Отправить куку конечному пользователю можно следующим образом:
// получение коллекции (yii\web\CookieCollection) из компонента "response" $cookies = Yii::$app->response->cookies; // добавление новой куки в HTTP-ответ $cookies->add(new \yii\web\Cookie([ 'name' => 'language', 'value' => 'zh-CN', ])); // удаление куки. $cookies->remove('language'); // . что эквивалентно следующему: unset($cookies['language']);
Кроме свойств name и value, класс yii\web\Cookie также предоставляет ряд свойств для получения информации о куках: domain, expire. Эти свойства можно сконфигурировать и затем добавить куку в коллекцию для HTTP-ответа.
Примечание: Для большей безопасности значение свойства yii\web\Cookie::$httpOnly по умолчанию установлено в true . Это уменьшает риски доступа к защищенной куке на клиентской стороне (если браузер поддерживает такую возможность). Вы можете обратиться к httpOnly wiki для дополнительной информации.
Валидация кук ¶
Во время записи и чтения кук через компоненты request и response , как будет показано в двух последующих подразделах, фреймворк предоставляет автоматическую валидацию, которая обеспечивает защиту кук от модификации на стороне клиента. Это достигается за счет подписи каждой куки секретным ключом, позволяющим приложению распознать куку, которая была модифицирована на клиентской стороне. В таком случае кука НЕ БУДЕТ доступна через свойство cookie collection компонента request .
Примечание: Валидация кук защищает только от их модификации. Если валидация не была пройдена, получить доступ к кукам все еще можно через глобальную переменную $_COOKIE . Это связано с тем, что дополнительные пакеты и библиотеки могут манипулировать куками без вызова валидации, которую обеспечивает Yii.
По-умолчанию валидация кук включена. Её можно отключить, установив свойство yii\web\Request::$enableCookieValidation в false , однако мы настоятельно не рекомендуем это делать.
Примечание: Куки, которые напрямую читаются/пишутся через $_COOKIE и setcookie() НЕ БУДУТ валидироваться.
При использовании валидации кук необходимо указать значение свойства yii\web\Request::$cookieValidationKey, которое будет использовано для генерации вышеупомянутого секретного ключа. Это можно сделать, настроив компонент request в конфигурации приложения:
return [ 'components' => [ 'request' => [ 'cookieValidationKey' => 'fill in a secret key here', ], ], ];
Примечание: Свойство cookieValidationKey является секретным значением и должно быть известно только людям, которым вы доверяете. Не помещайте эту информацию под систему контроля версий.
php Механизм записи/хранения/удаления данных о сессии. Разница между unset($_COOKIE) и session_destroy()
![]()
Для удаления данных о сессии Д.Котеров рекомендует выполнять данную последовательность действий:
//Очистить данные сессии для текущего сценария: $_SESSION = []; //Удалить cookie, соответствующую id: @unset($_COOKIE[session_name()]); //удалить хранилище сессии: session_destroy();
Чтобы понять, почему обязательно разбивать удаление сессии на 3 этапа, давайте разберёмся, что вообще где существует и куда сохраняется.
Для наглядности определим все места, где хранятся всевозможные данные о сессии:
-
Суперглобальный массив $_SESSION.
Создаётся при старте сессии session_start(). Это только переменная скрипта, которая доступна только на протяжении работы скрипта и НЕ хранится в хранилище на сервере, а хранится в оперативной памяти (а значит исчезает после очередного выполнения скрипта, инициализируясь вновь из хранилища при очередном обращении к серверу). У Котерова:
При завершении сценария PHP автоматически сохраняет массив $_SESSION во временном хранилище, имя которого хранится в SID
Т.е. можно сказать, что:
- В php-скрипте работать с данными сессии можно через массив $_SESSION
- $_SESSION является «маской» для хранилища сессии и хотя запись в этот массив приводит к записи в хранилище, удаление массива само по себе не уничтожает данные в хранилище.
- удалив массив, вы потеряете доступ к данным сессии только в текущем вызове скрипта, но в следующем он будет вновь иницилизирован (восстанет из пепла), если дополнительно не очистить хранилище.
Таким образом
Если session_destroy() не будет вызвана, и не будут очищены куки, то при новом запуске скрипта, данные из хранилища, записанные в него ранее, появятся в $_SESSION, даже если при этом запуске скрипта, вручную в $_SESSION вы их не добавите.
// Эту строку пишем, чтобы очистить данные о сессии в текущем запуске скрипта $_SESSION = []; //Эта строка удаляет SID @unset($_COOKIE[session_name()]); //Удаляет хранилище сессии: session_destroy();
Источники
- Д.Котеров «PHP7 в подлиннике» стр.625 — 627
- php.net — session_destroy()
Key Words for FKN + antitotal forum (CS VSU):
- сессия php
- session destroy php
- механизм работы session destroy
- где хранятся данные о сессии
- как удалить сессию
- SID
- идентификатор сессии
- хранилище данных о сессии
- в чём разница unset($_COOKIE) и session_destroy()