Введение
HTTP-приложения не имеют состояний. Сессии — способ сохранения информации о пользователе между отдельными запросами. Laravel поставляется со множеством различных механизмов сессий, доступных через единый выразительный API. Из коробки поддерживаются такие популярные системы, как Memcached, Redis и СУБД.
Настройка
Настройки сессии содержатся в файле config/session.php. Обязательно просмотрите параметры, доступные вам в этом файле. По умолчанию Laravel использует драйвер сессий file, который подходит для большинства приложений. Для увеличения производительности сессий в продакшне вы можете использовать драйверы memcached или redis.
Настройки драйвера определяют, где будут храниться данные сессии для каждого запроса. Laravel поставляется с целым набором замечательных драйверов:
- file — данные хранятся в storage/framework/sessions.
- cookie — данные хранятся в виде зашифрованных cookie.
- database — хранение данных в реляционной БД.
- memcached / redis — для хранения используются эти быстрые кэширующие хранилища.
- array — сессии хранятся в виде PHP-массивов и не будут сохраняться между запросами.
Внимание: драйвер array обычно используется во время тестирования, так как он на самом деле не сохраняет данные для последующих запросов.
Требования для драйверов
При использовании драйвера сессий database вам необходимо создать таблицу для хранения данных сессии. Ниже — пример такого объявления с помощью конструктора таблиц:
Schema::create('sessions', function ($table) {
$table->string('id')->unique();
$table->integer('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
Для создания этой миграции вы можете использовать Artisan-команду shsession:table
:
shphp artisan session:table php artisan migrate
Чтобы использовать сессии Redis в Laravel, необходимо установить пакет predis/predis (~1.0) с помощью Composer. Вы можете настроить подключения Redis в файле настроек database. А в файле session в параметре connection можно указать конкретное подключение Redis для сессии.
добавлено в 5.0 ()
Использование сессий
Получение данных
В Laravel есть два основных способа работы с данными сессии: с помощью глобального вспомогательного метода PHPsession()
и через экземпляр Request. Сначала давайте обратимся к сессии через экземпляр Request, который может быть указан в качестве зависимости в методе контроллера. Учтите, зависимости метода контроллера автоматически внедряются при помощи сервис-контейнера Laravel:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Показать профиль данного пользователя.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function show(Request $request, $id)
{
$value = $request->session()->get('key');
//
}
}
При получении значения из сессии, вы можете передать значение по умолчанию вторым аргументом метода PHPget()
. Это значение будет возвращено, если указанного ключа нет в сессии. Если вы передадите в метод замыкание в качестве значения по умолчанию, и запрашиваемого ключа не существует, то будет выполняться это замыкание и возвращаться его результат:
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
Глобальный вспомогательный метод PHPsession()
Также вы можете использовать глобальную PHP-функцию PHPsession()
для извлечения и помещения данных в сессию. При вызове PHPsession()
с одним строковым аргументом, метод вернёт значение ключа этой сессии. При вызове PHPsession()
с массивом пар ключ/значение, эти значения будут сохранены в сессии:
Route::get('home', function () {
// Получить кусок данных из сессии...
$value = session('key');
// Указать значение по умолчанию...
$value = session('key', 'default');
// Сохранить кусок данных в сессию...
session(['key' => 'value']);
});
Есть небольшое практическое отличие между использованием сессий через экземпляр HTTP-запроса и использованием глобального вспомогательного метода PHPsession()
. Оба способа тестируются методом PHPassertSessionHas()
, доступным во всех ваших тест-кейсах.
Если вы хотите получить все данные из сессии, используйте метод PHPall()
:
$data = $request->session()->all();
Определение наличия элемента в сессии
Для проверки существования значения в сессии можно использовать метод PHPhas()
. Этот метод вернёт true, если значение существует и не равно PHPnull
:
if ($request->session()->has('users')) {
//
}
Для проверки существования значения в сессии, даже если оно равно PHPnull
, можно использовать метод PHPexists()
. Этот метод вернёт true, если значение существует:
if ($request->session()->exists('users')) {
//
}
Сохранение данных
Для сохранения данных в сессии обычно используются метод PHPput()
или вспомогательный метод PHPsession()
:
// Через экземпляр запроса...
$request->session()->put('key', 'value');
// Через глобальный вспомогательный метод...
session(['key' => 'value']);
Запись данных в массивы сессии
Метод PHPpush()
служит для записи нового значения в элемент сессии, который является массивом. Например, если ключ user.teams содержит массив с именами команд, вы можете записать новое значение в массив вот так:
$request->session()->push('user.teams', 'developers');
Метод PHPpull()
прочитает и удалит элемент из сессии за одно действие:
$value = $request->session()->pull('key', 'default');
Одноразовые данные
Иногда вам нужно сохранить переменную в сессии только для следующего запроса. Вы можете сделать это методом PHPflash()
(flash англ. — вспышка — прим. пер.). Сохранённые этим методом данные будут доступны только во время следующего HTTP-запроса, а затем будут удалены. В основном такие данные полезны для кратковременных сообщений о состоянии:
$request->session()->flash('status', 'Задание выполнено успешно!');
Для сохранения одноразовых данных в течение большего числа запросов используйте метод PHPreflash()
, который оставит все эти данные для следующего запроса. А если вам надо хранить только определённые данные, то используйте метод PHPkeep()
:
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
Удаление данных
Метод PHPforget()
удалит куски данных из сессии. Для удаления из сессии всех данных используйте метод PHPflush()
:
$request->session()->forget('key');
$request->session()->flush();
Обновление ID сессии
Обновление ID сессии часто используется для защиты приложения от злоумышленников, применяющих атаку фиксации сессии.
Laravel автоматически обновляет ID сессии во время аутентификации, если вы используете встроенный LoginController; но если вы хотите обновлять ID сессии вручную, используйте метод PHPregenerate()
.
$request->session()->regenerate();
добавлено в 5.0 ()
С сессиями можно работать несколькими способами: с помощью метода PHPsession()
HTTP-запросов, с помощью фасада Session, или с помощью функции PHPsession()
. При вызове функции PHPsession()
без аргументов она возвратит весь объект сессии. Например:
session()->regenerate();
Сохранение переменной в сессии
Session::put('key', 'value');
session(['key' => 'value']);
Добавление элемента к переменной-массиву
Session::push('user.teams', 'developers');
$value = Session::get('key');
$value = session('key');
Чтение переменной или возврат значения по умолчанию
$value = Session::get('key', 'default');
$value = Session::get('key', function() { return 'default'; });
Прочитать переменную и забыть её
$value = Session::pull('key', 'default');
Получение всех переменных сессии
$data = Session::all();
Проверка существования переменой
if (Session::has('users'))
{
//
}
Session::forget('key');
Session::flush();
Присвоение сессии нового идентификатора
Session::regenerate();
Добавление своих драйверов сессий
Ваш драйвер сессий должен реализовывать SessionHandlerInterface. Этот интерфейс содержит всего несколько простых методов, которые надо реализовать. Заглушка реализации MongoDB выглядит приблизительно так:
<?php
namespace App\Extensions;
class MongoHandler implements SessionHandlerInterface
{
public function open($savePath, $sessionName) {}
public function close() {}
public function read($sessionId) {}
public function write($sessionId, $data) {}
public function destroy($sessionId) {}
public function gc($lifetime) {}
}
В Laravel нет стандартного каталога для ваших расширений. Вы можете разместить их где угодно. В этом примере мы создали каталог Extensions для хранения в нём MongoHandler.
Поскольку задачи этих методов не так очевидны, давайте коротко рассмотрим каждый из них:
- Метод
PHPopen()
обычно используется в системе хранения файл-сессий. Поскольку Laravel поставляется с драйвером сессий file, вам почти никогда не потребуется делать что-либо в этом методе. Вы можете оставить его пустым как заглушку. То, что PHP требует реализовать данный метод, — это пример плохого проектирования интерфейса (обсудим это позже). - Методом
PHPclose()
зачастую можно пренебречь, как и методомPHPopen()
. Для большинства драйверов он не нужен. - Метод
PHPread()
должен вернуть данные сессии поPHP$sessionId
в виде строки. Не нужно выполнять сериализацию или другое преобразование при получении или сохранении данных сессии в ваш драйвер, поскольку Laravel выполнит сериализацию за вас. - Метод
PHPwrite()
должен записать указанную строкуPHP$data
в соответствии сPHP$sessionId
в какое-либо постоянное хранилище, такое как MongoDB, Dynamo и т.п. И снова, не нужно выполнять сериализацию — Laravel выполнит её за вас. - Метод
PHPdestroy()
должен удалить из постоянного хранилища данные, соответствующиеPHP$sessionId
. - Метод
PHPgc()
должен удалить все данные сессий, которые старше заданногоPHP$lifetime
(который является отметкой времени UNIX). Для самоочищающихся систем, таких как Memcached и Redis, этот метод можно оставить пустым.
После реализации драйвера его можно зарегистрировать в фреймворке. Для добавления дополнительных драйверов для работы с сессиями в Laravel используйте метод PHPextend()
фасада Session. Вам надо вызвать метод PHPextend()
из метода PHPboot()
сервис-провайдера. Это можно сделать в имеющемся AppServiceProvider или создать абсолютно новый провайдер:
<?php
namespace App\Providers;
use App\Extensions\MongoSessionStore;
use Illuminate\Support\Facades\Session;
//для версии 5.2 и ранее:
//use Session;
use Illuminate\Support\ServiceProvider;
class SessionServiceProvider extends ServiceProvider
{
/**
* Выполнение после-регистрационной загрузки сервисов.
*
* @return void
*/
public function boot()
{
Session::extend('mongo', function ($app) {
// Возврат реализации SessionHandlerInterface...
return new MongoSessionStore;
});
}
/**
* Регистрация привязок в контейнере.
*
* @return void
*/
public function register()
{
//
}
}
Когда драйвер сессий зарегистрирован, вы можете использовать драйвер mongo в своём файле настроек config/session.php.