Skip to content
Icon

ПРЕДУПРЕЖДЕНИЕ Вы просматриваете документацию к старой версии Laravel. Рассмотрите возможность обновления Вашего проекта до Laravel 9.x.

HTTP-сессия

Введение

Поскольку приложения, управляемые HTTP, не имеют состояния, сеансы предоставляют способ хранения информации о пользователе в нескольких запросах. Эта пользовательская информация обычно помещается в постоянное хранилище / бэкэнд, к которому можно получить доступ из последующих запросов.

Laravel поставляется с множеством бэкэнд сеансов, доступ к которым осуществляется через выразительный унифицированный API. Включена поддержка популярных серверных программ, таких как Memcached, Redis и баз данных.

Конфигурация

Файл конфигурации сеанса вашего приложения хранится в config/session.php. Обязательно ознакомьтесь с вариантами, доступными вам в этом файле. По умолчанию Laravel настроен на использование драйвера сеанса file, который хорошо работает для многих приложений. Если ваше приложение будет балансировать нагрузку на нескольких веб-серверах, вам следует выбрать централизованное хранилище, к которому могут получить доступ все серверы, например Redis или база данных.

Опция конфигурации сеанса driver определяет, где будут храниться данные сеанса для каждого запроса. Laravel поставляется с несколькими отличными драйверами из коробки:

  • file - сессии храняться в storage/framework/sessions.
  • cookie - сессии храняться в безопасных зашифрованных файлах cookie.
  • database - сессии храняться в реляционной базе данных.
  • memcached / redis - сессии храняться в одном из этих быстрых хранилищ на основе кеша.
  • dynamodb - сессии храняться в AWS DynamoDB.
  • array - сессии храняться в в массиве PHP и не сохраняются.

{tip} The array driver is primarily used during testing and prevents the data stored in the session from being persisted.

Требования к драйверам

База данных

При использовании сеансового драйвера database вам нужно будет создать таблицу, содержащую записи сеанса. Пример объявления Schema для таблицы можно найти ниже:

Schema::create('sessions', function ($table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity')->index();
});

Вы можете использовать Artisan-команду session:table для генерации этой миграции. Чтобы узнать больше о миграции базы данных, вы можете ознакомиться с полной документацией по миграции:

php artisan session:table
 
php artisan migrate

Redis

Перед использованием сеансов Redis с Laravel вам нужно будет либо установить расширение PHP PhpRedis через PECL, либо установить пакет predis/predis (~1.0) через Composer. Дополнительные сведения о настройке Redis смотрите в документации Redis.

{tip} В файле конфигурации session параметр connection может использоваться, чтобы указать, какое соединение Redis используется сеансом.

Взаимодействие с сессией

Получение данных

Есть два основных способа работы с данными сеанса в Laravel: глобальный помощник session и через экземпляр Request. Во-первых, давайте посмотрим на доступ к сеансу через экземпляр Request, который может иметь типовой намек на замыкание маршрута или метод контроллера. Помните, что зависимости методов контроллера автоматически вводятся через Laravel сервисный контейнер:

<?php
 
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
 
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function show(Request $request, $id)
{
$value = $request->session()->get('key');
 
//
}
}

Когда вы извлекаете элемент из сеанса, вы также можете передать значение по умолчанию в качестве второго аргумента метода get. Это значение по умолчанию будет возвращено, если указанный ключ не существует в сеансе. Если вы передаете замыкание в качестве значения по умолчанию методу get, а запрошенный ключ не существует, замыкание будет выполнено и его результат будет возвращен:

$value = $request->session()->get('key', 'default');
 
$value = $request->session()->get('key', function () {
return 'default';
});

Помощник глобальной сессии

Вы также можете использовать глобальную функцию PHP session для получения и сохранения данных в сеансе. Когда помощник session вызывается с одним строковым аргументом, он возвращает значение этого сеансового ключа. Когда помощник вызывается с массивом пар ключ / значение, эти значения будут сохранены в сеансе:

Route::get('/home', function () {
// Retrieve a piece of data from the session...
$value = session('key');
 
// Specifying a default value...
$value = session('key', 'default');
 
// Store a piece of data in the session...
session(['key' => 'value']);
});

{tip} Существует небольшая практическая разница между использованием сеанса через экземпляр HTTP-запроса и использованием глобального помощника session. Оба метода тестируемые через метод assertSessionHas, который доступен во всех ваших тестовых примерах.

