前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >PHP设置Redis储存Session,自定义session驱动

PHP设置Redis储存Session,自定义session驱动

作者头像
宣言言言
发布于 2019-12-18 08:39:12
发布于 2019-12-18 08:39:12
1.8K00
代码可运行
举报
文章被收录于专栏:宣言(Siam)博客宣言(Siam)博客
运行总次数:0
代码可运行

我们在之前的文章已经讲到了session是将数据储存在本地文件中,并且将session_id返回给客户端(浏览器会储存在cookies里)。

那么当我们在负载均衡集群环境的时候,负载调度部分负责把客户端的请求按照不同的策略分配给后端服务节点。所以会出现我们在A机器设置了session,后面请求在B机器判断session依旧为空的情况。

常用的负载均衡环境处理session的策略

PHP也可以配置将session保存在redis或者memcache中,在几种用来存储会话数据的方式。显然是Redis在效率上要更快些,而与memcached相比,因为有持久化,也更安全一些。 所以也是常用的负载均衡环境处理session的策略。 但因为是将信息储存在内存中,可能会出现内存不足、利用率不高等问题。

优点:效率高 缺点:信息储存在内存中,会产生大小不一的内存块,内存无法完全利用,并且可能出现内存不足。

设置session处理

php中除了可以通过简单修改配置项来设定使用其他的session处理方式,同时也提供了对应的接口以便于我们自定义session的处理逻辑。

接下来我们来通过自定义redis处理session的逻辑来了解接口。

session_set_save_handler函数

session_set_save_handler()该函数定义用户session逻辑,如写入、取出、关闭等。 该函数的传参如下:

该函数有两种用法

在PHP5.4以前的用法

bool session_set_save_hanler(callback open,callback close,callback read,callback write,callback destory,callback gc)

可见该函数的几个参数接收都是以callback回调函数的形式的。

参数

描述

open

session打开时的回调函数。接收两个参数,第一个参数是保持session的路径,第二个参数是session的名字

close

当session操作完成时调用此函数。不接收参数。

read

以session_id作为参数。通过以session_id作为参数从数据存储方中取得数据,并返回此数据。如果数据为空,可以返回一个空字符串。此函数在调用session_start 前被触发

write

当数据存储时调用。接收两个参数,一个是session_id,另外一个是session的数据

destory

当调用session_destroy 函数时触发destroy函数。只有一个参数 session_id

gc

当php执行session垃圾回收机制时触发

调用方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php 

// 需要先引入自定义的SiamSession类(该类的实现逻辑于下面PHP5.4以后的实现相同),然后再设置到save_handler中去
// 也可以直接在参数处传递闭包

$siamSession = new SiamSession();
session_set_save_handler(
  [$siamSession,"open"],
  [$siamSession,"close"],
  [$siamSession,"read"],
  [$siamSession,"write"],
  [$siamSession,"destroy"],
  [$siamSession,"gc"]
);

// 开启
session_start();

※※※

在PHP5.4以后的用法 也是推荐的用法

session_set_save_handler ( object $sessionhandler [, bool $register_shutdown = TRUE ] ) : bool

参数

描述

sessionhandler

实现了 (SessionHandlerInterface, SessionIdInterface)或 SessionUpdateTimestampHandlerInterface 接口的对象, 例如 SessionHandler。

register_shutdown

将函数 session_write_close() 注册为 register_shutdown_function() 函数。在PHP函数停止执行时可以触发。

session_write_close()函数:结束当前会话并存储会话数据。

调用方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php 

// 需要先引入自定义的Session处理程序,然后再设置到save_handler中去
// 也可以直接在参数处传递闭包

$siamSession = new SiamSession();
session_set_save_handler($siamSession, true);

// 开启
session_start();

我们看到第一个参数的描述,传入的参数应该是一个实现了 SessionHandlerInterface 接口的对象

同时还可以附属实现 SessionIdInterfaceSessionUpdateTimestampHandlerInterface 接口

