建表
既然要把session存入数据库,那首先要有一张存session的表了,我们在test库中创建一张session表
CREATE TABLE `session` (`session_id` CHAR(32) NOT NULL COMMENT 'sessionid',`session_data` TEXT NOT NULL COMMENT '数据',`session_expire` INT(11) NOT NULL COMMENT '过期时间',`session_expire_data` DATETIME NULL DEFAULT NULL COMMENT '过期时间,日期形式')COLLATE='utf8_general_ci'ENGINE=MyISAM;
重写session处理函数
有了表之后我们只需要重写session的处理函数就行了
处理函数为 session_set_save_handler(),他有6个参数,后面3个参数为可选参数,不用管。6个参数均为回调函数,下面我们一一来看
第一个参数 open($save_path,$session_name) — open 回调函数类似于类的构造函数, 在会话打开的时候会被调用。 这是自动开始会话或者通过调用 session_start() 手动开始会话 之后第一个被调用的回调函数。 此回调函数操作成功返回 TRUE,反之返回 FALSE。
第二个参数 close() — close 回调函数类似于类的析构函数。 在 write 回调函数调用之后调用。 当调用 session_write_close() 函数之后,也会调用 close 回调函数。 此回调函数操作成功返回 TRUE,反之返回 FALSE。
第三个参数 read($session_id) — 简单的说就是读取数据
第四个参数 write($session_id,$session_data) — 简单的说就是存储数据
第五个参数 destroy($session_id) — 删除数据
第六个参数 gc($expire_time) — 垃圾收集回调函数,用于删除过期数据,但是 调用周期由 session.gc_probability 和 session.gc_divisor 参数控制,默认应该为1/1000,可以把两个参数都修改为1,就是100%了
通过上面的了解后,下面我们直接看代码
<?php
/**
* 连接数据库
*/
function getConnection(){
$dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8", 'localhost', 'test');
$db_user = 'root';
$db_pass = 'root';
//指定查询结果集为关联数组
$option = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
$pdo = new PDO($dsn, $db_user, $db_pass, $option);
return $pdo;
}
/**
* 启动会话
*/
function my_session_open($save_path,$session_name){
return true;
}
/**
* 关闭会话
*/
function my_session_close(){
return true;
}
/**
* 读取数据 -- 必须返回 string
*/
function my_session_read($session_id){
$pdo = getConnection();
$sql = 'select * from session where session_id = :session_id and session_expire > :session_expire';
$sth = $pdo->prepare($sql);
$sth->bindValue(':session_id',$session_id);
$sth->bindValue(':session_expire',time());
$sth->execute();
$res = $sth->fetch();
if ($res) {
return $res['session_data'];
}
return '';
}
/**
* 写入数据
*/
function my_session_write($session_id,$session_data){
$pdo = getConnection();
$sql = 'select * from session where session_id = :session_id';
$sth = $pdo->prepare($sql);
$sth->bindValue(':session_id',$session_id);
$sth->execute();
$res = $sth->fetch();
$max_time = get_cfg_var('session.gc_maxlifetime');
$session_expire = time() + $max_time;
if ($res) {
//更新数据
$sql = 'update session set session_data = :session_data,session_expire = :session_expire,session_expire_data = :session_expire_data where session_id = :session_id';
}else{
//添加数据
$sql = 'insert into session (session_id,session_data,session_expire,session_expire_data) values (:session_id,:session_data,:session_expire,:session_expire_data)';
}
$sth = $pdo->prepare($sql);
$sth->bindValue(':session_id',$session_id);
$sth->bindValue(':session_data',$session_data);
$sth->bindValue(':session_expire',$session_expire);
$sth->bindValue(':session_expire_data',date('Y-m-d H:i:s',$session_expire));
$sth->execute();
return true;
}
/**
* 删除数据
*/
function my_session_destroy($session_id){
$pdo = getConnection();
$sql = 'delete from session where session_id = :session_id';
$sth = $pdo->prepare($sql);
$sth->bindValue(':session_id',$session_id);
$sth->execute();
return true;
}
/**
* 删除过期数据
*/
function my_session_gc($expire_time){
$pdo = getConnection();
$sql = 'delete from session where session_expire < :session_expire';
$sth = $pdo->prepare($sql);
$sth->bindValue(':session_expire',time());
$sth->execute();
return true;
}
session_set_save_handler('my_session_open','my_session_close','my_session_read','my_session_write','my_session_destroy','my_session_gc');
session_start();
$_SESSION['name'] = '小明';
echo $_SESSION['name'];
其实也可以使用 php自带的 SessionHandler 类,如
<?php
class Session extends SessionHandler{
protected $pdo;
public function __construct(){
$dsn = sprintf("mysql:host=%s;dbname=%s;charset=utf8", 'localhost', 'test');
$db_user = 'root';
$db_pass = 'root';
//指定查询结果集为关联数组
$option = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC);
$this->pdo = new PDO($dsn, $db_user, $db_pass, $option);
}
public function open($save_path, $session_name){
//...
return true;
}
public function close(){
//...
return true;
}
public function read($session_id){
//...
return '';
}
public function write($session_id, $session_data){
//...
return true;
}
public function destroy($session_id){
//...
return true;
}
public function gc($maxlifetime){
//...
return true;
}
}
session_set_save_handler(new Session());
存Rdis
可以和上面一样,写一个处理类
也可以直接用 ini_set() 函数
<?php
ini_set("session.save_handler", "redis");
ini_set("session.save_path", "tcp://127.0.0.1:6379");
//如果redis设置了密码,可以这样设置
ini_set("session.save_path", "tcp://127.0.0.1:6379?auth=authpwd");
结语
主要就是重新改写那几个回调函数,是不是很简单呢