Получение всех данных сеанса

Если вы хотите получить все данные в сеансе, вы можете использовать метод all:

$data = $request->session()->all();

Определение наличия элемента в сеансе

Чтобы определить, присутствует ли элемент в сеансе, вы можете использовать метод has. Метод has возвращает true, если элемент присутствует, а не null:

if ($request->session()->has('users')) {
//
}

Чтобы определить, присутствует ли элемент в сеансе, даже если его значение равно null, вы можете использовать метод exists:

if ($request->session()->exists('users')) {
//
}

Чтобы определить, отсутствует ли элемент в сеансе, вы можете использовать метод missing. Метод missing возвращает true, если элемент равен null или если элемент отсутствует:

if ($request->session()->missing('users')) {
//
}

Хранение данных

Для хранения данных в сеансе вы обычно будете использовать метод put экземпляра запроса или глобальный помощник session:

// Через экземпляр запроса...
$request->session()->put('key', 'value');
 
// Через глобального помощника "session"...
session(['key' => 'value']);

Отправка значений в массив сеанса

Метод push может использоваться для вставки нового значения в значение сеанса, которое является массивом. Например, если ключ user.teams содержит массив названий команд, вы можете поместить новое значение в массив следующим образом:

$request->session()->push('user.teams', 'developers');

Получение и удаление элемента

Метод pull будет извлекать и удалять элемент из сеанса одним оператором:

$value = $request->session()->pull('key', 'default');

Увеличение и уменьшение значений сеанса

Если данные вашей сессии содержат целое число, которое вы хотите увеличить или уменьшить, вы можете использовать методы increment и decrement:

$request->session()->increment('count');
 
$request->session()->increment('count', $incrementBy = 2);
 
$request->session()->decrement('count');
 
$request->session()->decrement('count', $decrementBy = 2);

Мгновенные данные

Иногда вы можете захотеть сохранить элементы в сеансе для следующего запроса. Вы можете сделать это с помощью метода flash. Данные, хранящиеся в сеансе с использованием этого метода, будут доступны немедленно и во время последующего HTTP-запроса. После последующего HTTP-запроса данные будут удалены. Flash-данные в первую очередь полезны для кратковременных статусных сообщений:

$request->session()->flash('status', 'Task was successful!');

Если вам нужно сохранить данные флэш-памяти для нескольких запросов, вы можете использовать метод reflash, который сохранит все данные флэш-памяти для дополнительного запроса. Если вам нужно сохранить только определенные флэш-данные, вы можете использовать метод keep:

$request->session()->reflash();
 
$request->session()->keep(['username', 'email']);

Чтобы сохранить ваши флеш-данные только для текущего запроса, вы можете использовать метод now:

$request->session()->now('status', 'Task was successful!');

Удаление данных

Метод forget удалит часть данных из сеанса. Если вы хотите удалить все данные из сеанса, вы можете использовать метод flush:

// Забыть единственный ключ...
$request->session()->forget('name');
 
// Забыть несколько ключей...
$request->session()->forget(['name', 'status']);
 
$request->session()->flush();

Регенерация идентификатора сессии

Повторное создание идентификатора сеанса часто выполняется для предотвращения использования злоумышленниками атаки фиксации сеанса на ваше приложение.

Laravel автоматически восстанавливает идентификатор сеанса во время аутентификации, если вы используете один из Laravel стартовые наборы приложений или Laravel Fortify; однако, если вам нужно вручную повторно сгенерировать идентификатор сеанса, вы можете использовать метод regenerate:

$request->session()->regenerate();

Если вам нужно повторно сгенерировать идентификатор сеанса и удалить все данные из сеанса одним оператором, вы можете использовать метод invalidate:

$request->session()->invalidate();

Блокировка сессии

{note} Чтобы использовать блокировку сеанса, ваше приложение должно использовать драйвер кеша, поддерживающий атомарные блокировки. В настоящее время эти драйверы кэша включают драйверы memcached, dynamodb, redis и database. Кроме того, вы не можете использовать драйвер сеанса cookie.

По умолчанию Laravel позволяет запросам, использующим один и тот же сеанс, выполняться одновременно. Так, например, если вы используете HTTP-библиотеку JavaScript для выполнения двух HTTP-запросов к вашему приложению, они оба будут выполняться одновременно. Для многих приложений это не проблема; однако потеря данных сеанса может произойти в небольшом подмножестве приложений, которые выполняют одновременные запросы к двум различным конечным точкам приложения, которые оба записывают данные в сеанс.

