Версія фреймворка: 8.x

Сесія HTTP

Вступ

Оскільки програми, керовані HTTP, не мають стану, сеанси забезпечують спосіб зберігання інформації про користувача в декількох запитах. Laravel постачається з різноманітними серверними сервісами, доступ до яких здійснюється за допомогою виразного уніфікованого API. Підтримка таких популярних серверних систем, якMemcached,Редіс, а бази даних включені нестандартно.

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

Файл конфігурації сеансу зберігається за адресоюconfig/session.php. Не забудьте переглянути варіанти, доступні вам у цьому файлі. За замовчуванням Laravel налаштовано на використанняfileдрайвер сеансу, який буде добре працювати для багатьох додатків.

СесіяdriverПараметр конфігурації визначає, де будуть зберігатися дані сеансу для кожного запиту. Laravel поставляється з декількома чудовими водіями, що вийшли з коробки:

  • file - sessions are stored in storage/framework/sessions.
  • cookie - sessions are stored in secure, encrypted cookies.
  • database - sessions are stored in a relational database.
  • memcached / redis - sessions are stored in one of these fast, cache based stores.
  • array - sessions are stored in a PHP array and will not be persisted.
Драйвер масиву використовується під частестуванняі запобігає збереженню даних, що зберігаються в сеансі.

Передумови драйвера

База даних

При використанніdatabaseдрайвера сеансу, вам потрібно буде створити таблицю, яка міститиме елементи сеансу. Нижче наведено прикладSchemaдекларація для таблиці:

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

Ви можете використовуватиsession:tableКоманда Artisan для генерації цієї міграції:

php artisan session:table

php artisan migrate

Редіс

Перш ніж використовувати сеанси Redis з Laravel, вам доведеться або встановити розширення PHpRedis PHP через PECL, або встановитиpredis/predisпакет (~ 1.0) через Composer. Щоб отримати додаткову інформацію про налаштування Redis, перегляньте йогоСторінка документації Laravel.

Уsessionфайл конфігурації, файлconnectionПараметр може бути використаний, щоб вказати, яке з'єднання Redis використовується сеансом.

Використання сесії

Отримання даних

У Laravel існує два основних способи роботи з даними сеансів: глобальнийsessionпомічник і через aRequestінстанції. Спочатку давайте розглянемо доступ до сеансу через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метод. Це значення за замовчуванням буде повернуто, якщо вказаний ключ не існує у сеансі. Якщо ви здаєтеClosureяк значення за замовчуванням дляgetі запитуваний ключ не існує,Closureбуде виконано, а його результат повернено:

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

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

Помічник з глобальної сесії

Ви також можете використовувати глобальнийsessionФункція PHP для отримання та збереження даних у сеансі. Колиsessionhelper викликається одним аргументом рядка, він поверне значення цього ключа сеансу. Коли помічник викликається з масивом пар ключ / значення, ці значення зберігатимуться у сеансі:

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']);
});
Існує невелика практична різниця між використанням сеансу через екземпляр запиту HTTP та використанням глобальногоsessionпомічник. Обидва методи єперевіряєтьсячерезassertSessionHasметод, який доступний у всіх ваших тестових випадках.

Отримання всіх даних сеансу

Якщо ви хочете отримати всі дані сеансу, ви можете використовуватиallметод:

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

Визначення, чи існує елемент на сесії

Щоб визначити, чи присутній елемент у сесії, ви можете використовуватиhasметод.hasметод повертаєtrueякщо предмет присутній і його немаєnull:

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

Щоб визначити, чи присутній елемент у сеансі, навіть якщо його значення становитьnull, ви можете використовуватиexistsметод.existsметод повертаєtrueякщо товар присутній:

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

Зберігання даних

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

// Via a request instance...
$request->session()->put('key', 'value');

// Via the global helper...
session(['key' => 'value']);

Підштовхування до масиву значень сеансу

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

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

Отримання та видалення елемента

pullметод отримає та видалить елемент із сеансу в одному висловлюванні:

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

Flash-дані

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

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

Якщо вам потрібно зберегти ваші флеш-дані для кількох запитів, ви можете використовуватиreflashметод, який зберігатиме всі дані флеш-пам'яті для додаткового запиту. Якщо вам потрібно зберегти лише певні флеш-дані, ви можете використовуватиkeepметод:

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

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

Видалення даних

forgetметод видалить фрагмент даних із сеансу. Якщо ви хочете видалити всі дані із сеансу, ви можете використовуватиflushметод:

// Forget a single key...
$request->session()->forget('key');

// Forget multiple keys...
$request->session()->forget(['key1', 'key2']);

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

Відновлення ідентифікатора сесії

Регенерація ідентифікатора сеансу часто робиться з метою запобігання зловмисним користувачам використовуватифіксація сеансуатака на вашу програму.

Laravel автоматично відновлює ідентифікатор сеансу під час автентифікації, якщо ви використовуєтеLaravel Jetstream; однак, якщо вам потрібно вручну відтворити ідентифікатор сеансу, ви можете використовувати файлregenerateметод.

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

Блокування сеансу

Щоб використовувати блокування сеансів, ваша програма повинна використовувати драйвер кешу, який підтримуєатомні замки. В даний час ці драйвери кешу включаютьmemcached,dynamodb,redis, іdatabaseводіїв. Крім того, ви не можете використовуватиcookieдрайвер сеансу.

За замовчуванням Laravel дозволяє одночасно виконувати запити, що використовують один і той же сеанс. Так, наприклад, якщо ви використовуєте бібліотеку JavaScript HTTP, щоб зробити два 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()

Додавання користувацьких драйверів сеансів

Впровадження драйвера

Ваш користувальницький драйвер сеансу повинен реалізувати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) {}
}
Laravel не постачається з каталогом, що містить ваші розширення. Ви можете розмістити їх де завгодно. У цьому прикладі ми створили файлExtensionsкаталог для розміщенняMongoSessionHandler.

Оскільки мета цих методів не зрозуміла, давайте швидко розглянемо, що робить кожен із методів:

  • The open method would typically be used in file based session store systems. Since Laravel ships with a file session driver, you will almost never need to put anything in this method. You can leave it as an empty stub. It is a fact of poor interface design (which we'll discuss later) that PHP requires us to implement this method.
  • The close method, like the open method, can also usually be disregarded. For most drivers, it is not needed.
  • The read method should return the string version of the session data associated with the given $sessionId. There is no need to do any serialization or other encoding when retrieving or storing session data in your driver, as Laravel will perform the serialization for you.
  • The write method should write the given $data string associated with the $sessionId to some persistent storage system, such as MongoDB, Dynamo, etc. Again, you should not perform any serialization - Laravel will have already handled that for you.
  • The destroy method should remove the data associated with the $sessionId from persistent storage.
  • The gc method should destroy all session data that is older than the given $lifetime, which is a UNIX timestamp. For self-expiring systems like Memcached and Redis, this method may be left empty.

Реєстрація драйвера

Після реалізації вашого драйвера ви готові зареєструвати його у фреймворку. Щоб додати додаткові драйвери до бекенду сеансу Laravel, ви можете використовуватиextendметод наSessionфасад. Вам слід зателефонувати доextendметод зbootметод aпостачальник послуг. Ви можете зробити це з існуючих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 implementation of SessionHandlerInterface...
            return new MongoSessionHandler;
        });
    }
}

Після реєстрації драйвера сеансу ви можете використовуватиmongoдрайвер у вашомуconfig/session.phpфайл конфігурації.