那么我们先来看看这几个接口需要实现什么方法

从SessionHandler理解几个接口实现

在描述中可以看到举例传入的参数可以为SessionHandler,也就是如果我们想要自定义Session处理程序,可以参考该类需要实现的方法。

  • 这个类是设计用于公开当前内部PHP Session处理程序,如果想要自己实现PHP Session处理程序,请实现 SessionHandlerInterface接口
  • 从SessionHandler继承的类,可以通过调用父类方法来重写覆盖具体操作,例如将数据加密储存。并且将新类通过session_set_save_handler()设置为PHP Session处理程序
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
// SessionHandler 实现了SessionHandlerInterface和SessionIdInterface两个接口
// 其中 SessionIdInterface 提供了 create_sid 接口,可以自定义session_id的生成规则
// 其他的方法则由 SessionHandlerInterface 提供,主要是session的回调处理,如打开、关闭、gc、写入、读取
SessionHandler implements SessionHandlerInterface , SessionIdInterface {
    /**
     * close方法,当session关闭的时候触发
     */
    public close ( void ) : bool
    /**
     * create_sid方法,返回一个新创建的session_id
     */
    public create_sid ( void ) : string
    /**
     * destroy方法,当调用session_destroy的时候触发
     */
    public destroy ( string $session_id ) : bool
    /**
     * gc方法,当php程序gc清理的时候触发,主要用于清除已经过期的session
     */
    public gc ( int $maxlifetime ) : int
    /**
     * open方法,当session打开的时候触发
     */
    public open ( string $save_path , string $session_name ) : bool
    /**
     * read方法,读取session的处理逻辑,可以在这里解密储存数据
     * 在session_start后会触发
     */
    public read ( string $session_id ) : string

    /**
     * write方法,将session数据写入到储存中,可以在这里加密数据
     */
    public write ( string $session_id , string $session_data ) : bool
}

还有另一个接口是SessionUpdateTimestampHandlerInterface 我们看看它又提供了什么方法的接口

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SessionUpdateTimestampHandlerInterface {
    /**
     * 更新时间戳,即更新session过期时间的
     */
    abstract public updateTimestamp ( string $key , string $val ) : bool
    /**
     * 验证session_id 是否还在线
     */ 
    abstract public validateId ( string $key ) : bool
}

SessionHandlerInterface 接口是PHP >= 5.4.0 提供的 SessionIdInterface 接口是PHP >= 5.5.1 提供的 SessionUpdateTimestampHandlerInterface 接口是PHP >= 7.0 提供的


接下来我们通过代码来实践一下,通过实现SessionHandlerInterface接口,来写一个redis的PHP Session处理程序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php

class SiamSession  implements \SessionHandlerInterface
{
    private $redis;
    private $expTime = 30; // 默认超时时间 根据业务场景设置

    function __construct(){
        // 连接redis
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1',6379);

        // 设置session处理回调 并且将session_write_close注册为register_shutdown_function函数
        session_set_save_handler($this, true);

        // 开启
        session_start();

    }

    function open($path, $name)
    {
        return true;
    }

    function close(){
        return true;
    }

    function read($session_id)
    {
        $value = $this->redis->get("siam_".$session_id);
        if ($value){
            return $value;
        }
        return '';
    }

    function write($session_id, $data)
    {
        if( $this->redis->set("siam_".$session_id, $data) ){
            $this->redis->expire("siam_".$session_id, $this->expTime);
            return true;
        }
        return false;
    }

    function destroy($session_id)
    {
        if ( $this->redis->delete("siam_".$session_id) )
        {
            return true;
        }
        return false;
    }

    function gc($maxlifetime)
    {
        return true; // 因为redis设置了过期时间,不需要再gc回收
    }

    function __destruct()
    {
        session_write_close();
    }
}

new SiamSession();

接着我们在另一个文件中写下测试代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
require_once "SiamSession.php";

$_SESSION['name'] = "siam";
echo $_SESSION['name'];