Чтобы смягчить это, Laravel предоставляет функциональность, которая позволяет вам ограничивать количество одновременных запросов для данного сеанса. Для начала вы можете просто привязать метод block к определению вашего маршрута. В этом примере входящий запрос к конечной точке /profile получит блокировку сеанса. Пока эта блокировка удерживается, любые входящие запросы к конечным точкам /profile или /order, которые имеют один и тот же идентификатор сеанса, будут ждать завершения выполнения первого запроса, прежде чем продолжить свое выполнение:

Route::post('/profile', function () {
//
})->block($lockSeconds = 10, $waitSeconds = 10)
 
Route::post('/order', function () {
//
})->block($lockSeconds = 10, $waitSeconds = 10)

Метод block принимает два необязательных аргумента. Первый аргумент, принимаемый методом block, - это максимальное количество секунд, в течение которых блокировка сеанса должна удерживаться, прежде чем она будет снята. Конечно, если выполнение запроса завершится до этого времени, блокировка будет снята раньше.

Второй аргумент, принимаемый методом block, - это количество секунд, в течение которых запрос должен ждать при попытке получить блокировку сеанса. Исключение Illuminate\Contracts\Cache\LockTimeoutException будет выдано, если запрос не сможет получить блокировку сеанса в течение заданного количества секунд.

Если ни один из этих аргументов не передан, блокировка будет получена максимум на 10 секунд, а запросы будут ждать максимум 10 секунд при попытке получить блокировку:

Route::post('/profile', function () {
//
})->block()

Добавление настраиваемых драйверов сессии

Применение драйвера

Если ни один из существующих драйверов сеанса не соответствует потребностям вашего приложения, Laravel позволяет написать собственный обработчик сеанса. Ваш настраиваемый драйвер сеанса должен реализовывать встроенный в PHP SessionHandlerInterface. Этот интерфейс содержит всего несколько простых методов. Замешанная реализация MongoDB выглядит следующим образом:

<?php
 
namespace App\Extensions;
 
class MongoSessionHandler 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) {}
}

{tip} Laravel не поставляется с каталогом для хранения ваших расширений. Вы можете разместить их где угодно. В этом примере мы создали каталог Extensions для размещения MongoSessionHandler.

Поскольку цель этих методов не совсем понятна, давайте быстро рассмотрим, что делает каждый из методов:

  • Метод open обычно используется в файловых системах хранения сеансов. Поскольку Laravel поставляется с драйвером сеанса file, вам редко понадобится что-либо помещать в этот метод. Вы можете просто оставить этот метод пустым.
  • Метод close, как и метод open, также обычно не учитывается. Для большинства драйверов в этом нет необходимости.
  • Метод read должен возвращать строковую версию данных сеанса, связанных с данным $sessionId. Нет необходимости выполнять сериализацию или другое кодирование при извлечении или хранении данных сеанса в вашем драйвере, поскольку Laravel выполнит сериализацию за вас.
  • Метод write должен записать заданную строку $data, связанную с $sessionId, в некоторую постоянную систему хранения, такую ​​как MongoDB или другую систему хранения по вашему выбору. Опять же, вам не следует выполнять сериализацию - Laravel уже сделает это за вас.
  • Метод destroy должен удалить данные, связанные с $sessionId, из постоянного хранилища.
  • Метод gc должен уничтожить все данные сеанса, которые старше заданного $lifetime, которое является меткой времени UNIX. Для систем с самоуничтожением, таких как Memcached и Redis, этот метод можно оставить пустым.

Регистрация драйвера

Как только ваш драйвер будет реализован, вы готовы зарегистрировать его в Laravel. Чтобы добавить дополнительные драйверы в серверную часть сеанса Laravel, вы можете использовать метод extend, предоставляемый Session facade. Вы должны вызвать метод extend из метода boot сервис провайдера. Вы можете сделать это из существующего App\Providers\AppServiceProvider или создать совершенно нового провайдера:

<?php
 
namespace App\Providers;
 
use App\Extensions\MongoSessionHandler;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
 
class SessionServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
 
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Session::extend('mongo', function ($app) {
// Return an implementation of SessionHandlerInterface...
return new MongoSessionHandler;
});
}
}

После регистрации драйвера сеанса вы можете использовать драйвер mongo в файле конфигурации config/session.php.