Сессии

Содержание:


Введение

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

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

Файл конфигурации для сессии располагается по адресу config/session.php. По умолчанию, Ларавел использует для сессии драйвер file, который отлично работает для большинства приложений. На рабочем сервере вы можете использовать драйверы memcached или redis для ещё большей скорости работы с сессией.

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

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

Необходимые составляющие драйвера

База данных

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

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

Вы можете использовать команду Artisan session:table, чтобы сгенерировать такую миграцию:

php artisan session:table

php artisan migrate

Redis

Перед тем как использовать сессии Redis с Ларавел, вам необходимо установить компонент predis/predis через композер. Вы можете настроить соединение Redis в файле конфигурации. В нем есть опция connection, которая может быть использована для того, чтобы указать что сессией используется соединение Redis.


Использование сессии

Извлечение данных

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

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

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']);
});
На практике, нет большой разницы между использование сессии через экземпляр HTTP запроса или использовать глобальный помощник. Оба метода прекрасно тестируются через метод ssertSessionHas, который доступен во всех случаях.

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

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

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

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

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

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

А чтобы определить наличие элемента в сессии, даже если его значение равно null, вы можете использовать метод 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.teams содержит массив имён команды, вы можете присвоить новое значение таким образом:

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

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

Метод pull получит и удалит элемент из сессии одной строкой:

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

Флеш-данные

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

$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 автоматически восстанавлиет идентификатор сессии в процессе аутентификации. когда вы используете встроенный LoginController. Однако, если вам нужно восстановить идентификатор сессии вручную, вы можете использовать метод regenerate.

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

Добавление пользовательского драйвера сессии

Реализация драйвера

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

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.

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

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

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

После реализации драйвер, вы готовы зарегистрировать его в фреймворке. Чтобы добавить дополнительные драйверы в бэкэнд Laravel, вы можете использовать метод extend для фасада Session. Нужно вызвать метод extend из метода boot сервис контейнера. Вы может сделать это из существующего AppServiceProvider или создать новый провайдер:

namespace App\Providers;

use App\Extensions\MongoSessionHandler;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;

class SessionServiceProvider extends ServiceProvider
{
    /**
     * Register bindings in the container.
     *
     * @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 файле конфигурации.