可以看到浏览器正常出现了siam

那么我们进入phpredisadmin查看一下数据 可以看到类似图片的情况

其他的储存可以参考上面的处理,对数据进行处理,就可以实现自己的session处理器了

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019.08.30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
转 PHP下的session的生存周期
首先说一下session的创建的开始到结束的过程。 当程序需要为某个客户端的请求创建一个 session 的时候,服务器首先会检查这个客户端是否已经包含了一个 session 标识,这个我们称为 session id(获取方法为 session_id() ),如果已包含一个 session id 则说明此客户端之前已经创建过 session,服务器则按照 session id 把这个 session 中的值检索出来,如果客户端不包含 session id,说明此客户端第一次请求服务器或手动清除过缓存文件,则
霡霂
2018/06/04
7800
PHP网络技术(六)——session及与cookie的比较
PHP网络技术(六) ——session及与cookie的比较 (原创内容,转载请注明来源,谢谢) 一、概念 session是持续的、双向性的连接。其是通过在cookie中存储sessionID,实现session的传递,以区分不同用户的session。 与cookie的存储方式不同,session存储在服务端,每个session一个文件进行存储。通过上述的sessionID,可以获取不同的session文件。session文件名是sess_32位随机字符串,里面的内容形如:变量名|类型:
用户1327360
2018/03/07
9460
php实现SESSION跨域
稍微大一点的网站,通常都会有不只一个服务器,每个服务器运行着不同的功能模块或者不同的子系统,他们使用不同的二级域名,比如www.a.com、 i.a.com、bbs.a.com。而一个整体性强的网站,用户系统是统一的,即一套用户名、密码在整个网站的各个子系统中都是可以登录使用的。各个服 务器共享用户数据是比较容易实现的,只需要在后端放个数据库服务器,各个服务器通过统一接口对用户数据进行访问即可。但还存在一个问题,就是用户在 i.a.com登录之后,进入www.a.com时,仍然需要重新登录,基本的通行证的问
wangxl
2018/03/08
2.6K0
PHP全栈学习笔记4
JavaScript是网景公司开发的,是一种基于对象和事件驱动并具有安全性能的解释型脚本语言。
达达前端
2019/07/03
2.8K0
PHP全栈学习笔记4
PHP全栈学习笔记9
http最大特点是无连接无状态,clinet到http request到server,server到http response到clinet。
达达前端
2019/07/03
6500
PHP全栈学习笔记9
Redis保存PHP Session方法
Redis保存session用的命令是setex,用redis-cli monitor实时监测可以检测到。
wangxl
2018/07/27
5.6K1
Redis保存PHP Session方法
[android] 与PHP的session进行交互demo
从MainActivity跳转到MailIndexActivity,第一个请求接口设置session,第二个activity请求接口获取session
唯一Chat
2019/09/11
6770
Redis专题(十)——Redis存储Session
Redis专题(十) ——Redis存储session (原创内容,转载请注明来源,谢谢) 一、概述 PHP默认是将session存于服务器的文件中。当并发量大,此方式效率低,因此可以采用redis存储session。 要改变session的存储位置,首先要改变php.ini中的配置项session.save_handler,将其值设置为user。 二、改变存储位置函数 php内置的函数session_set_save_handler可以重新设定session的保存方
用户1327360
2018/03/07
1.3K0
PHP会话技术session我不允许还有人不会!
🎬 鸽芷咕:个人主页 🔥 个人专栏:《速学数据结构》 《C语言进阶篇》
鸽芷咕
2023/12/25
2030
PHP会话技术session我不允许还有人不会!
php负载中使用redis实现session会话保持
首先要明确session和cookie的区别。浏览器端存的是cookie每次浏览器发请求到服务端是http 报文头是会自动加上你的cookie信息的。服务端拿着用户的cookie作为key去存储里找对应的value(session). 同一域名下的网站的cookie都是一样的。所以无论几台服务器,无论请求分配到哪一台服务器上同一用户的cookie是不变的。也就是说cookie对应的session也是唯一的。 所以,这里只要保证多台业务服务器访问同一个redis服务器(或集群)就行了。
张琳兮
2019/03/14
1.4K0
Go 语言面向对象教程 —— 接口篇:接口定义与实现
接口在 Go 语言中有着至关重要的地位,如果说 goroutine 和 channel 是支撑起 Go 语言并发模型的基石,那么接口就是 Go 语言整个类型系统的基石。Go 语言的接口不单单只是接口,下面就让我们一步步来探索 Go 语言的接口特性。
学院君
2019/08/08
8420
Laravel源码分析之Session
由于HTTP最初是一个匿名、无状态的请求/响应协议,服务器处理来自客户端的请求然后向客户端回送一条响应。现代Web应用程序为了给用户提供个性化的服务往往需要在请求中识别出用户或者在用户的多条请求之间共享数据。Session 提供了一种在多个请求之间存储、共享有关用户的信息的方法。 Laravel 通过同一个可读性强的 API 处理各种自带的 Session 后台驱动程序。
KevinYan
2019/10/13
1.1K0
如何使用Redis接管文件存储
前言php默认使用文件存储session,如果并发量大,效率会非常低。而redis对高并发的支持非常好,可以利用redis替换文件来存储session。
友儿
2022/09/11
8070
【PHP小课堂】深入学习PHP中的SESSION(一)
其实 SESSION 这个话题本来也并不想多说的,毕竟它也是我们学习 PHP 的一个必然要接触的内容。或者说,不管是什么语言,只要是做 WEB 开发,都会和 SESSION 打交道,但是在面试的时候,SESSION 和 Cookie 也是经常会被问到的问题。既然如此,那么我们还是来深入的学习一下 SESSION 中的一些函数的具体作用吧。。
硬核项目经理
2024/06/13
970
【PHP小课堂】深入学习PHP中的SESSION(一)
如何运用PHP+REDIS解决负载均衡后的session共享问题
稍大一些的网站,通常都会有好几个服务器,每个服务器运行着不同功能的模块,使用不同的二级域名,而一个整体性强的网站,用户系统是统一的,即一套用户名、密码在整个网站的各个模块中都是可以登录使用的。各个服务器共享用户数据是比较容易实现的,只需要在后端放个数据库服务器,各个服务器通过统一接口对用户数据进行访问即可。但还存在一个问题,就是用户在这个服务器登录之后,进入另一个服务器的别的模块时,仍然需要重新登录,这就是一次登录,全部通行的问题,映射到技术上,其实就是各个服务器之间如何实现共享 SESSION 数据的问题。
宜信技术学院
2019/06/28
2K0
带你走入redis的应用场景(补充一)
1. 字符串类型1.1 常用APISET key value //存入...
友儿
2022/09/11
2830
PHP 于小项目:从鉴权说起
在当今这个开发技术多样化的时代,选择合适的开发语言和框架常常决定了项目的效率与成败。对于个人开发者,特别是那些进行小型、短期项目的人来说,PHP 是一种特别友好的选择。本文将通过介绍 PHP 实现鉴权(登录)的方式,探讨为何它如此适合个人开发者的临时小项目。
创意锦囊
2024/09/27
1020
PHP 于小项目:从鉴权说起
php session基本原理解析
本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn
仙士可
2019/12/19
3600
PHP中的Session工作机制与Session ID的实现原理
客户端第一次访问某服务器,为每个访问者创建一个唯一的 id (UID),并基于这个 UID 来存储变量。UID 存储在 cookie 中,亦或通过 URL 进行传导。
友儿
2022/09/11
2.2K0
带你走进PHP session反序列化漏洞
前些天打了巅峰极客,遇到了一题 session 反序列化,借此机会整理一下php session 反序列化的前生今世,愿与君共勉,如若有错,还望斧正
p4nda
2023/01/03
1.8K0
相关推荐
转 PHP下的session的生存周期
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文