會議
- 設定
- 驅動程式先決條件
- 全域輔助函數Session
- 取得所有的Session 資料
- 儲存資料
- #在Session 陣列中儲存資料
- 檢索& 刪除一條資料 重新產生Session ID
- 新增自訂Session 驅動程式
- ##實作驅動程式 ##註冊驅動程式
- #
HTTP 會話機制
簡介
#由於HTTP 驅動的應用程式是無狀態的,Session 提供了一種在多個請求之間儲存有關使用者資訊的方法,Laravel 透過同一個可讀性強的API 處理各種自帶的後台驅動程式。支援諸如比較熱門的 Memcached, Redis 和資料庫。
設定
#Session 的設定檔儲存在
config/session.php
檔案中。請務必查看此文件中對於你而言可用的選項。預設情況下,Laravel 為絕大多數應用程式配置的 Session 驅動為file
。在生產環境中,你可以考慮使用memcached
或redis
驅動,讓 Session 的效能更加出色。Session
driver
的設定預設了每個請求儲存 Session 資料的位置。 Laravel 自帶了幾個不錯而且開箱即用的驅動:file
- 將Session 儲存在storage/framework/sessions
中。cookie
- Sessions 被儲存在安全加密的 cookie 中。database
- Sessions 被儲存在關係型資料庫中。memcached
/redis
- Sessions 被儲存在基於快取的儲存系統中。array
- Sessions 儲存在 PHP 陣列中,但不會被持久化。
{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
Redis
Laravel 在使用 Redis 作為 Session 驅動程式之前,需要透過 Composer 安裝
predis/predis
擴充包 (~1.0)。然後在database
設定檔中配置 Redis 連線資訊。在session
設定檔中,connection
選項可用於指定 Session 使用哪個 Redis 連線。使用Session
在取得資料
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
方法的預設值,且所請求的鍵並不存在時,get
方法將執行閉包並傳回其結果:$value = $request->session()->get('key', 'default'); $value = $request->session()->get('key', function () { return 'default'; });
全域輔助函數Session
你也可以使用全域的PHP 輔助函數
session
來取得和儲存Session 資料。使用單一字串類型的值作為參數呼叫輔助函數session
時,它會傳回該字該符串對應的 Session 鍵的值。當使用鍵值對陣列作為參數呼叫輔助函數session
時,傳入的鍵值將會儲存在Session 中:Route::get('home', function () { // 获取 session 中的一条数据... $value = session('key'); // 指定一个默认值... $value = session('key', 'default'); // 在 Session 中存储一条数据... session(['key' => 'value']); });
{tip} 透過HTTP 請求實例操作Session 與使用全域輔助函數
session
兩者之間並沒有實質上的差異。這兩種方法都可以透過所有測試案例中可用的assertSessionHas
方法進行 測試 。來取得所有的Session 數據
如果你想要取得所有的Session 數據,可以使用
all
方法:$data = $request->session()->all();
判斷Session 中是否存在某個值
要確定Session 中是否存在某個值,可以使用
has
方法。如果該值存在且不為null
,那麼has
方法會傳回true
: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']);
在 Session 陣列中儲存資料
#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 ID 通常是為了防止惡意使用者利用 session fixation 對你的應用程式進行攻擊。
如果你使用了內建函數
LoginController
,Laravel 會自動重新產生身分認證中的 Session ID。否則,你需要手動使用regenerate
方法重新產生 Session ID。$request->session()->regenerate();
新增自訂Session 驅動程式
實作驅動器
你自訂的 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
。#由於以上方法並不是很容易理解,所以我們接下來快速過一遍每一個方法:
open
方法通常用於基於檔案的Session 儲存系統。因為 Laravel 已經附帶了一個file
Session 驅動程式。所以你不需要在該方法中放置任何程式碼。 PHP 要求必須要有這個方法的實作(這只是一個糟糕的介面設計),你只需要把這個方法置空。close
方法跟open
方法相似,通常也可以被忽略。對大多數的驅動而言,此方法不是必須的。read
方法應傳回與給定的$sessionId
相符的 Session 資料的字串格式。在你的自訂的驅動程式中取得或儲存 Session 資料時,不需要進行任何序列化或其他編碼,因為 Laravel 會自動為你執行序列化。write
方法將與$sessionId
關聯的給定的$data
字串寫入到一些持久化儲存系統,如MongoDB 、 Dynamo 等。再次重申,你不需要進行任何序列化或其他編碼,因為 Laravel 會自動為你處理這些事情。destroy
方法將會從持久化儲存中與刪除與$sessionId
相關的資料。gc
方法能銷毀給定的$lifetime
(UNIX 的時間戳記)之前的所有資料。對本身擁有過期機制的系統如 Memcached 和 Redis 而言,此方法可以置空。
註冊驅動程式
當實作驅動程式後,需要在框架中註冊它。在
Laravel
後端增加額外的驅動,需要使用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() { // } }
驅動程式完成註冊時,你可以在使用在設定檔
config/session. php
中使用mongo
驅動程式。本篇首刊在 LearnKu.com 網站上。
- 判斷Session 中是否存在某個值