Skip to content
赞助商赞助商赞助商
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

HTTP 会话

介绍

由于 HTTP 驱动的应用程序是无状态的,会话提供了一种在多个请求之间存储用户信息的方法。Laravel 附带了多种会话后端,可以通过一个富有表现力的统一 API 访问。支持流行的后端如 MemcachedRedis 和数据库的支持是开箱即用的。

配置

会话配置文件存储在 config/session.php。请务必查看此文件中可用的选项。默认情况下,Laravel 配置为使用 file 会话驱动程序,这对于许多应用程序来说效果很好。

会话 driver 配置选项定义了每个请求的会话数据存储位置。Laravel 附带了几个出色的驱动程序:

  • file - 会话存储在 storage/framework/sessions
  • cookie - 会话存储在安全加密的 cookie 中。
  • database - 会话存储在关系数据库中。
  • memcached / redis - 会话存储在这些快速的基于缓存的存储中。
  • array - 会话存储在 PHP 数组中,不会被持久化。

NOTE

数组驱动程序在测试期间使用,防止会话中存储的数据被持久化。

驱动程序先决条件

数据库

使用 database 会话驱动程序时,您需要创建一个表来包含会话项。以下是表的 Schema 声明示例:

php
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');
});

您可以使用 session:table Artisan 命令生成此迁移:

php
php artisan session:table

php artisan migrate

Redis

在使用 Laravel 的 Redis 会话之前,您需要通过 PECL 安装 PhpRedis PHP 扩展,或通过 Composer 安装 predis/predis 包(~1.0)。有关配置 Redis 的更多信息,请查阅其 Laravel 文档页面

NOTE

session 配置文件中,connection 选项可用于指定会话使用的 Redis 连接。

使用会话

检索数据

在 Laravel 中有两种主要方式处理会话数据:全局 session 辅助函数和通过 Request 实例。首先,让我们看看通过 Request 实例访问会话,这可以在控制器方法中进行类型提示。请记住,控制器方法依赖项会通过 Laravel 服务容器 自动注入:

php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 显示给定用户的个人资料。
     *
     * @param  Request  $request
     * @param  int  $id
     * @return Response
     */
    public function show(Request $request, $id)
    {
        $value = $request->session()->get('key');

        //
    }
}

当您从会话中检索一个项目时,您还可以将默认值作为 get 方法的第二个参数传递。如果指定的键不存在于会话中,将返回此默认值。如果您将 Closure 作为默认值传递给 get 方法,并且请求的键不存在,则将执行 Closure 并返回其结果:

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

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

全局会话助手

您还可以使用全局 session PHP 函数在会话中检索和存储数据。当 session 辅助函数用单个字符串参数调用时,它将返回该会话键的值。当辅助函数用键/值对数组调用时,这些值将存储在会话中:

php
Route::get('home', function () {
    // 从会话中检索一条数据...
    $value = session('key');

    // 指定默认值...
    $value = session('key', 'default');

    // 在会话中存储一条数据...
    session(['key' => 'value']);
});

NOTE

使用 HTTP 请求实例通过会话与使用全局 session 辅助函数之间几乎没有实际区别。两种方法都可以通过 assertSessionHas 方法进行测试,该方法在所有测试用例中可用。

检索所有会话数据

如果您想检索会话中的所有数据,可以使用 all 方法:

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

确定会话中是否存在某个项目

要确定会话中是否存在某个项目,可以使用 has 方法。如果项目存在且不为 nullhas 方法返回 true

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

要确定会话中是否存在某个项目,即使其值为 null,可以使用 exists 方法。如果项目存在,exists 方法返回 true

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

存储数据

要在会话中存储数据,通常使用 put 方法或 session 辅助函数:

php
// 通过请求实例...
$request->session()->put('key', 'value');

// 通过全局助手...
session(['key' => 'value']);

推送到数组会话值

push 方法可用于将新值推送到作为数组的会话值。例如,如果 user.teams 键包含一个团队名称数组,可以像这样将新值推送到数组中:

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

检索并删除项目

pull 方法将在单个语句中检索并删除会话中的项目:

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

闪存数据

有时您可能希望仅在下一个请求中存储会话中的项目。您可以使用 flash 方法来实现。使用此方法存储在会话中的数据将立即可用,并在后续 HTTP 请求期间可用。在后续 HTTP 请求之后,闪存数据将被删除。闪存数据主要用于短期状态消息:

php
$request->session()->flash('status', '任务成功完成!');

如果您需要将闪存数据保留多个请求,可以使用 reflash 方法,这将保留所有闪存数据以供额外请求。如果您只需要保留特定的闪存数据,可以使用 keep 方法:

php
$request->session()->reflash();

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

删除数据

forget 方法将从会话中删除一条数据。如果您想删除会话中的所有数据,可以使用 flush 方法:

php
// 忘记单个键...
$request->session()->forget('key');

// 忘记多个键...
$request->session()->forget(['key1', 'key2']);

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

重新生成会话 ID

重新生成会话 ID 通常是为了防止恶意用户利用您的应用程序进行会话固定攻击。

如果您使用内置的 LoginController,Laravel 会在身份验证期间自动重新生成会话 ID;但是,如果您需要手动重新生成会话 ID,可以使用 regenerate 方法。

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

添加自定义会话驱动程序

实现驱动程序

您的自定义会话驱动程序应实现 SessionHandlerInterface。此接口包含我们需要实现的几个简单方法。一个存根的 MongoDB 实现看起来像这样:

php
<?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

由于这些方法的目的不易理解,让我们快速介绍一下每个方法的作用:

  • open 方法通常用于基于文件的会话存储系统。由于 Laravel 附带了一个 file 会话驱动程序,您几乎不需要在此方法中放置任何内容。您可以将其保留为空存根。这是 PHP 需要我们实现此方法的糟糕接口设计的一个事实(我们将在后面讨论)。
  • close 方法与 open 方法一样,通常也可以忽略。对于大多数驱动程序,它是不需要的。
  • read 方法应返回与给定 $sessionId 关联的会话数据的字符串版本。在检索或存储会话数据时,您无需进行任何序列化或其他编码,因为 Laravel 会为您执行序列化。
  • write 方法应将与 $sessionId 关联的给定 $data 字符串写入某个持久存储系统,例如 MongoDB、Dynamo 等。同样,您不应执行任何序列化 - Laravel 已经为您处理了。
  • destroy 方法应从持久存储中删除与 $sessionId 关联的数据。
  • gc 方法应销毁所有比给定 $lifetime(UNIX 时间戳)更旧的会话数据。对于自我过期系统如 Memcached 和 Redis,此方法可以留空。

注册驱动程序

一旦实现了驱动程序,您就可以将其注册到框架中。要向 Laravel 的会话后端添加其他驱动程序,可以在 Session facade 上使用 extend 方法。您应该在 服务提供者boot 方法中调用 extend 方法。您可以从现有的 AppServiceProvider 中执行此操作,也可以创建一个全新的提供者:

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

    /**
     * 启动任何应用程序服务。
     *
     * @return void
     */
    public function boot()
    {
        Session::extend('mongo', function ($app) {
            // 返回 SessionHandlerInterface 的实现...
            return new MongoSessionHandler;
        });
    }
}

一旦会话驱动程序注册完毕,您可以在 config/session.php 配置文件中使用 mongo 驱动程序。