はじめに

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

Laravelは、表現力豊かで統一されたAPIを通じてアクセスされるさまざまなセッションバックエンドを提供しています。MemcachedRedis、およびデータベースなどの人気のあるバックエンドのサポートが含まれています。

設定

アプリケーションのセッション設定ファイルはconfig/session.phpに保存されています。このファイルで利用可能なオプションを確認してください。デフォルトでは、Laravelはdatabaseセッションドライバーを使用するように設定されています。

セッションdriver設定オプションは、各リクエストのためにセッションデータがどこに保存されるかを定義します。Laravelにはさまざまなドライバーが含まれています:

  • file - セッションはstorage/framework/sessionsに保存されます。
  • cookie - セッションは安全で暗号化されたクッキーに保存されます。
  • database - セッションはリレーショナルデータベースに保存されます。
  • memcached / redis - セッションはこれらの高速なキャッシュベースのストアのいずれかに保存されます。
  • dynamodb - セッションはAWS DynamoDBに保存されます。
  • array - セッションはPHP配列に保存され、永続化されません。

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

ドライバーの前提条件

データベース

databaseセッションドライバーを使用する場合、セッションデータを含むデータベーステーブルが必要です。通常、これはLaravelのデフォルト0001_01_01_000000_create_users_table.php データベースマイグレーションに含まれています。ただし、何らかの理由でsessionsテーブルがない場合は、make:session-table Artisanコマンドを使用してこのマイグレーションを生成できます:

  1. php artisan make:session-table
  2. php artisan migrate

Redis

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

  1. <a name="interacting-with-the-session"></a>
  2. ## セッションとの対話
  3. <a name="retrieving-data"></a>
  4. ### データの取得
  5. Laravelでセッションデータを操作する主な方法は2つあります:グローバル`````session`````ヘルパーと`````Request`````インスタンスを介してです。まず、`````Request`````インスタンスを介してセッションにアクセスする方法を見てみましょう。これはルートクロージャまたはコントローラメソッドで型ヒントできます。コントローラメソッドの依存関係は、Laravelの[サービスコンテナ](/read/laravel-11-x/89c648800d1f2464.md)を介して自動的に注入されることを忘れないでください:
  6. ``````php
  7. <?php
  8. namespace App\Http\Controllers;
  9. use Illuminate\Http\Request;
  10. use Illuminate\View\View;
  11. class UserController extends Controller
  12. {
  13. /**
  14. * Show the profile for the given user.
  15. */
  16. public function show(Request $request, string $id): View
  17. {
  18. $value = $request->session()->get('key');
  19. // ...
  20. $user = $this->users->find($id);
  21. return view('user.profile', ['user' => $user]);
  22. }
  23. }
  24. `

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

  1. $value = $request->session()->get('key', 'default');
  2. $value = $request->session()->get('key', function () {
  3. return 'default';
  4. });

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

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

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

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

すべてのセッションデータの取得

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

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

セッションデータの一部を取得

  1. ``````php
  2. $data = $request->session()->only(['username', 'email']);
  3. $data = $request->session()->except(['username', 'email']);
  4. `

セッション内にアイテムが存在するかどうかの判定

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

  1. if ($request->session()->has('users')) {
  2. // ...
  3. }

アイテムがセッション内に存在するかどうかを判定するには、その値がnullであっても、existsメソッドを使用できます:

  1. if ($request->session()->exists('users')) {
  2. // ...
  3. }

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

  1. if ($request->session()->missing('users')) {
  2. // ...
  3. }

データの保存

セッションにデータを保存するには、通常、リクエストインスタンスのputメソッドまたはグローバルsessionヘルパーを使用します:

  1. // Via a request instance...
  2. $request->session()->put('key', 'value');
  3. // Via the global "session" helper...
  4. session(['key' => 'value']);

配列セッション値へのプッシュ

  1. ``````php
  2. $request->session()->push('user.teams', 'developers');
  3. `

アイテムの取得と削除

  1. ``````php
  2. $value = $request->session()->pull('key', 'default');
  3. `

セッション値のインクリメントとデクリメント

セッションデータにインクリメントまたはデクリメントしたい整数が含まれている場合、incrementおよびdecrementメソッドを使用できます:

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

