鍍金池/ 教程/ PHP/ Session
門面
Laravel Homestead
安裝及配置
測試
HTTP 中間件
加密
升級指南
幫助函數(shù)
應(yīng)用目錄結(jié)構(gòu)
集合
新手入門指南-簡單任務(wù)管理系統(tǒng)
任務(wù)調(diào)度
查詢構(gòu)建器
視圖
驗證
Laravel Cashier(訂購&支付&發(fā)票)
本地化
隊列
調(diào)整器
分頁
文件系統(tǒng)/云存儲
貢獻代碼
哈希
HTTP 控制器
緩存
遷移
HTTP 請求
Laravel Elixir
發(fā)行版本說明
Envoy 任務(wù)運行器(SSH任務(wù))
序列化
Session
起步
帶用戶功能的任務(wù)管理系統(tǒng)
起步
用戶授權(quán)
郵件
事件
填充數(shù)據(jù)
HTTP 路由
服務(wù)提供者
Blade 模板引擎
包開發(fā)
用戶認證
Artisan 控制臺
HTTP 響應(yīng)
集合
服務(wù)容器
關(guān)聯(lián)關(guān)系
一次請求的生命周期
契約
Redis
錯誤&日志

Session

1、簡介

由于 HTTP 驅(qū)動的應(yīng)用是無狀態(tài)的,所以我們使用 session 來存儲用戶請求信息。Laravel 通過干凈、統(tǒng)一的 API 處理后端各種有效 session 驅(qū)動,目前支持的流行后端驅(qū)動包括 Memcached、Redis 和數(shù)據(jù)庫。

1.1 配置

Session 配置文件位于 config/session.php。默認情況下,Laravel 使用的 session 驅(qū)動為文件驅(qū)動,這對許多應(yīng)用而言是沒有什么問題的。在生產(chǎn)環(huán)境中,你可能考慮使用 memcached或者 redis驅(qū)動以便獲取更快的 session 性能。

session 驅(qū)動定義請求的 session 數(shù)據(jù)存放在哪里,Laravel 可以處理多種類型的驅(qū)動:

  • file – session 數(shù)據(jù)存儲在 storage/framework/sessions目錄下;
  • cookie – session 數(shù)據(jù)存儲在經(jīng)過加密的安全的 cookie 中;
  • database – session 數(shù)據(jù)存儲在數(shù)據(jù)庫中
  • memcached / redis – session 數(shù)據(jù)存儲在 memcached/redis 中;
  • array – session 數(shù)據(jù)存儲在簡單 PHP 數(shù)組中,在多個請求之間是非持久化的。

注意:數(shù)組驅(qū)動通常用于運行測試以避免 session 數(shù)據(jù)持久化。

1.2 Session 驅(qū)動預(yù)備知識

1.2.1 數(shù)據(jù)庫

當使用 databasesession 驅(qū)動時,需要設(shè)置表包含 session 項,下面是該數(shù)據(jù)表的表結(jié)構(gòu)聲明:

Schema::create('sessions', function ($table) {
    $table->string('id')->unique();
    $table->text('payload');
    $table->integer('last_activity');
});

你可以使用 Artisan 命令 session:table 來生成遷移:

php artisan session:table
composer dump-autoload
php artisan migrate

1.2.2 Redis

在 Laravel 中使用 Redis session 驅(qū)動前,需要通過 Composer 安裝 predis/predis 包。

1.3 其它 Session 相關(guān)問題

Laravel 框架內(nèi)部使用flash session 鍵,所以你不應(yīng)該通過該名稱添加數(shù)據(jù)項到 session。 如果你需要所有存儲的 session 數(shù)據(jù)經(jīng)過加密,在配置文件中設(shè)置encrypt 配置為 true。

2、基本使用

訪問 session 首先,我們來訪問 session,我們可以通過 HTTP 請求訪問 session 實例,可以在控制器方法中通過類型提示引入請求實例,記住,控制器方法依賴通過 Laravel 服務(wù)容器注入:

<?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 showProfile(Request $request, $id)
    {
        $value = $request->session()->get('key');

        //
    }
}

從 session 中獲取數(shù)據(jù)的時候,還可以傳遞默認值作為第二個參數(shù)到get 方法,默認值在指定鍵在 session 中不存在時返回。如果你傳遞一個閉包作為默認值到 get 方法,該閉包會執(zhí)行并返回執(zhí)行結(jié)果:

