laravel 基础教程 —— Session

Session

简介

由于 HTTP 驱动是一种无状态的协议,这通常意味着服务端并不能清楚的知道当前请求用户与之前请求用户间的关系,而 Session 提供了这种跨请求用户的解决方案。Laravel 附带了简洁统一的 API 来支持各种后端 session 驱动。对于 MemcachedRedis 和数据库这种流行的后端驱动,Laravel 提供了开箱即用的支持。

配置

session 的配置文件被存储在 config/session.php。你应该确保在使用前阅读该文件中的配置项注释。Laravel 对配置中的每一项都进行了详细的注释。默认的,laravel 配置使用的是 file session 驱动,这对于大多数应用来说已经够用了。但是在生产环境中还是建议使用 memcached 或者 redis 这种内存级驱动,这对于应用的 session 性能来说会是一个很大的提升。

对于每个请求的 session 数据,都会存储在你所定义的 session driver 所在的位置中。下列驱动在 laravel 中可以开箱即用:

  • file - sessions 会存储在 storage/framework/sessions 中。
  • cookie - sessions 会被存储在经过安全加密的 cookies 中。
  • database - sessions 会被存储在你应用中所使用的数据库中。
  • memcached / redis - sessions 会被存储在更快的内存级存储驱动中。
  • array - sessions 会使简单存储在 PHP 的数组中,并且它不能被跨请求访问。

注意:array 驱动通常是用来进行测试时使用的以避免持久的 session 数据。

驱动先决条件

数据库

当使用 database session 驱动时,你需要先创建一个表来存储 session 项。下面的例子是数据库 session 驱动表的架构声明:

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

composer dump-autoload

php artisan migrate

Redis

在使用 Redis session 驱动之前,你需要通过 Composer 安装 predis/predis(~1.0)。

其他 Session 注意事项

Laravel 框架内部使用了 flash 作为 session 其中的一个键,所以你应该避免使用该名称的键到 session 中。

如果你需要存储安全加密后的 session 数据,你可以在配置文件中将 encrypt 选项设置为 true

基础用法

访问 Session

首先,让我们来访问 session。我们可以通过 HTTP 请求来访问 session 的实例。HTTP 请求可以通过在控制器方法中使用类型提示来进行依赖注入。你应该记得,控制器方法的依赖会通过 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 showProfile(Request $request, $id)
   {
     $value = $request->session()->get('key');

     //
   }
}

当你从 session 中检索值时,你也可以指定一个默认的值到 get 方法的第二个参数,默认值会在 session 未检索到相应键的值时返回。你也可以传递 Closure 作为默认值,如果找不到相应的键,Closure 执行的结果所返回的值将作为默认值:

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

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

如果你希望从 session 中检索出所有的值,你可以使用 all 方法:

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

你可以可以使用全局帮助方法 session 来进行值的检索和存储:

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 是否存在某项

你可以使用 has 方法来判断 session 中是否含有某项,如果存在则返回 true:

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

在 session 中存储数据

一旦你获取了 session 的实例,你就拥有了和底层数据进行交互的能力,你可以通过各种实例的方法来进行交互。比如,你可以使用 put 方法来在 session 中存储一个新的数据项:

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

推送内容到 session 中值为数组的项

你可以使用 push 方法来将一个新的值推送到 session 中值为数组的项中。比如,如果 user.teams 键表明了数组在 session 中的路径,你可以像这样推送新的值到该数组中:

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

检索并删除某项

pull 方法会在检索的同时在 session 中删除该项:

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

删除 session 中的某项

你可以使用 forget 方法来删除 session 中的某一项数据,如果你想要移除 session 中的所有数据,你可以使用 flush 方法:

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

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

重新生成 session ID

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

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

闪存数据

有时候你希望在 session 中存储某些数据,但是只允许下一次请求时使用,使用后即消除。那么就可以使用 flash 方法。这方法在 session 中存储的数据只能在随后的请求中进行访问,并且在之后删除。闪存的数据通常用来做一些临时的状态消息:

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

如果你需要维持闪存的数据到更多的请求,你可以使用 reflash 方法,它会维持所有的闪存数据到额外的请求中。如果你只需要维持指定的闪存数据,你可以使用 keep 方法:

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

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

添加自定义的 Session 驱动

你需要使用 Session 假面的 extend 方法才能添加额外的 session 驱动到 Laravel 中。你可以在服务提供者的 boot 方法中来调用 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()
    {
      //
    }
}

你应该注意你的自定义 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) {}
}

由于这些方法并不像缓存的 StoreInterface 那样难于理解。所以,我们就来快速的过一下吧:

  • open 方法一般用于基于文件的 session 存储系统。由于 laravel 已经附带了 file session 驱动,所以你几乎不需要在这个方法中添加任何的代码。你可以直接放置其为空方法。事实上,这是一种可怜的接口设计(我们将会在后面讨论它),PHP 必须要我们实现这个方法。
  • close 方法,类似于 open 方法,你也可以对其进行忽视,对于大多数驱动来说根本不需要。
  • read 方法应该根据给定的 $sessionId 返回 session 中关联数据的字符串版本。你不需要在存储或检索时做任何的序列化或其它的编码操作,因为 laravel 会为你执行序列化服务。
  • destroy 方法应该从 session 存储中删除所关联的数据。
  • gc 方法应该根据给定的 $lifetime UNIX 时间戳删除 session 所关联的过期数据。对于拥有自动过期能力的系统,比如 Memcached 和 Redis,你可以直接让这个方法为空。

一旦你的 session 驱动被注册。你就可以在 config/session.php 配置文件中使用 mongo 驱动了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,841评论 5 472
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,415评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,904评论 0 333
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,051评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,055评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,255评论 1 278
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,729评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,377评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,517评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,420评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,467评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,144评论 3 317
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,735评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,812评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,029评论 1 256
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,528评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,126评论 2 341

推荐阅读更多精彩内容