Laravel 9.x HTTPセッション

イントロダクション

HTTPで駆動するアプリケーションはステートレスであるため、セッションで複数のリクエストにわたりユーザーに関する情報を保存する手段を提供しています。そうしたユーザー情報は、後続のリクエストからアクセスできる永続的な保存/バックエンドに通常配置されます。

Laravelには、表現力豊かで統一されたAPIを介してアクセスできるさまざまなセッションバックエンドを用意しています。MemcachedRedis、データベースなどの一般的なバックエンドをサポートしています。

設定

アプリケーションのセッション設定ファイルはconfig/session.phpに保存されています。このファイルで利用可能なオプションを必ず確認してください。デフォルトでは、Laravelはfileセッションドライバを使用するように設定しています。これは多くのアプリケーションでうまく機能します。アプリケーションが複数のWebサーバ間で負荷分散される場合は、Redisやデータベースなど、すべてのサーバがアクセスできる集中型保存領域を選択する必要があります。

セッションのdriver設定オプションは、各リクエストのセッションデータが保存される場所を定義します。Laravelは、すぐに使える優れたドライバを最初からいくつか用意しています。

  • file - セッションをstorage/framework/sessionsに保存します
  • cookie - セッションを暗号化され安全なクッキーに保存します
  • database - セッションをリレーショナルデータベースへ保存します
  • memcachedredis - セッションをこれらの高速なキャッシュベースの保存域へ保存します
  • dynamodb - セッションをAWS DynamoDBへ保存します
  • array - セッションをPHP配列に格納し、永続化しません

Note: 配列(array)ドライバは主にテスト中に使用し、セッションに保存したデータが永続化されるのを防ぎます。

ドライバの動作要件

データベース

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();
});

session:table Artisanコマンドを使用してこのマイグレーションを生成できます。データベースのマイグレーションの詳細は、完全なマイグレーションドキュメントを参照してください。

php artisan session:table

php artisan migrate

Redis

LaravelでRedisセッションを使用する前に、PECLを介してPhpRedis PHP拡張機能をインストールするか、Composerを介してpredis/predisパッケージ(〜1.0)をインストールする必要があります。Redisの設定の詳細は、LaravelのRedisドキュメントを参照してください。

Note: session設定ファイルで、connectionオプションを使用し、セッションで使用するRedis接続を指定できます。

セッションの操作

データの取得

Laravelでセッションデータを操作する主な方法は、グローバルなsessionヘルパとRequestインスタンスの2つあります。最初に、Requestインスタンスを介してセッションにアクセスする方法を見てみましょう。これはルートクロージャまたはコントローラメソッドでタイプヒントを使い取得できます。コントローラメソッドの依存関係は、Laravelサービスコンテナを介して自動的に依存注入されることに注意してください。

<?php

namespace App\Http\Controllers;

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

class UserController extends Controller
{
    /**
     * 特定のユーザーのプロファイルを表示
     *
     * @param  Request  $request
     * @param  int  $id
     * @return Response
     */
    public function show(Request $request, $id)
    {
        $value = $request->session()->get('key');

        //
    }
}

セッションからアイテムを取得するときに、getメソッドの2番目の引数としてデフォルト値を渡すこともできます。指定したキーがセッションに存在しない場合、このデフォルト値を返します。クロージャをデフォルト値としてgetメソッドに渡すと、リクエストされたキーが存在しない場合にそのクロージャを実行し、その実行結果を返します。

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

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

グローバルセッションヘルパ

グローバルなsessionPHP関数を使用して、セッション内のデータを取得/保存することもできます。sessionヘルパを文字列引数一つで呼び出すと、そのセッションキーの値を返します。キー/値ペアの配列を使用してヘルパを呼び出すと、それらの値をセッションへ保存します。

Route::get('/home', function () {
    // セッションからデータを取得
    $value = session('key');

    // デフォルト値の指定
    $value = session('key', 'default');

    // セッションにデータを保存
    session(['key' => 'value']);
});

Note: HTTPリクエストインスタンスを介してセッションを使用する場合と、グローバルなsessionヘルパを使用する場合の、実践的な違いはほとんどありません。どちらのメソッドも、すべてのテストケースで使用できるassertSessionHasメソッドを使用し、テスト可能です。

全セッションデータの取得

セッション内のすべてのデータを取得する場合は、allメソッドを使用します。

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

アイテムのセッション存在判定

アイテムがセッションに存在するかを判定するには、hasメソッドを使用します。アイテムが存在し、nullでない場合、hasメソッドはtrueを返します。

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

値がnullでも、そのアイテムがセッションに存在するかを判定する場合には、existsメソッドを使用します。

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

アイテムがセッションに存在しないことを判定するには、missingメソッドを使用します。そのアイテムが存在しない場合、missingメソッドはtrueを返します。

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()->('count');

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

$request->session()->decrement('count');

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

データの一時保存

