メインコンテンツまでスキップ

HTTP セッション

はじめに

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 コマンドを使用できます:

php artisan make:session-table

php artisan migrate

Redis

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

注記

SESSION_CONNECTION 環境変数、または session.php 構成ファイルの connection オプションを使用して、セッションストレージに使用する Redis 接続を指定できます。

セッションとのやり取り

データの取得

Laravel でセッションデータを操作する主な方法は、グローバルの session ヘルパーと Request インスタンスを介した方法の2つです。まず、Request インスタンスを介してセッションにアクセスする方法を見てみましょう。これは、ルートクロージャやコントローラーメソッドで型ヒントとして使用できます。コントローラーメソッドの依存関係は、Laravel の サービスコンテナ を介して自動的にインジェクションされます:

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

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

only メソッドと except メソッドを使用して、セッションデータのサブセットを取得できます:

    $data = $request->session()->only(['username', 'email']);

$data = $request->session()->except(['username', 'email']);

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

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

    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']);

配列セッション値への追加

push メソッドを使用して、配列であるセッション値に新しい値を追加できます。たとえば、user.teams キーがチーム名の配列を含んでいる場合、次のようにして配列に新しい値を追加できます:

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

アイテムの取得と削除

pull メソッドは、セッションからアイテムを取得して削除するための単一のステートメントです:

    $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!');

データの削除

forget メソッドは、セッションからデータを削除します。セッションからすべてのデータを削除したい場合は、flush メソッドを使用できます:

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

セッションブロッキング

警告

セッションブロッキングを利用するには、アプリケーションが アトミックロック をサポートするキャッシュドライバを使用している必要があります。現在、これらのキャッシュドライバには、memcacheddynamodbredisdatabasefile、および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つのオプション引数を受け入れます。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) {}
}

注記

Laravelには拡張機能を格納するディレクトリが含まれていません。どこにでも配置することができます。この例では、Extensionsディレクトリを作成してMongoSessionHandlerを配置しています。

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

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

ドライバーの登録

ドライバーが実装されたら、Laravelに登録する準備が整います。Laravelのセッションバックエンドに追加のドライバーを追加するには、Session ファサード が提供する extend メソッドを使用できます。extend メソッドを サービスプロバイダboot メソッドから呼び出すべきです。既存の 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;
});
}
}

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