$value = $request->session()->get('key', 'default');

$value = $request->session()->get('key', function() {
    return 'default';
});

如果你想要從 session 中獲取所有數(shù)據(jù),可以使用all方法:

$data = $request->session()->all();

還可以使用全局的 PHP 函數(shù) session來獲取和存儲 session 中的數(shù)據(jù):

Route::get('home', function () {
    // 從 session 中獲取數(shù)據(jù)...
    $value = session('key');

    // 存儲數(shù)據(jù)到 session...
    session(['key' => 'value']);
});

判斷 session 中是否存在指定項 has方法可用于檢查數(shù)據(jù)項在 session 中是否存在。如果存在的話返回 true

if ($request->session()->has('users')) {
    //
}

在 session 中存儲數(shù)據(jù) 獲取到 session 實例后,就可以調(diào)用多個方法來與底層數(shù)據(jù)進行交互,例如,put 方法存儲新的數(shù)據(jù)到 session 中:

$request->session()->put('key', 'value');

推送數(shù)據(jù)到數(shù)組 session push 方法可用于推送數(shù)據(jù)到值為數(shù)組的 session,例如,如果 user.teams 鍵包含團隊名數(shù)組,可以像這樣推送新值到該數(shù)組:

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

獲取并刪除數(shù)據(jù) pull 方法將會從 session 獲取并刪除數(shù)據(jù):

$value = $request->session()->pull('key', 'default');

從 session 中刪除數(shù)據(jù)項 forget 方法從 session 中移除指定數(shù)據(jù),如果你想要從 session 中移除所有數(shù)據(jù),可以使用 flush 方法:

$request->session()->forget('key');
$request->session()->flush();

重新生成 Session ID 如果你需要重新生成 session ID,可以使用 regenerate 方法:

$request->session()->regenerate();

2.1 一次性數(shù)據(jù)

有時候你可能想要在 session 中存儲只在下個請求中有效的數(shù)據(jù),可以通過flash 方法來實現(xiàn)。使用該方法存儲的 session 數(shù)據(jù)只在隨后的 HTTP 請求中有效,然后將會被刪除:

$request->session()->flash('status', 'Task was successful!');

如果你需要在更多請求中保持該一次性數(shù)據(jù),可以使用 reflash 方法,該方法將所有一次性數(shù)據(jù)保留到下一個請求,如果你只是想要保存特定一次性數(shù)據(jù),可以使用 keep 方法:

$request->session()->reflash();
$request->session()->keep(['username', 'email']);

3、添加自定義Session 驅(qū)動

要為 Laravel 后端 session 添加更多驅(qū)動,可以使用 Session 門面上的 extend 方法。可以在服務(wù)提供者的 boot 方法中調(diào)用該方法:

<?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()
    {
        //
    }
}

需要注意的是自定義 session 驅(qū)動需要實現(xiàn) SessionHandlerInterface 接口,該接口包含少許我們需要實現(xiàn)的方法,一個 MongoDB 的實現(xiàn)如下:

<?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 接口方法那樣容易理解,我們接下來快速過一遍每一個方法:

  • open 方法用于基于文件的 session 存儲系統(tǒng),由于 Laravel 已經(jīng)有了一個 file session 驅(qū)動,所以在該方法中不需要放置任何代碼,可以將其置為空方法。
  • close 方法和 open 方法一樣,也可以被忽略,對大多數(shù)驅(qū)動而言都用不到該方法。
  • read 方法應(yīng)該返回與給定$sessionId 相匹配的 session 數(shù)據(jù)的字符串版本,從驅(qū)動中獲取或存儲 session 數(shù)據(jù)不需要做任何序列化或其它編碼,因為 Laravel 已經(jīng)為我們做了序列化。
  • write 方法應(yīng)該講給定$data 寫到持久化存儲系統(tǒng)相應(yīng)的$sessionId , 例如 MongoDB, Dynamo 等等。
  • destroy方法從持久化存儲中移除 $sessionId 對應(yīng)的數(shù)據(jù)。
  • gc 方法銷毀大于給定$lifetime 的所有 session 數(shù)據(jù),對本身擁有過期機制的系統(tǒng)如 Memcached 和 Redis 而言,該方法可以留空。 session 驅(qū)動被注冊之后,就可以在配置文件 config/session.php 中使用 mongo 驅(qū)動了。