HTTP Session
Table of Contents
Introduction
HTTP 駆動型のアプリケーションはステートレスであるため、セッションは複数のリクエストにわたる user に関する情報を保存する方法を提供します。その user の情報は、通常、後続のリクエストからアクセスできる永続的なストア / バックエンドに配置されます。
Laravel は、表現力豊かで統一された API を通じてアクセスされる、様々な session バックエンドを標準装備しています。 Memcached 、Redis 、そしてデータベースのような人気のバックエンドに対応しています。
Configuration
あなたのアプリケーションの session 設定ファイルは config/session.php に保存されています。このファイル内の利用可能な options を確認するようにしてください。 default では、 Laravel は database session driver を使用するように設定されています。
session driver設定オプションは、各 request に対して session data がどこに保存されるかを定義します。 Laravel には様々なドライバーが含まれています:
file- セッションはstorage/framework/sessionsに保存されます。cookie- セッションは、安全で暗号化されたクッキーに保存されます。database- セッションは関係性のある database に保存されます。memcached/redis- セッションは、これらの高速で、 cache ベースのストアのいずれかに保存されます。dynamodb- セッションは AWS DynamoDB に保存されます。array- セッションは PHP の array に保存され、永続化されません。
NOTE
array driver は主にtesting中に使用され、保存されている data が session に永続化されるのを防ぎます。
Driver Prerequisites
Database
databaseの session driver を使用する際には、session data を含む database テーブルが存在することを確認する必要があります。通常、これは Laravel の default 0001_01_01_000000_create_users_table.php database migrationに含まれています。しかし、何らかの理由でsessionsテーブルがない場合は、make:session-table Artisan command を使用してこのマイグレーションを生成することができます:
php artisan make:session-table
php artisan migrate
Redis
Redissessions を Laravel で使用する前に、PECL 経由で PhpRedis PHP 拡張をインストールするか、predis/predisパッケージ(〜1.0)を Composer 経由でインストールする必要があります。 Redis の設定についての詳細は、Laravel のRedis ドキュメンテーションをご覧ください。
NOTE
SESSION_CONNECTION環境 variables、またはsession.php設定ファイルのconnectionoption を使用して、どの Redis 接続が sessionstorage に使用されるかを指定できます。
Interacting With the Session
Data の取得
二つの primary な方法が存在し、 session data を Laravel で扱うためにはグローバルなsessionヘルパーとRequestインスタンスがあります。まずは、Requestインスタンスを通じて session にアクセスする方法を見てみましょう。この方法は、 route クロージャまたは controller method に入力ヒントを与えることができます。そして覚えておいてください、 controller method の依存関係は自動的に Laravel のservice containerが注入されます。
<?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]);
}
}
あなたが session からアイテムを取得する際、get method の第二引数として default value を渡すことも可能です。この default value は、指定されたキーが session に存在しない場合に返されます。get method に default value としてクロージャを渡し、要求されたキーが存在しない場合、そのクロージャは実行され、その結果が返されます。
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
グローバル Session ヘルパー
あなたはまた、グローバルな session PHP 関数を使用して、 data を session に取得し保存することもできます。session ヘルパーが single の string 引数で呼び出された場合、その session キーの value が返されます。ヘルパーがキー/ value のペアの array で呼び出された場合、それらの values は 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']);
});
NOTE
HTTP requestインスタンス経由で session を使用するのと、グローバルsessionヘルパーを使用するのとの間には実質的な違いはほとんどありません。どちらの方法も、すべてのテストケースで利用可能なassertSessionHasmethod を介してテスト可能です。
すべての Session Data を取得する
もしすべての data を session から取得したい場合は、all method を使用することができます。
$data = $request->session()->all();
Session Data の一部を取得する
onlyおよびexceptメソッドは、 session data の一部を取得するために使用できます:
$data = $request->session()->only(['username', 'email']);
$data = $request->session()->except(['username', 'email']);
Session 内にアイテムが存在するかどうかの判断
アイテムが session に存在するかどうかを判断するために、has method を使用することができます。 has method は、アイテムが存在し、nullでない場合にtrueを返します。
if ($request->session()->has('users')) {
// ...
}
ある項目が session に存在するかどうかを判断するには、その value がnullであっても、exists method を使用できます:
if ($request->session()->exists('users')) {
// ...
}
アイテムが session に存在しないかどうかを判断するには、missing method を使用できます。 missing method は、アイテムが存在しない場合にtrueを返します。
if ($request->session()->missing('users')) {
// ...
}
Data の保存
data を session に保存するためには、通常、 request インスタンスのput method またはグローバルなsessionhelper を使用します。
// Via a request instance...
$request->session()->put('key', 'value');
// Via the global "session" helper...
session(['key' => 'value']);
Array Session Values へのプッシュ
push method は、 array である session value に新しい value をプッシュするために使用できます。例えば、user.teamskey がチーム名の array を含んでいる場合、以下のように新しい value を array にプッシュできます:
$request->session()->push('user.teams', 'developers');
アイテムの取得と Deleting
pull method は、シングル statement で session からアイテムを取得し削除します。
$value = $request->session()->pull('key', 'default');
Session Values の増分と減分
もし、あなたの session data が、増減させたい integer を含んでいるなら、incrementとdecrementmethod を使用することができます:
$request->session()->increment('count');
$request->session()->increment('count', $incrementBy = 2);
$request->session()->decrement('count');
$request->session()->decrement('count', $decrementBy = 2);
フラッシュ Data
時々、次の request のためにアイテムを session に保存したいと思うかもしれません。flash method を使用してこれを行うことができます。この method を使用して session に保存された Data はすぐに利用可能で、続く HTTP request の間も利用可能です。その次の HTTP request 後には、フラッシュされた data は削除されます。フラッシュ data は主に短命の status メッセージに役立ちます:
$request->session()->flash('status', 'Task was successful!');
もし複数の request のためにフラッシュ data を保持する必要がある場合は、reflash method を使用することで、全てのフラッシュ data を追加の request のために保持することができます。特定のフラッシュ data だけを保持する必要がある場合は、keep method を使用することができます。
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
現在の request のみに対してフラッシュ data を永続化するために、now method を使用することができます:
$request->session()->now('status', 'Task was successful!');
Deleting Data
forget method は、 session から 1 つの data を削除します。もし session からすべての data を削除したい場合は、flush method を使用することができます。
// Forget a single key...
$request->session()->forget('name');
// Forget multiple keys...
$request->session()->forget(['name', 'status']);
$request->session()->flush();
Session ID の再生成
session ID を再生成することは、悪意のある users があなたの application に対してsession 固定 攻撃を悪用するのを防ぐためによく行われます。
Laravel は、 Laravel のapplication スターターキットあるいはLaravel Fortifyを使用している場合、 authentication 中に自動的に session ID を再生成します。しかし、手動で session ID を再生成する必要がある場合、regenerate method を使用することができます。
$request->session()->regenerate();
もし session ID を再生成し、 session から全ての data を single statement で削除する必要がある場合、invalidate method を利用することができます:
$request->session()->invalidate();
Session Blocking
WARNING
session ブロッキングを利用するには、あなたの application はatomic locksをサポートする cache driver を使用している必要があります。現在、そのような cache ドライバには、
memcached、dynamodb、redis、database、file、arrayドライバが含まれます。さらに、cookieの session driver は使用できません。
default で、 Laravel は同じ session を使用したリクエストが concurrently で実行されることを許可しています。したがって、例えば JavaScript HTTP library を使って二つの HTTP requests をあなたの application に対して行った場合、それらは同時に実行されます。多くのアプリケーションではこれは問題ではありませんが、 session data の損失は、異なる二つの application エンドポイントに対して同時にリクエストを行い、両方が session に data を書き込むようなアプリケーションの一部で発生する可能性があります。
これを軽減するために、 Laravel は、特定の session に対する同時リクエストを制限する機能を提供します。始めるには、block method をあなたの route 定義に単純にチェインするだけです。この例では、/profileエンドポイントへの入力 request が session のロックを取得します。このロックが保持されている間、同じ session ID を共有する/profileまたは/orderエンドポイントへの他の入力リクエストは、最初の request が実行を終了するのを待ってから実行を続行します。
Route::post('/profile', function () {
// ...
})->block($lockSeconds = 10, $waitSeconds = 10)
Route::post('/order', function () {
// ...
})->block($lockSeconds = 10, $waitSeconds = 10)
block method は、二つの option の引数を受け付けます。block method によって最初に受け入れられる引数は、 session ロックが開放される前に維持されるべき最大の秒数です。もちろん、もし request がこの時間前に実行を終えれば、ロックはより早く解放されます。
block method が受け付ける第二引数は、 session のロックを取得しようとする際に request が待懸命になるべき秒数です。指定された秒数内に request が session のロックを取得できない場合、Illuminate\Contracts\Cache\LockTimeoutExceptionが throw されます。
これらの引数のいずれも渡されない場合、ロックは最大 10 秒間取得され、ロックの取得を試みる間、リクエストは最大 10 秒間待機します:
Route::post('/profile', function () {
// ...
})->block()
Adding Custom Session Drivers
Driver の実装
既存の sessiondrivers があなたの application のニーズに合わない場合、Laravel を使用すると、独自の session handler を記述することが可能です。あなたの custom session driver は、PHP の組み込みのSessionHandlerInterfaceを実装する必要があります。このインターフェースには、いくつかの単純な method が含まれています。スタブ化された 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 は、 extensions を格納するディレクトリを標準で提供していません。あなたは好きな場所にそれらを配置することができます。この例では、
MongoSessionHandlerを保存するためのExtensionsディレクトリを作成しました。
これらのメソッドの目的がすぐに理解できないため、それぞれのメソッドが何をするのかを簡単に説明しましょう:
openmethod は、通常、ファイルベースの session ストアシステムで使用されます。 Laravel はfileの session driver を標準で提供しているため、この method に何かを入れる必要はほとんどありません。この method は空のままにしておくことができます。closemethod は、openmethod と同様に、通常は無視できます。ほとんどの driver では、それは必要ではありません。readmethod は、与えられた$sessionIdに関連付けられた session data の string version を返すべきです。 session data をあなたの driver で取得または格納する際に、直列化や他のエンコーディングをする必要はありません。なぜなら、 Laravel が直列化を行ってくれるからです。writemethod は与えられた$datastring を$sessionIdと関連付けて、MongoDB や他の選択した storage システムなどの永続的な storage システムに書き込むべきです。再度、任意のシリアライゼーションを実行しないでください - Laravel がすでにそれを処理してくれています。destroymethod は、$sessionIdに関連付けられた data を永続的な storage から削除するべきです。gcmethod は、与えられた$lifetimeよりも古い全ての session data を破棄するべきです。これは UNIX の timestamp です。自身で有効期限が切れるシステム、例えば Memcached や Redis のようなものでは、この method は空のままにしておくことも可能です。
Registering the Driver
driver が実装されたら、それを Laravel に register する準備が整いました。Laravel の session バックエンドに追加の driver を追加するためには、Session facade によって提供される extend method を使用することができます。extend method は、service providerのboot method から呼び出すべきです。既存の App\Providers\AppServiceProviderから行うか、全く新しい provider を作成して行うことができます:
<?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 が登録されると、mongo driver をアプリケーションの session driver として指定できます。これは、SESSION_DRIVER environment 変数またはアプリケーションの config/session.php 構成ファイル内で行うことができます。