Session
簡(jiǎn)介
由于 HTTP 驅(qū)動(dòng)是一種無(wú)狀態(tài)的協(xié)議鲜戒,這通常意味著服務(wù)端并不能清楚的知道當(dāng)前請(qǐng)求用戶(hù)與之前請(qǐng)求用戶(hù)間的關(guān)系赁炎,而 Session 提供了這種跨請(qǐng)求用戶(hù)的解決方案诵姜。Laravel 附帶了簡(jiǎn)潔統(tǒng)一的 API 來(lái)支持各種后端 session 驅(qū)動(dòng)蚊俺。對(duì)于 Memcached圈纺,Redis 和數(shù)據(jù)庫(kù)這種流行的后端驅(qū)動(dòng)了讨,Laravel 提供了開(kāi)箱即用的支持。
配置
session 的配置文件被存儲(chǔ)在 config/session.php
钧排。你應(yīng)該確保在使用前閱讀該文件中的配置項(xiàng)注釋敦腔。Laravel 對(duì)配置中的每一項(xiàng)都進(jìn)行了詳細(xì)的注釋。默認(rèn)的恨溜,laravel 配置使用的是 file
session 驅(qū)動(dòng)符衔,這對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō)已經(jīng)夠用了找前。但是在生產(chǎn)環(huán)境中還是建議使用 memcached
或者 redis
這種內(nèi)存級(jí)驅(qū)動(dòng),這對(duì)于應(yīng)用的 session 性能來(lái)說(shuō)會(huì)是一個(gè)很大的提升判族。
對(duì)于每個(gè)請(qǐng)求的 session 數(shù)據(jù)躺盛,都會(huì)存儲(chǔ)在你所定義的 session driver
所在的位置中。下列驅(qū)動(dòng)在 laravel 中可以開(kāi)箱即用:
-
file
- sessions 會(huì)存儲(chǔ)在storage/framework/sessions
中形帮。 -
cookie
- sessions 會(huì)被存儲(chǔ)在經(jīng)過(guò)安全加密的 cookies 中槽惫。 -
database
- sessions 會(huì)被存儲(chǔ)在你應(yīng)用中所使用的數(shù)據(jù)庫(kù)中。 -
memcached
/redis
- sessions 會(huì)被存儲(chǔ)在更快的內(nèi)存級(jí)存儲(chǔ)驅(qū)動(dòng)中辩撑。 -
array
- sessions 會(huì)使簡(jiǎn)單存儲(chǔ)在 PHP 的數(shù)組中躯枢,并且它不能被跨請(qǐng)求訪(fǎng)問(wèn)。
注意:
array
驅(qū)動(dòng)通常是用來(lái)進(jìn)行測(cè)試時(shí)使用的以避免持久的 session 數(shù)據(jù)槐臀。
驅(qū)動(dòng)先決條件
數(shù)據(jù)庫(kù)
當(dāng)使用 database
session 驅(qū)動(dòng)時(shí)锄蹂,你需要先創(chuàng)建一個(gè)表來(lái)存儲(chǔ) session 項(xiàng)。下面的例子是數(shù)據(jù)庫(kù) session 驅(qū)動(dòng)表的架構(gòu)聲明:
Schema::create('sessions', function ($table) {
$table->string('id')->unique();
$table->integer('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
你也可以使用 session:table
Artisan 命令來(lái)生成一個(gè)數(shù)據(jù)庫(kù)會(huì)話(huà)驅(qū)動(dòng)的遷移表:
php artisan session:table
composer dump-autoload
php artisan migrate
Redis
在使用 Redis session 驅(qū)動(dòng)之前水慨,你需要通過(guò) Composer 安裝 predis/predis
(~1.0)得糜。
其他 Session 注意事項(xiàng)
Laravel 框架內(nèi)部使用了 flash
作為 session 其中的一個(gè)鍵,所以你應(yīng)該避免使用該名稱(chēng)的鍵到 session 中晰洒。
如果你需要存儲(chǔ)安全加密后的 session 數(shù)據(jù)朝抖,你可以在配置文件中將 encrypt
選項(xiàng)設(shè)置為 true
。
基礎(chǔ)用法
訪(fǎng)問(wèn) Session
首先谍珊,讓我們來(lái)訪(fǎng)問(wèn) session治宣。我們可以通過(guò) HTTP 請(qǐng)求來(lái)訪(fǎng)問(wèn) session 的實(shí)例。HTTP 請(qǐng)求可以通過(guò)在控制器方法中使用類(lèi)型提示來(lái)進(jìn)行依賴(lài)注入砌滞。你應(yīng)該記得侮邀,控制器方法的依賴(lài)會(huì)通過(guò) laravel 的服務(wù)容器進(jìn)行注入:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @param Request $request
* @param int $id
* @return Response
*/
public function showProfile(Request $request, $id)
{
$value = $request->session()->get('key');
//
}
}
當(dāng)你從 session 中檢索值時(shí),你也可以指定一個(gè)默認(rèn)的值到 get
方法的第二個(gè)參數(shù)贝润,默認(rèn)值會(huì)在 session 未檢索到相應(yīng)鍵的值時(shí)返回绊茧。你也可以傳遞 Closure
作為默認(rèn)值,如果找不到相應(yīng)的鍵打掘,Closure
執(zhí)行的結(jié)果所返回的值將作為默認(rèn)值:
$value = $request->session()->get('key', 'default');
$value = $request->session()->get('key', function () {
return 'default';
});
如果你希望從 session 中檢索出所有的值华畏,你可以使用 all
方法:
$data = $request->session()->all();
你可以可以使用全局幫助方法 session
來(lái)進(jìn)行值的檢索和存儲(chǔ):
Route::get('home', function () {
// Retrieve a piece of data from the session...
$value = session('key');
// Store a piece of data in the session...
session(['key' => 'value']);
});
判斷 session 是否存在某項(xiàng)
你可以使用 has
方法來(lái)判斷 session 中是否含有某項(xiàng),如果存在則返回 true
:
if ($request->session()->has('user')) {
//
}
在 session 中存儲(chǔ)數(shù)據(jù)
一旦你獲取了 session 的實(shí)例尊蚁,你就擁有了和底層數(shù)據(jù)進(jìn)行交互的能力亡笑,你可以通過(guò)各種實(shí)例的方法來(lái)進(jìn)行交互。比如横朋,你可以使用 put
方法來(lái)在 session 中存儲(chǔ)一個(gè)新的數(shù)據(jù)項(xiàng):
$request->session()->put('key', 'value');
推送內(nèi)容到 session 中值為數(shù)組的項(xiàng)
你可以使用 push
方法來(lái)將一個(gè)新的值推送到 session 中值為數(shù)組的項(xiàng)中仑乌。比如,如果 user.teams
鍵表明了數(shù)組在 session 中的路徑,你可以像這樣推送新的值到該數(shù)組中:
$request->session()->push('user.teams', 'developers');
檢索并刪除某項(xiàng)
pull
方法會(huì)在檢索的同時(shí)在 session 中刪除該項(xiàng):
$value = $request->session()->pull('key', 'default');
刪除 session 中的某項(xiàng)
你可以使用 forget
方法來(lái)刪除 session 中的某一項(xiàng)數(shù)據(jù)绝骚,如果你想要移除 session 中的所有數(shù)據(jù),你可以使用 flush
方法:
$request->session()->forget('key');
$request->session()->flush();
重新生成 session ID
如果你需要重新生成 session ID祠够,你可以使用 regenerate
方法:
$request->session()->regenerate();
閃存數(shù)據(jù)
有時(shí)候你希望在 session 中存儲(chǔ)某些數(shù)據(jù)压汪,但是只允許下一次請(qǐng)求時(shí)使用,使用后即消除古瓤。那么就可以使用 flash
方法止剖。這方法在 session 中存儲(chǔ)的數(shù)據(jù)只能在隨后的請(qǐng)求中進(jìn)行訪(fǎng)問(wèn),并且在之后刪除落君。閃存的數(shù)據(jù)通常用來(lái)做一些臨時(shí)的狀態(tài)消息:
$request->session()->flash('status', 'Task was successful!');
如果你需要維持閃存的數(shù)據(jù)到更多的請(qǐng)求穿香,你可以使用 reflash
方法,它會(huì)維持所有的閃存數(shù)據(jù)到額外的請(qǐng)求中绎速。如果你只需要維持指定的閃存數(shù)據(jù)皮获,你可以使用 keep
方法:
$request->session()->reflash();
$request->session()->keep(['username', 'email']);
添加自定義的 Session 驅(qū)動(dòng)
你需要使用 Session
假面的 extend
方法才能添加額外的 session 驅(qū)動(dòng)到 Laravel 中。你可以在服務(wù)提供者的 boot
方法中來(lái)調(diào)用 extend
方法:
<?php
namespace App\Providers;
use Session;
use App\Extensions\MongoSessionStore;
use Illuminate\Support\ServiceProvider;
class SessionServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Session::extend('mongo', function ($app) {
// Return implementation of SessionHandlerInterface...
return new MongoSessionStore;
});
}
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
}
你應(yīng)該注意你的自定義 session 驅(qū)動(dòng)應(yīng)該實(shí)現(xiàn) SessionHandlerInterface
接口纹冤。該接口僅包含了幾個(gè)簡(jiǎn)單的需要實(shí)現(xiàn)的方法洒宝。一個(gè)實(shí)現(xiàn)了的 MongoDB 驅(qū)動(dòng)的結(jié)構(gòu)應(yīng)該像下面一樣:
<?php
namespace App\Extensions;
class MongoHandler 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) {}
}
由于這些方法并不像緩存的 StoreInterface
那樣難于理解。所以萌京,我們就來(lái)快速的過(guò)一下吧:
-
open
方法一般用于基于文件的 session 存儲(chǔ)系統(tǒng)雁歌。由于 laravel 已經(jīng)附帶了file
session 驅(qū)動(dòng),所以你幾乎不需要在這個(gè)方法中添加任何的代碼知残。你可以直接放置其為空方法靠瞎。事實(shí)上,這是一種可憐的接口設(shè)計(jì)(我們將會(huì)在后面討論它)求妹,PHP 必須要我們實(shí)現(xiàn)這個(gè)方法乏盐。 -
close
方法,類(lèi)似于open
方法制恍,你也可以對(duì)其進(jìn)行忽視丑勤,對(duì)于大多數(shù)驅(qū)動(dòng)來(lái)說(shuō)根本不需要。 -
read
方法應(yīng)該根據(jù)給定的$sessionId
返回 session 中關(guān)聯(lián)數(shù)據(jù)的字符串版本吧趣。你不需要在存儲(chǔ)或檢索時(shí)做任何的序列化或其它的編碼操作法竞,因?yàn)?laravel 會(huì)為你執(zhí)行序列化服務(wù)。 -
destroy
方法應(yīng)該從 session 存儲(chǔ)中刪除所關(guān)聯(lián)的數(shù)據(jù)强挫。 -
gc
方法應(yīng)該根據(jù)給定的$lifetime
UNIX 時(shí)間戳刪除 session 所關(guān)聯(lián)的過(guò)期數(shù)據(jù)岔霸。對(duì)于擁有自動(dòng)過(guò)期能力的系統(tǒng),比如 Memcached 和 Redis俯渤,你可以直接讓這個(gè)方法為空呆细。
一旦你的 session 驅(qū)動(dòng)被注冊(cè)。你就可以在 config/session.php
配置文件中使用 mongo
驅(qū)動(dòng)了八匠。