後続のリクエストで使用するために、セッションにアイテムを一時保存したい場合があります。flashメソッドを使い実現できます。このメソッドを使用してセッションに保存されたデータは、即時および後続のHTTPリクエスト中に利用可能です。後続のHTTPリクエストの後、一時保存したデータを削除します。一時保存データは、主に持続保存の必要がないステータスメッセージに役立ちます。

$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();

セッションIDの再生成

多くの場合、セッションIDの再生成は、悪意のあるユーザーがアプリケーションに対するセッション固定攻撃を防ぐため行います。

LaravelアプリケーションスターターキットまたはLaravel Fortifyのどちらかを使用している場合、Laravelは認証中にセッションIDを自動的に再生成します。しかし、セッションIDを手作業で再生成する必要がある場合は、regenerateメソッドを使用できます。

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

セッションIDを再生成してセッションからすべてのデータを一文で削除する必要がある場合は、invalidateメソッドを使用します。

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

セッションブロッキング

Warning!! セッションブロッキングを利用するには、アプリケーションでアトミックロックをサポートするキャッシュドライバを使用している必要があります。現在、これらのキャッシュドライバには、memcacheddynamodbredis、およびdatabaseドライバをサポートしています。また、cookieセッションドライバを使用することはできません。

デフォルトでは、Laravelは同じセッションを使用するリクエストを同時に実行することを許可します。したがって、たとえば、JavaScript HTTPライブラリを使用してアプリケーションへ2つのHTTPリクエストを作成すると、両方が同時に実行されます。多くのアプリケーションでは、これは問題ではありません。ただし、セッションデータの損失が、両方がセッションへデータを書き込む2つの異なるアプリケーションエンドポイントに同時にリクエストを行うアプリケーションの小さなサブセットで発生する可能性があります。

これを軽減するために、Laravelは特定のセッションの同時リクエストを制限できる機能を提供します。これを使用するには、blockメソッドをルート定義にチェーンするだけです。この例では、/profileエンドポイントへの受信リクエストがセッションロックを取得します。このロックが保持されている間、同じセッションIDを共有する/profileまたは/orderエンドポイントへの受信リクエストは、実行を続行する前に最初のリクエストの実行が終了するのを待ちます。

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

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

blockメソッドは2つのオプションの引数を取ります。blockメソッドの最初の引数は、セッションロックを解放するまでに保持する必要がある最大秒数です。もちろん、この時間より前にリクエストの実行が終了すれば、ロックはより早く解放されます。

blockメソッドの2番目の引数は、セッションロックを取得しようとしているときにリクエストが待機する秒数です。リクエストが指定された秒数以内にセッションロックを取得できない場合、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) {}
}

Note: Laravelには、拡張機能を格納するためのディレクトリはありません。好きな場所に自由に配置できます。この例では、MongoSessionHandlerを格納するためにExtensionsディレクトリを作成しました。

これらのメソッドの目的は簡単には理解しずらいため、各メソッドの機能について簡単に説明します。

  • openメソッドは通常、ファイルベースのセッションストアシステムで使用します。Laravelにはfileセッションドライバが付属しているため、このメソッドに何も入れる必要があることはまれです。このメソッドは空のままにしておくことができます。
  • openメソッドと同様に、closeメソッドも通常は無視できます。ほとんどのドライバにとって、それは必要ありません。
  • readメソッドは、指定された$sessionIdに関連付いたセッションデータの文字列バージョンを返す必要があります。Laravelがシリアル化を実行するため、ドライバでセッションデータを取得または保存するときに、シリアル化やその他のエンコードを行う必要はありません。
  • writeメソッドは、$sessionIdに関連付いた、指定$data文字列を、MongoDBや選択した別のストレージシステムなどの永続ストレージシステムに書き込む必要があります。繰り返しになりますが、シリアル化を実行しないでください。Laravelがすでにそれを処理しています。
  • destroyメソッドは、永続ストレージから$sessionIdに関連付いたデータを削除する必要があります。
  • gcメソッドは、指定$lifetime(UNIXタイムスタンプ)よりも古いすべてのセッションデータを破棄する必要があります。MemcachedやRedisなどの自己期限切れシステムの場合、このメソッドは空のままにしておくことができます。

ドライバの登録

ドライバを実装したら、Laravelへ登録する準備が済みました。Laravelのセッションバックエンドへドライバを追加するには、Sessionファサードが提供するextendメソッドを使用します。サービスプロバイダbootメソッドからextendメソッドを呼び出す必要があります。これは、既存のApp\Providers\AppServiceProviderから行うか、もしくはまったく新しいプロバイダを作成することもできます。

<?php

namespace App\Providers;

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

class SessionServiceProvider extends ServiceProvider
{
    /**
     * 全アプリケーションサービスの登録
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * アプリケーションの全サービスの初期起動処理
     *
     * @return void
     */
    public function boot()
    {
        Session::extend('mongo', function ($app) {
            // SessionHandlerInterfaceの実装を返す
            return new MongoSessionHandler;
        });
    }
}

セッションドライバを登録したら、config/session.php設定ファイルでmongoドライバを使用できます。

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる