はじめに
HTTP駆動のアプリケーションはステートレスであるため、セッションは複数のリクエストにわたってユーザーに関する情報を保存する方法を提供します。そのユーザー情報は通常、後続のリクエストからアクセスできる永続ストア/バックエンドに配置されます。
Laravelは、表現力豊かで統一されたAPIを通じてアクセスされるさまざまなセッションバックエンドを提供しています。Memcached、Redis、およびデータベースなどの人気のあるバックエンドのサポートが含まれています。
設定
アプリケーションのセッション設定ファイルは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コマンドを使用してこのマイグレーションを生成できます:
php artisan make:session-table
php artisan migrate
Redis
LaravelでRedisセッションを使用する前に、PECLを介してPhpRedis PHP拡張をインストールするか、Composerを介してpredis/predis
パッケージ(~1.0)をインストールする必要があります。Redisの設定に関する詳細は、LaravelのRedisドキュメントを参照してください。
<a name="interacting-with-the-session"></a>
## セッションとの対話
<a name="retrieving-data"></a>
### データの取得
Laravelでセッションデータを操作する主な方法は2つあります:グローバル`````session`````ヘルパーと`````Request`````インスタンスを介してです。まず、`````Request`````インスタンスを介してセッションにアクセスする方法を見てみましょう。これはルートクロージャまたはコントローラメソッドで型ヒントできます。コントローラメソッドの依存関係は、Laravelの[サービスコンテナ](/read/laravel-11-x/89c648800d1f2464.md)を介して自動的に注入されることを忘れないでください:
``````php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*/
public function show(Request $request, string $id): View
{
$value = $request->session()->get('key');
// ...
$user = $this->users->find($id);
return view('user.profile', ['user' => $user]);
}
}
`
セッションからアイテムを取得する際、get
メソッドの第2引数としてデフォルト値を渡すこともできます。このデフォルト値は、指定されたキーがセッションに存在しない場合に返されます。get
メソッドにデフォルト値としてクロージャを渡し、要求されたキーが存在しない場合、クロージャが実行され、その結果が返されます:
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
グローバルセッションヘルパー
グローバルsession
PHP関数を使用して、セッション内のデータを取得および保存することもできます。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リクエストインスタンスを介してセッションを使用することと、グローバルsession
ヘルパーを使用することの間には、実用的な違いはほとんどありません。どちらの方法も、すべてのテストケースで利用可能なassertSessionHas
メソッドを介してテスト可能です。
すべてのセッションデータの取得
セッション内のすべてのデータを取得したい場合は、all
メソッドを使用できます:
$data = $request->session()->all();
セッションデータの一部を取得
``````php
$data = $request->session()->only(['username', 'email']);
$data = $request->session()->except(['username', 'email']);
`
セッション内にアイテムが存在するかどうかの判定
セッション内にアイテムが存在するかどうかを判定するには、has
メソッドを使用します。has
メソッドは、アイテムが存在し、true
でない場合にnull
を返します:
if ($request->session()->has('users')) {
// ...
}
アイテムがセッション内に存在するかどうかを判定するには、その値がnull
であっても、exists
メソッドを使用できます:
if ($request->session()->exists('users')) {
// ...
}
アイテムがセッション内に存在しないかどうかを判定するには、missing
メソッドを使用します。missing
メソッドは、アイテムが存在しない場合にtrue
を返します:
if ($request->session()->missing('users')) {
// ...
}
データの保存
セッションにデータを保存するには、通常、リクエストインスタンスのput
メソッドまたはグローバルsession
ヘルパーを使用します:
// Via a request instance...
$request->session()->put('key', 'value');
// Via the global "session" helper...
session(['key' => 'value']);
配列セッション値へのプッシュ
``````php
$request->session()->push('user.teams', 'developers');
`
アイテムの取得と削除
``````php
$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リクエストの後、フラッシュデータは削除されます。フラッシュデータは主に短命のステータスメッセージに役立ちます:
$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!');
データの削除
``````php
// Forget a single key...
$request->session()->forget('name');
// Forget multiple keys...
$request->session()->forget(['name', 'status']);
$request->session()->flush();
`
セッションIDの再生成
セッションIDの再生成は、悪意のあるユーザーがアプリケーションに対してセッション固定攻撃を悪用するのを防ぐために行われることがよくあります。
Laravelは、LaravelのアプリケーションスターターキットまたはLaravel Fortifyのいずれかを使用している場合、認証中に自動的にセッションIDを再生成します。ただし、手動でセッションIDを再生成する必要がある場合は、regenerate
メソッドを使用できます:
$request->session()->regenerate();
セッションIDを再生成し、単一のステートメントでセッションからすべてのデータを削除する必要がある場合は、invalidate
メソッドを使用できます:
$request->session()->invalidate();
セッションブロッキング
セッションブロッキングを利用するには、アプリケーションが原子的ロックをサポートするキャッシュドライバーを使用している必要があります。現在、これらのキャッシュドライバーには、memcached
、dynamodb
、redis
、database
、file
、およびarray
ドライバーが含まれています。さらに、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番目の引数は、セッションロックを取得しようとする際にリクエストが待機する秒数です。指定された秒数内にセッションロックを取得できない場合、`````Illuminate\Contracts\Cache\LockTimeoutException`````がスローされます。
これらの引数のいずれも渡されない場合、ロックは最大10秒間取得され、リクエストはロックを取得しようとする際に最大10秒間待機します:
``````php
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) {}
}
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
からこれを行うか、まったく新しいプロバイダーを作成できます:
<?php
namespace App\Providers;
use App\Extensions\MongoSessionHandler;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\ServiceProvider;
class SessionServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ...
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Session::extend('mongo', function (Application $app) {
// Return an implementation of SessionHandlerInterface...
return new MongoSessionHandler;
});
}
}
セッションドライバーが登録されると、mongo
ドライバーをアプリケーションのセッションドライバーとしてSESSION_DRIVER
環境変数またはアプリケーションのconfig/session.php
設定ファイル内で指定できます。