一、为什么要SESSION入库
SESSION默认的存储媒介是文件,php.ini中的session.sava.handler选项。当SESSION文件较多时,通过文件系统的操作SESSION数据,会产生访问速度瓶颈问题。
SESSION数据会被系统序列化存储在SESSION会话文件中: C:\Windows\Temp
通过改写SESSION的存储机制,将SESSION存储在数据库中(MYSQL)或者Memcached、Redis等缓存服务器中,便于提升大量SESSION数据的操作效率,也便于SESSION数据共享。
本文主要讲解SESSION入库(MYSQL)。通过阅读,你可以:
- 掌握SESSION自定义存储处理机制
- 加深对SESSION存储机制的理解,加深SESSION、COOKIE区别联系的理解
二、SESSION存储管理机制
详细请参考 <<
接口说明参考 <<
PHP提供自定义会话存储处理器
方式1:
session_set_save_handler ( callable $open , callable $close , callable $read , callable $write , callable $destroy , callable $gc [, callable $create_sid [, callable $validate_sid [, callable $update_timestamp ]]] )
//需要先定义对应的回调函数(系统自行调用)
//调用session_set_sava_handler函数完成以上函数的注册
方式2:
session_set_save_handler(SessionHandlerInterface $handler,是否注册shutdown回调函数=true)
//$handler是SessionHandlerInterface接口实现类的对象
三、创建数据库
#创建数据库
create database db_session charest utf8;
#选择数据库
user db_session;
#创建数据表
create table tb_session(
session_id varchar(100) primary key comment "会话内容",
session_data text comment "session数据序列化字符串",
session_time int not null default 0 comment "写入时间"
)charset =utf8 engine = innodb;
四、封装SESSION入库MYSQL
<?php
header("content-type:text/html;charset=utf8");
class MyHandler implements SessionHandlerInterface{
private $handle = null;
/**
* [open 准备工作:数据库连接]
* @param [type] $save_path [session文件的保存路径]
* @param [type] $session_name [COOKIE数据名(保存的是SESSION会话名称)]
*/
public function open($save_path, $session_name)
{
$handle = mysql_connect('localhost','root','root') or die('数据库连接失败'); //连接MySQL数据库
mysql_select_db('db_session',$handle) or die('数据库中没有此库名'); //找到数据库
return(true);
}
/**
* [read 按照会话名称,读取session数据]
* @param [type] $session_id [当前session会话的名称]
* @return [type] [session数据,从数据表中读取出来的序列化字符串]
*/
public function read($session_id)
{
$time = time(); //设定当前时间
$sql = "select session_data from tb_session where session_id = '$session_id' and session_time > $time";
$result = mysql_query($sql,$handle);
$row = mysql_fetch_array($result);
mysql_free_result($result); //释放结果集
if ($row){
return($row['session_data']); //返回Session名称及内容
}else{
return(false);
}
}
/**
* [close 收尾工作,断开连接]
* @return [type] [description]
*/
public function close()
{
mysql_close($handle);
return(true);
}
/**
* [write 按照session_id将数据写入数据表]
* @param [type] $session_id [当前会话名称]
* @param [type] $session_data [序列化后的session数据]
*/
public function write($session_id,$session_data)
{
$time = 60*60; //设置失效时间
$lapse_time = time() + $time; //得到UNIX时间戳
//如果会话存在 --更新操作
//会话不存在 --写入操作
//replace into --避免主键冲突
$sql = "replace into tb_session values ('$session_id','$session_data',$time);";
$result = mysql_query($sql,$handle);
return($result);
}
/**
* [destroy 销毁数据]
* @param [type] $session_id [销毁的会话数据对应的会话名称]
*/
public function destroy($session_id)
{
$sql = "delete from tb_session where session_id = '$session_id'"; //删除数据库sql语句
$result = mysql_query($sql,$handle);
return($result);
}
/**
* [gc 删除垃圾数据]
* @param [type] $expiry_time [垃圾回收机制中设定的最大时间]
*/
public function gc($expiry_time)
{
$lapse_time = time(); //将参数$expiry_time赋值为当前时间戳
$sql = "delete from tb_session where expiry_time < $lapse_time"; //删除数据库sql语句
$result = mysql_query($sql,$handle);
return($result);
}
}
//直接传递函数名
//如果该函数参数个数较少,可以使用匿名函数
//session_set_save_handler("open", "close", "read", "write", "destroy", "gc");
session_set_save_handler(new MyHandler, true);
/*// 开启SESSION会话 做准备工作
session_start();
$_SESSION['a']=1;
$_SESSION['b']='test_string';
*/
?>
五、FAQ
- 同一IP不同浏览器的SESSION不同?
- SESSION是基于浏览器的(SESSION是依赖于COOKIE)。每次浏览器请求时,系统安装浏览器版本信息,生成唯一的会话名称。不同浏览器请求,对应不同会话名称。
- open回调函数的传递的session_name意义?
- 用户请求时,浏览器会携带本网站的COOKIE数据给服务器脚本。session_name的值一般为PHPSESSID(可以在php.ini中的session.name进行设置)。
- PHP按照PHPSESSID读取对应的COOKIE数据,如果有,则就是本次会话的session_id。如果没有则自动创建新的session_id。
- 修改SESSION的保存时间,使其过期,下次访问SESSION数据一定会被清除吗?
- 不一定。SESSION的GC垃圾回收机制,是在SESSION初始化时,按照一定的概率进行启动。由PHP.ini中session.gc_probability/sessiongc_divisor计算出启动的概率。只有在垃圾回收机制被启动,才能回收过期数据。大型网站,概率应该设置适当的小,避免性能消耗。