这里实现了一个把session存储到数据库的类,包括数据表的创建。类的使用。php的配置。 可以更好地进行用户控制管理。

做项目的时候,有一个需求,是要实现禁止一个账号两处登录。同时要统计当前在线用户数量,用户上下线时间。

然而用户并不一定会按正常流程通过点注销来下线,所以我们无法统计到精确的用户在线状态。我们能知道用户是什么时候上线的,不知道用户下线了没有。

后来决定用将session保存到数据库中,同时保存到数据表的还有该session的userid或adminid以及最后访问时间lastvisit。

这样,当我们查询有哪些用户在线的时候,就先清除一下session数据表中过期的session。然后从这找表中找到剩下的session表中保存的userid。更新用户登录表,将userid不在session表中的userid中的用户修改为下线。 这样就能一定程度下查找到当前在线用户了。

同时还有一个好处,就是因为session是保存在数据库中,所以只要在用户登录的时候,删除前一个使用这个userid登录的用户session。就能保证只有一个账户只能在一处登录了。

甚至可以通过session保存数据库来强制用户下线,也就是踢人功能。

将session保存到数据库貌似在集群服务器的时候也是有很大的优越性的。

上代码:

1.数据表:(session的内容就只是data字段的内容。 后面的adminid,userid,lastvisit是通过处理session时一起存下来的,方便跟其他表做一些关联操作。

2.ini_set('session.save_handler', 'user');   本来是应该在php.ini中修改这个。  默认的session.save_handler的值是file。我们这里不在php.ini中修改,是因为我们有一些上传文件的操作,必须要使用保存到文件中的session。 所以我们只在使用我们的session类之前加上这一句,临时修改成保存到用户自定。   放在我们的类使用前。

3.解析session。 事实上,在session数据流到我们的session类的时候,它是以这样的形式出现的:role|i:1;Name|s:5:"admin";AdminID|i:1;LoginTime|s:19:"2015-10-16 22:45:24";authnum_session|s:4:"6nfy";

我们要对它进行一定程度的解析,才能分析session中的字段,保存到我们创建的字段中去,比如userid,adminid。我们用这个函数来解析。

function unserializes($data_value) {
$vars = preg_split(
'/([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\|/',
$data_value, -1, PREG_SPLIT_NO_EMPTY |
PREG_SPLIT_DELIM_CAPTURE
);
for ($i = 0; isset($vars[$i]); $i++) {
$result[$vars[$i++]] = unserialize($vars[$i]);
}
return @$result;
}

4.接下来就是我们的session类。 注意,我的php版本是5.4。 在5.4之前不支持这种方法(不过有另外的处理机制,比较类似,5.4可以用类来实现,之前的版本是用几个函数来实现)。

ini_set('session.save_handler', 'user');
class MySessionHandler implements SessionHandlerInterface
{
private $savePath;
private $pdo;//创建数据库连接 //打开session的时候会最开始执行这里。
public function open($savePath, $sessionName)
{
//前面4行,是我们的数据库类来创建数据库连接,这样在其他几个函数就可以直接使用$pdo,操作数据库。
$pdo = new PDO('mysql:dbname=webserver;host=127.0.0.1;charset=utf8', 'root', '');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo = $pdo;
return true;
} public function close()
{
return true;
} //从数据库中读取Session数据
public function read($id)
{
$st = $this->pdo->prepare("select data from tb_session where id = ?");
$st->bindParam(1,$id);
$st->execute();
while($Row = $st->fetch(PDO::FETCH_BOTH)) {
@$SessionData = @$Row['data'];
}
return (string)@$SessionData;
} //用户访问的时候存入新的session,或更新旧的session.
//同时读取session中的userid或adminid写入数据表。
public function write($id, $data)
{
$time = time();
$st = $this->pdo->prepare("select id from tb_session where id =?");
$st->bindParam(1,$id);
$st->execute();
if(($Row = $st->fetch(PDO::FETCH_BOTH))){
$st = $this->pdo->prepare("update tb_session set data =?, lastvisit=? where id=?");
$st->bindParam(1,$data);
$st->bindParam(2,$time);
$st->bindParam(3,$id);
$st->execute();
}else{
$st = $this -> pdo->prepare("insert into tb_session (data,id,lastvisit) values (?,?,?)");
$st->bindParam(1,$data);
$st->bindParam(2,$id);
$st->bindParam(3,$time);
$st->execute();
}
$dataArr = unserializes($data);
if(@$dataArr['logining'] == 1){
//登录时通过$dataArr['UserID'] 和$dataArr['AdminID']的值保存到数据表的逻辑。代码略。
}
return true;
} //session销毁的时候,从数据表删除。
public function destroy($id)
{
$st = $this -> pdo->prepare("delete from tb_session where id=?");
$st->bindParam(1,$id);
$st->execute();
return true;
} //回收session的时候,让用户下线。记录下线时间。清除超期session。不是每次都会执行。是一个概率问题。可以在php.ini中调节。默认1/100。概率是session.gc_probability/session.gc_divisor。默认情况下,session.gc_probability = 1,session.gc_divisor =100,可在php.ini中修改
public function gc($maxlifetime)
{
//回收的时候存入在线时长。修改在线状态。代码略
//清除过期session
$timeNow = time();
$st = $this -> pdo->prepare("delete from tb_session where ($maxlifetime + lastvisit) < $timeNow");
$st->execute();
return true;
}
}

5.类的使用。使用之前调用此类。别忘记include_once("../class/session.class.php");   下面两句也可以放在session.class.php这个文件中,那么每次使用session的时候就只要session_start();就可以了。

6.php5.4之前存session到数据库的处理: https://www.cnblogs.com/fps2tao/p/9638839.html

转:https://blog.csdn.net/liusaint1992/article/details/49199947

参考:http://php.net/manual/zh/class.sessionhandlerinterface.php

php将session保存到数据库的类实例(php版本需要大于5.4)的更多相关文章

  1. ASP.NET将Session保存到数据库中

    因为ASP.NET中Session的存取机制与ASP相同,都是保存在进行中, 一旦进程崩溃,所有Session信息将会丢失,所以我采取了将Session信息保存到SQL Server中,尽管还有其它的 ...

  2. PHP SESSION 保存到数据库

    PHP SESSION 的工作原理 在客户端(如浏览器)登录网站时,被访问的 PHP 页面可以使用 session_start() 打开 SESSION,这样就会产生客户端的唯一标识 SESSION ...

  3. C# Oracle数据库操作类实例详解

    本文所述为C#实现的Oracle数据库操作类,可执行超多常用的Oracle数据库操作,包含了基础数据库连接.关闭连接.输出记录集.执行Sql语句,返回带分页功能的dataset .取表里字段的类型和长 ...

  4. 小技巧-ASP.Net session保存在数据库服务器

    引用博客:http://www.cnblogs.com/lykbk/archive/2013/01/13/hf576856868.html web Form 网页是基于HTTP的,它们没有状态, 这意 ...

  5. Asp.Net将Session保存在数据库中

    1.由于项目dll文件变动比较频繁,而保存登陆的状态又保存在Session中,所以导致用户经常无故掉线.(dll变动的时候导致Session丢失) 2.有一种方法可以长期保存session,那就是se ...

  6. php将会话保存在数据库里

    php默认把会话保存在临时文件中,保存在数据库中可以提高安全性,在共享主机服务器上,所有web站点都使用同一个临时目录,这意味着数十个程序都在同一位置进行文件读取的操作,我们很容易就编写一个脚本从这个 ...

  7. 进程外Session保存和全局文件错误捕获

    Session深入学习,进程外的Session 当用户登入页面跳转时候,我们会将用户登录信息保存在服务端一个键值对的Session(Session池)中.那么Session池又是在哪里呢? 它最终默认 ...

  8. Java中将图片保存到数据库中

    在实际的开发中,我们可能需要将图片.影音等文件直接保存到数据库中,然后通过编程方式将数据读出进行使用.例如将读出的图片数据显示出来,将读出的电影文件播放出来. 二进制数据直接保存到文件和从文件中读出非 ...

  9. 通用数据库操作类,前端easyui-datagrid,form

    实现功能:     左端datagrid显示简略信息,右侧显示选中行详细信息,数据库增删改 (1)点击选中行,右侧显示详细信息,其中[新增].[修改].[删除]按钮可用,[保存]按钮禁用 (2)点击[ ...

随机推荐

  1. [Javascript]1. Improve you speed! Loop optimaztion

    /** Improve you loop code */ var treasureChest = { goldCoins: 10000, magicalItem : "Crown of Sp ...

  2. [Node.js]30. Level 6: Listen 'Question' from client, and then Answer the Question

    Clients can also answer each other questions, so let's build that feature by first listening for the ...

  3. PS常用技能综合

    1.ps中怎么吧选中的一块区域覆盖到另一个区域中? 1.用PS中选取工具或套索工具--选好后用移动工具把你选取的区域移动到你要覆盖的地方2.或用图章工具中的仿制图章 2.如何将选中的区域新建为一个新图 ...

  4. C# 64位系统调用32位DLL异常解决办法(异常来自HRESULT :0x8007007E)

    解决办法如下 1.在IDE中将目标平台设置成x86(VS是在项目的属性->生成->目标平台) 2.如果DLL中调用了其他的DLL,需要将其他的DLL一同编译 3.有时DLL生成时会依赖于I ...

  5. 多mysql实例下开发需要注意主从同步延迟

    今天晚上服务器上线测试,遇到了一个问题! 往数据库写了一条数据之后,再读取该记录,居然读不出来,报空指针.十分费解,喊来开发组长定位问题.他的解释是:写操作用的是主库,而读操作用的是从库.在写库写完之 ...

  6. Java从零开始学三十七(JAVA IO- 二进制文件读写)

    一.简述 二.使用步骤 DataInputStream: 引入相关的类 构造数据输入流的对象(如:FileInputStream,BufferedWriter包装后读取文件等) 读取二进制文件的数据 ...

  7. HTML5 PACS 医学成像

    http://ivmartel.github.io/dwv/ http://oviyam.raster.in/oviyam2.html https://github.com/ivmartel/dwv ...

  8. serialize 序列化 +号处理

    少说多做,直接运行代码,代码中有注释: <!DOCTYPE html> <html lang="zh"> <head> <meta cha ...

  9. TCP并发server模型(三)

    本篇博客讲述的是单client单线程模型,该模型相同由主进程统一accept,仅仅是将fork改为了pthread_create. 与进程相比,线程有非常多长处(速度快,占用资源少.数据能够共享). ...

  10. Linux 系统访问控制列表ACL

    常见的文件系统的一般权限(rwx).特殊权限(SUID,SGID,STICK).隐藏权限(chattr)其实有个共性——权限是针对某一类用户设置的.而如果希望对某个指定的用户进行单独的权限控制,那么就 ...