由於 HTTP 驅動的應用程式是無狀態的,因此 Session 提供一種跨越多個請求來儲存關於使用者資訊的方法。Laravel 內建使用直觀且一致的 API 來存取各種 Session 後端,並支援目前較熱門的後端驅動,像是 Memcached 、 Redis 和資料庫。
Session 設定檔被存放在 config/session.php
。請確實的查看檔案中的可用選項。預設的 Laravel 被設定使用 file
Session 驅動,這對於許多應用程式來說算是不錯。在正式上線的應用程式中,你可能會考慮使用 memcached
或 redis
驅動來追求更快的 Session 效能。
Session driver
設定選項用來定義每個請求所儲存的 Session 資料位置。Laravel 內建幾個很棒的驅動,且能馬上應用:
{tip} 陣列式驅動被用於測試的時候,並防止 Session 中的資料被永久儲存。
在使用 database
Session 驅動時,你會需要建立一個資料表來放置 Session 項目。以下是使用 Schema
建立資料表的範例:
Schema::create('sessions', function ($table) {
$table->string('id')->unique();
$table->unsignedInteger('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
你可以使用 Artisan 的 session:table
指令來產生這個遷移檔:
php artisan session:table
php artisan migrate
在使用 Laravel 搭配 Redis Session 之前,你會需要透過 Composer 來安裝predis/predis
套件(~1.0)。你可以在 database
設定檔中設定你的 Redis。在 session
設定檔中,connection
選項可被用於指定 Session 要使用哪一個 Redis 連線。
Laravel 有兩種主要的方式來使用 Session 資料:全域的 session
輔助函式和透過 Request
實例。首先,讓我們觀察透過 Request
實例來存取該 Session,這個實例能直接注入在控制器的方法上。但請你記得,控制器方法依賴是透過 Laravel 服務容器來自動注入的:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* 顯示特定使用者的個人資料。
*
* @param Request $request
* @param int $id
* @return Response
*/
public function show(Request $request, $id)
{
$value = $request->session()->get('key');
//
}
}
當你從 Session 中取得一個值得時候,你也可以傳入一個預設的值作為 get
方法的第二個參數。如果 Session 中沒有指定的鍵,就會回傳這個預設值。如果你傳入一個閉包
作為 get
方法的預設值,結果請求的值並未存在時,就會執行閉包
與回傳它的結果:
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
你也可以使用全域的 session
PHP 函式來取得,並儲存 Session 中的資料。如果只使用一個字串參數來呼叫 session
輔助函式的時候,它會回傳 Session 鍵的值。當使用一組陣列的鍵與值來呼叫輔助函式時,這些值會被存到 Session 中:
Route::get('home', function () {
// 從 Session 中取得一段資料...
$value = session('key');
// 指定一個預設值...
$value = session('key', 'default');
// 在 Session 中儲存一段資料...
session(['key' => 'value']);
});
{tip} 不論是透過 HTTP 請求實例,還是使用全域的
session
輔助函式,這兩者之間並無實際上的差異。能透過assertSessionHas
方法在所有測試案例中測試這兩種方法。
如果你想要在 Session 中取得所有資料,你可以使用 all
方法:
$data = $request->session()->all();
要確定一個值是否存在於 Session,你可以使用 has
方法。如果該值存在,has
方法就會回傳 true
,如果沒有則回傳 null
:
if ($request->session()->has('users')) {
//
}
要確認一個值是否存在於 Session,縱使這個值是 null
,你可以使用 exists
方法。exists
方法會在該值存在時回傳 true
:
if ($request->session()->exists('users')) {
//
}
要在 Session 儲存資料,你通常會使用 put
方法或 session
輔助函式:
// 透過一個請求實例...
$request->session()->put('key', 'value');
// 透過全域輔助函式...
session(['key' => 'value']);
push
方法可被用於將一個新的值推入一組放置 Session 值的陣列。例如,如果 user.teams
鍵中有一組團隊名稱的陣列,你可以將一個新值推入陣列中,就像:
$request->session()->push('user.teams', 'developers');
pull
方法只用一行句子就能從 Session 中取得和刪除一個項目:
$value = $request->session()->pull('key', 'default');
有時你可能希望只有在下一個請求中才將項目儲存到 Session 裡。你可以使用 flash
方法來做到。使用這個方法來將資料儲存到 Session,資料只會保留到下一個 HTTP 請求之前,然後就會清除這些資料。快閃資料主要用於短期的狀態訊息:
$request->session()->flash('status', 'Task was successful!');
如果你需要保留快閃資料給更多的請求,你可以使用 reflash
方法,這方法會將所有快閃資料保留到額外的請求。如果你只需要指定快閃資料,你可以使用 keep
方法:
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
forget
方法會從 Session 中移除資料片段。如果你想要從 Session 中移除所有資料,你可以使用 flush
方法:
$request->session()->forget('key');
$request->session()->flush();
重新產生 Session ID 通常是為了預防惡意使用者利用 session fixation 來攻擊你的應用程式。
如果使用內建的 LoginController
,Laravel 會在認證過程中自動重新產生 Session ID。然而,如果你需要手動重新產生 Session ID,你可以使用 regenerate
方法。
$request->session()->regenerate();
你自訂的 Session 驅動會實作 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) {}
}
{tip} Laravel 內建沒有提供用來延伸的目錄。所以你可以隨意放置在你想要的地方。在本範例中,我們建立了一個
Extensions
目錄來放置MongoSessionHandler
。
由於這些方法不是那麼容易理解,所以讓我們快速的快速的了解每一個方法吧:
一旦你的驅動程式已經實作,你就可以準備在框架中註冊它,要新增額外的驅動到 Laravel Session 後端,你可以在 Session
facade 上使用 extend
。你應該從一個服務提供者 的 boot
方法中呼叫 extend
方法。你可以從現有的 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 boot()
{
Session::extend('mongo', function ($app) {
// 回傳 SessionHandlerInterface 實作...
return new MongoSessionHandler;
});
}
/**
* 在容器中註冊綁定。
*
* @return void
*/
public function register()
{
//
}
}
Session 驅動一旦被註冊,你就可以在 config/session.php
設定檔中使用 mongo
驅動。