フラッシュデータ

時々、次のリクエストのためにセッションにアイテムを保存したい場合があります。flashメソッドを使用してこれを行うことができます。このメソッドを使用してセッションに保存されたデータは、すぐに利用可能で、次のHTTPリクエスト中に利用できます。次のHTTPリクエストの後、フラッシュデータは削除されます。フラッシュデータは主に短命のステータスメッセージに役立ちます:

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

フラッシュデータを複数のリクエストにわたって永続化する必要がある場合は、reflashメソッドを使用できます。これにより、すべてのフラッシュデータが追加のリクエストのために保持されます。特定のフラッシュデータのみを保持する必要がある場合は、keepメソッドを使用できます:

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

現在のリクエストのみにフラッシュデータを永続化するには、nowメソッドを使用できます:

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

データの削除

  1. ``````php
  2. // Forget a single key...
  3. $request->session()->forget('name');
  4. // Forget multiple keys...
  5. $request->session()->forget(['name', 'status']);
  6. $request->session()->flush();
  7. `

セッションIDの再生成

セッションIDの再生成は、悪意のあるユーザーがアプリケーションに対してセッション固定攻撃を悪用するのを防ぐために行われることがよくあります。

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

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

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

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

セッションブロッキング

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

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

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

  1. Route::post('/profile', function () {
  2. // ...
  3. })->block($lockSeconds = 10, $waitSeconds = 10)
  4. Route::post('/order', function () {
  5. // ...
  6. })->block($lockSeconds = 10, $waitSeconds = 10)
  1. `````block`````メソッドが受け入れる2番目の引数は、セッションロックを取得しようとする際にリクエストが待機する秒数です。指定された秒数内にセッションロックを取得できない場合、`````Illuminate\Contracts\Cache\LockTimeoutException`````がスローされます。
  2. これらの引数のいずれも渡されない場合、ロックは最大10秒間取得され、リクエストはロックを取得しようとする際に最大10秒間待機します:
  3. ``````php
  4. Route::post('/profile', function () {
  5. // ...
  6. })->block()
  7. `

カスタムセッションドライバーの追加

ドライバーの実装

既存のセッションドライバーがアプリケーションのニーズに合わない場合、Laravelは独自のセッションハンドラーを書くことを可能にします。カスタムセッションドライバーは、PHPの組み込みSessionHandlerInterfaceを実装する必要があります。このインターフェースには、いくつかのシンプルなメソッドが含まれています。スタブされたMongoDB実装は次のようになります:

  1. <?php
  2. namespace App\Extensions;
  3. class MongoSessionHandler implements \SessionHandlerInterface
  4. {
  5. public function open($savePath, $sessionName) {}
  6. public function close() {}
  7. public function read($sessionId) {}
  8. public function write($sessionId, $data) {}
  9. public function destroy($sessionId) {}
  10. public function gc($lifetime) {}
  11. }

Laravelには、拡張機能を含むディレクトリは付属していません。好きな場所に配置できます。この例では、Extensionsディレクトリを作成してMongoSessionHandlerを収容しました。

これらのメソッドの目的はすぐには理解できないため、各メソッドが何をするかを簡単に説明します:

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

ドライバーの登録

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

  1. <?php
  2. namespace App\Providers;
  3. use App\Extensions\MongoSessionHandler;
  4. use Illuminate\Contracts\Foundation\Application;
  5. use Illuminate\Support\Facades\Session;
  6. use Illuminate\Support\ServiceProvider;
  7. class SessionServiceProvider extends ServiceProvider
  8. {
  9. /**
  10. * Register any application services.
  11. */
  12. public function register(): void
  13. {
  14. // ...
  15. }
  16. /**
  17. * Bootstrap any application services.
  18. */
  19. public function boot(): void
  20. {
  21. Session::extend('mongo', function (Application $app) {
  22. // Return an implementation of SessionHandlerInterface...
  23. return new MongoSessionHandler;
  24. });
  25. }
  26. }

セッションドライバーが登録されると、mongoドライバーをアプリケーションのセッションドライバーとしてSESSION_DRIVER環境変数またはアプリケーションのconfig/session.php設定ファイル内で指定できます。