首页 » Laravel 5.3 中文文档 » 正文

「Laravel 5.3 中文文档」HTTP 层 – Session

简介

由于 HTTP 驱动的应用是无状态的,session 提供了一种在多个请求中保存用户信息的方式。Laravel 提供的多种后端可以通过丰富、统一的 API 进行调用。默认支持像 MemcachedRedis、以及数据库等流行的后端驱动。

配置

Session 配置文件存储在 config/session.php。记得查看一下该配置文件中对你可用的选项。默认情况下,Laravel 使用 file session 驱动,它对于大多数应用来说都是可用的。在生产环境的应用中,你可以考虑使用性能更好的 memcachedredis 驱动。

Session 的 driver 配置项定义了在哪里存储每个请求的  session 数据。Laravel 提供了几个开机即用的非常棒的驱动:

  • file – session 存储在 storage/framework/sessions
  • cookie – session 存储在安全、加密的 cookie 中。
  • database – session 存储在关系型数据库中。
  • memcached / redis – sessions 保存在其中一个快速且基于缓存的存储系统中。
  • array – session 存储在 PHP 数组中,但不是持久化的。

array 驱动一般用于测试,阻止数据被持久化的存储在 session 中。

驱动先决条件

数据库

当使用 database session 驱动时,你需要创建一个包含 session 元素的数据表,下面是对这个表的 Schema 声明的例子:

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 命令来生成这个迁移:

php artisan session:table

php artisan migrate

Redis

在 Laravel 中使用 Redis 驱动前,你需要通过 Composer 安装 predis/predis 包(~1.0)。你可以在 database 配置文件中配置你的 redis 连接项。在 session 配置文件中,connection 配置项可以用来指定使用哪个 redis 链接存储 session。

使用 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
{
    /**
     * Show the profile for the given user.
     *
     * @param  Request  $request
     * @param  int  $id
     * @return Response
     */
    public function show(Request $request, $id)
    {
        $value = $request->session()->get('key');

        //
    }
}

当你从 session 中获取值的时候,你还可以给 get 方法传递第二个参数作为默认值。当指定的 key 在 session 中不存在时会返回默认值。如果你给 get 方法传递一个 Closure 作为默认值,并且请求的 key 不存在,Closure 将会被执行并返回其结果:

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

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

全局 session 辅助函数

你还可以使用全局的 session 辅助函数在 session 中获取及存储数据。当只给 session 辅助函数传递一个字符串参数时,当给其传递一个 key / value 键值对进行调用时,那些值将会被被存储到 session 中:

Route::get('home', function () {
    // Retrieve a piece of data from the session...
    $value = session('key');

    // Specifying a default value...
    $value = session('key', 'default');

    // Store a piece of data in the session...
    session(['key' => 'value']);
});
使用 HTTP 请求实例及全局的 session 辅助函数之间几乎没有任何不同。两个方法都是可以通过assertSessionHas 测试的,它在任何测试案例中都可用。

获取所有 session 数据

如果你想获取 session 中的所有数据,你可以使用 all 方法:

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

判断一个项是否在 session 中存在

要判断一个值是否在 session 中设置了,你可以使用 has 方法。如果值存在则 has 方法会返回 true,否则会返回 false

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

要判断一个值是否在 session 设置了,甚至它的值是 null,你可以使用 exist 方法,当值设置了时,exist 方法会返回 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!');

如果你需要在几个请求内保持闪存数据,你可以使用 reflush 方法,它将为一个额外的请求保存所有的闪存数据。如果你只想保持指定的闪存数据,你可以使用 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。然而,如果你需要手动重新生成 Session ID,你可以使用 regenerate 方法:

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

添加自定义 Session 驱动

实现驱动

你的自定义 session 驱动需要实现 SessionHandlerInterface。这个接口包含了一些我们需要实现的简单的方法。MongoDB 的实现差不多是这样的:

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

Laravel 没有提供包含扩展的文件夹。你可以根据自己的喜好来存放它们。在这个例子中,我们创建一个 Extensions 文件夹来存放 MongoHandler

由于这些方法的意图并不是很容易理解,我们来快速看一下每个方法的作用:

  • open 方法一般用于基于文件的 session 存储系统。由于 Laravel 提供了 file 驱动,所以你不需要在这个方法中做任何操作。你可以让它保持是空的。这是一个弱的接口设计(我们后面会讨论),PHP 要求我们实现该方法。
  • close 方法,同 open 方法一样,一般不需要理会。对于大多数驱动,它都是不需要的。
  • read 方法需要返回与给定的 $sessionId 相关的 session 数据的字符串版本。不需要做序列化或任何其他编码,因为 Laravel 已经为我们执行了序列化。
  • write 方法应该把给定的 $data 字符串与 $sessionId 关联持续化到存储系统,例如 MongoDB、Dynamo 等。再次强调,你不需要执行任何序列化 – Laravel 已经为我们处理了。
  • destroy 方法需要从存储系统删除所有与 $sessionId 相关的数据。
  • gc 方法需要删除所有比给定的 $lifetime (Unix 时间戳)早的数据。对于自动过期的系统,如 Memcached 和 Redis,这个方法可以留空。

注册驱动

当你的驱动实现后,你就可以在框架中注册它了。要向 Laravel 的 session 后端添加额外的驱动,你可以使用 Session facade 的 extend 方法。你需要在服务提供者boot 方法中调用 extend 方法,你可以在已存在的 AppServiceProvider 中或创建一个新的提供者:

<?php

namespace App\Providers;

use App\Extensions\MongoSessionStore;
use Illuminate\Support\Facades\Session;
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 驱动注册后,你可以在 config/session.php 中使用 mongo 驱动。


该篇属于专题:《Laravel 5.3 中文文档

发表评论