简介
由于 HTTP 驱动的应用是无状态的,session 提供了一种在多个请求中保存用户信息的方式。Laravel 提供的多种后端可以通过丰富、统一的 API 进行调用。默认支持像 Memcached、Redis、以及数据库等流行的后端驱动。
配置
Session 配置文件存储在 config/session.php
。记得查看一下该配置文件中对你可用的选项。默认情况下,Laravel 使用 file
session 驱动,它对于大多数应用来说都是可用的。在生产环境的应用中,你可以考虑使用性能更好的 memcached
或 redis
驱动。
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']); });
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 中文文档》