session 存入数据库 php

时间:2023-03-08 23:17:48
session 存入数据库 php
  •  session 机制

1、php中session的生成机制

session是保存在服务器的,当我们在代码中调用session_start();时,PHP会同时往SESSION的存放目录(默认为/tmp/)和客户端的 cookie目录各生成一个文件。session文件名称像这样:

session 存入数据库 php

格式为sess_{SESSIONID} ,这时session文件中没有任何内容,当我们在session_start();并添加了这两行代码:

$_SESSION['name'] = 'wanchun0222';

$_SESSION['blog'] = 'coderbolg.net';

session文件会生成如下代码保存在session文件中
name|s:11:"wanchun0222";blog|s:13:"coderbolg.net";

这时再看看cookie:

session 存入数据库 php

可以看到服务器为我们自动生成了一个cookie,cookie名称为"PHPSESSID",cookie内容是一串字符,其实这串字符就是
{SESSIONID}。当我们使用session时,PHP就先生成一个唯一的SESSIONID号(如
2bd170b3f86523f1b1b60b55ffde0f66),再在我们服务器的默认目录下生成一个文件,文件名为
sess_{SESSIONID},同时在当前用户的客户端生成一个cookie,内容已经说过了。这样PHP会为每一个用户生成一个
SESSIONID,也就是说一个用户一个session文件。PHP第一次为某个用户使用session时就向客户端写入了cookie,当这个用户以
后访问时,浏览器会带上这个cookie,PHP在拿到cookie后就读出里面的SESSIONID,拿着这个SESSIONID去session目录
下找session文件。找到后在调用$_SESSION['blog']的时候显示出来。

2、php中session的过期回收机制

我们明白了session的生成及工作原理,发现在session目录下会有许多session文件。当然这些文件一定不是永远存在的,PHP一定
提供了一种过期回收机制。在php.ini中session.gc_maxlifetime为session设置了生存时间(默认为1440s)。如果
session文件的最后更新时间到现在超过了生存时间,这个session文件就被认为是过期的了。在下一次session回收的时候就会被删除。那下
一次session回收是在什么时候呢?这和php请求次数有关的。在PHP内部机制中,当php被请求了N次后就会有一次触发回收机制。到底是请求多少
次触发一次是通过以下两个参数控制的:

session.gc_probability = 1

session.gc_divisor = 100

这是php.ini的默认设置,意思是每100次PHP请求就有一次回收发生。概率是 gc_probability/gc_divisor 。我们了解了服务器端的session过期机制,再来看看客户端的cookie的过期机制。

如果cookie失效了浏览器自然发送不了cookie到服务器,这时即使服务器的session文件存在也没用,因为PHP不知道要读取哪个
session文件。我们知道PHP的cookie过期时间是在创建时设置的,那么PHP在创建session的同时为客户端创建的cookie的生命周
期是多久呢?这个在php.ini中有设置:session.cookie_lifetime
。这个值默认是0,代表浏览器一关闭SESSIONID就失效。那就是说我们把session.gc_maxlifetime和
session.cookie_lifetime设置成同一个值就可以控制session的失效时间了。

3、php中session的客户端存储机制

由上面的介绍我们可以知道,如果用户关闭了cookie,那我们的session就完全没法工作了。是的,确实是这样。php中session的客
户端存储机制只有cookie吗?不是的。既然我们的SESSIONID
不能通过cookie传递到各个页面,那我们还有另一个法宝,就是通过页面GET传值的方式。

PHP可以在cookie被禁用时自动通过GET方式跨页传递SESSIONID,前提是设置php.ini的
session.use_trans_sid为1。这时当我们在客户端禁用了cookie时使用了session,并在当前页面通过点击链接到另一页面
时,PHP会自动在链接上添加SESSIONID参数,像这
样:nextpage.php?SESSIONID=2bd170b3f86523f1b1b60b55ffde0f66。

  • session存入MySQL 数据库
<?php
/*============================文件说明========================================
@filename: session.class.php
@description: 数据库保存在线用户session,实现在线用户功能!
@notice: session过期时间一个小时,因为我们的站点是使用cookie(有效时间是1小时)登录。
          因此我们只记录用户登录的时间,而不是刷新一次更新一次
          删除数据库中session记录的动作发生在用户超时后执行这个文件或正常退出(session_destory)
@database: database:sessions field:sessionid(char32),uid(int10),last_visit(int10)
@author: duanjianbo
@adddate 2008-8-29
=============================================================================
*/
class session {
private $db;
private $lasttime=3600;//超时时间:一个小时
function session(&$db) {
$this->db = &$db;
session_module_name('user'); //session文件保存方式,这个是必须的!除非在Php.ini文件中设置了
session_set_save_handler(
array(&$this, 'open'), //在运行session_start()时执行
array(&$this, 'close'), //在脚本执行完成或调用session_write_close() 或 session_destroy()时被执行,即在所有session操作完后被执行
array(&$this, 'read'), //在运行session_start()时执行,因为在session_start时,会去read当前session数据
array(&$this, 'write'), //此方法在脚本结束和使用session_write_close()强制提交SESSION数据时执行
array(&$this, 'destroy'), //在运行session_destroy()时执行
array(&$this, 'gc') //执行概率由session.gc_probability 和 session.gc_divisor的值决定,时机是在open,read之后,session_start会相继执行open,read和gc
);
session_start(); //这也是必须的,打开session,必须在session_set_save_handler后面执行
}
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;
}
function open($path, $name) {
return true;
}
function close() {
$this->gc($this->lasttime);
return true;
}
function read($SessionKey){
$sql = "SELECT uid FROM sessions WHERE session_id = '".$SessionKey."' limit 1";
$query =$this->db->query($sql);
if($row=$this->db->fetch_array($query)){
return $row['uid'];
}else{
return "";
}
}
function write($SessionKey,$VArray) {
require_once(MRoot.DIR_WS_CLASSES .'db_mysql_class.php');
$db1=new DbCom();
// make a connection to the database... now
$db1->connect(DB_SERVER, DB_SERVER_USERNAME, DB_SERVER_PASSWORD, DB_DATABASE);
$db1->query("set names utf8");
$this->db=$db1;
$SessionArray = addslashes($VArray);
$data=$this->unserializes($VArray);
$sql0 = "SELECT uid FROM sessions WHERE session_id = '".$SessionKey."' limit 1";
$query0 =$this->db->query($sql0);
if($this->db->num_rows($query0)<=0){
if (isset($data['webid']) && !empty($data['webid'])) {
$this->db->query("insert into `sessions` set `session_id` = '$SessionKey',uid='".$data['webid']."',last_visit='".time()."'");
}
return true;
}else{
/*$sql = "update `sessions` set ";
if(isset($data['webid'])){
$sql .= "uid = '".$data['webid']."', " ;
}
$sql.="`last_visit` = null "
. "where `session_id` = '$SessionKey'";
$this->db->query($sql); */
return true;
}
}
function destroy($SessionKey) {
$this->db->query("delete from `sessions` where `session_id` = '$SessionKey'");
return true;
}
function gc($lifetime) {
$this->db->query("delete from `sessions` where unix_timestamp(now()) -`last_visit` > '".$this->lasttime."'");
return true;
}
}
?>

以上代码放入到文件session_db.php中,

然后每一个文件头最上方引用一下include_once('session_db.php')即可。

另外,在php.ini中要将session.save_handler设置为"user"即可。

这样就可以将数据库保存到mysql的tb_session表中,可以有很多人访问,再也不用担心访问的人过多导致session_temp文件目录中的碎文件过多读取效率低下的问题了。

随辅:tb_session的数据库脚本:

CREATE TABLE `tb_session` (

`session_key` varchar(30) NOT NULL,

`session_data` varchar(60) DEFAULT NULL,

`session_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (`session_key`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

以下同上代码作用一致,代码稍作调整

<?php
/*
*@author Fahy
*数据库为mysql,
*数据库名为session,表名为session,
*表中字段包括PHPSESSID,update_time,client_ip,data
*/
class Session{
private static $handler = null;
private static $ip = null;
private static $lifetime = null;
private static $time = null; //配置静态变量
private static function init($handler){
self::$handler = $handler; //获取数据库资源
self::$ip = !empty($_SERVER["REMOTE_ADDR"])? $_SERVER["REMOTE_ADDR"]:'unkonw'; //获取客户端ip
self::$lifetime = ini_get('session.gc_maxlifetime'); //获取session生命周期
self::$time = time(); //获取当前时间
}
//调用session_set_save_handler()函数并开启session
static function start($pdo){
self::init($pdo);
session_set_save_handler(
array(__CLASS__,'open'),
array(__CLASS__,'close'),
array(__CLASS__,'read'),
array(__CLASS__,'write'),
array(__CLASS__,'destroy'),
array(__CLASS__,'gc')
);
session_start();
} public static function open($path,$name){
return true;
}
public static function close(){
return true;
} //查询数据库中的数据
public static function read($PHPSESSID){
$sql = "select PHPSESSID,update_time,client_ip,data from session where PHPSESSID=?";
$stmt = self::$handler->prepare($sql);
$stmt->execute(array($PHPSESSID));
if(!$result = $stmt->fetch(PDO::FETCH_ASSOC)){
return '';
}
if(self::$ip == $result['client_ip']){
self::destroy($PHPSESSID);
return '';
}
if(($result['update_time']+self::$lifetime)<self::$time){
self::destroy($PHPSESSID);
return '';
}
return $result['data'];
}
/*
*首先查询该session是否存在数据,如果存在,则更新数据,如果不存在,则插入数据
*/
//将session写入数据库中,$data传入session中的keys和values数组
public static function write($PHPSESSID,$data){
$sql = "select PHPSESSID,update_time,client_ip,data from session where PHPSESSID=?";
$stmt = self::$handler->prepare($sql);
$stmt->execute(array($PHPSESSID)); if($result=$stmt->fetch(PDO::FETCH_ASSOC)){
if($result['data'] != $data || self::$time > ($result['update_time']+)){
$sql = "update session set update_time=?,data=? where PHPSESSID = ?";
$stmt = self::$handler->prepare($sql);
$stmt->execute(array($self::$time,$data,$PHPSESSID));
}
}else{
if(!empty($data)){
try{
$sql = "insert into session(PHPSESSID,update_time,client_ip,data) values(?,?,?,?)";
}catch(PDOException $e){
echo $e->getMessage();
}
$sth = self::$handler->prepare($sql);
$sth->execute(array($PHPSESSID,self::$time,self::$ip,$data));
}
}
return true;
} public static function destroy($PHPSESSID){
$sql = "delete from session where PHPSESSID = ?";
$stmt = self::$handler->prepare($sql);
$stmt->execute(array($PHPSESSID));
return true;
}
public static function gc($lifetime){
$sql = "delete from session where update_time<?";
$stmt = self::$handler->prepare($sql);
$stmt->execute(array(self::$time-$lifetime));
return true;
}
}
//使用PDO连接数据库
try{
$pdo = new PDO("mysql:host=localhost;dbname=session","root","hwj193");
}catch(PDOException $e){
echo $e->getMessage();
}
//传递数据库资源
Session::start($pdo);
  • session存入数据库(在thinkphp中)
<?php
try{
$pdo = new PDO('mysql:host=localhost;dbname=rphp4zf', 'root','');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); new SessionToDB($pdo);
} catch(PDOException $e) {
echo 'Error: '.$e->getMessage();
} class SessionToDB
{
private $_path = null;
private $_name = null;
private $_pdo = null;
private $_ip = null;
private $_maxLifeTime = 0; public function __construct(PDO $pdo)
{
session_set_save_handler(
array(&$this, 'open'),
array(&$this, 'close'),
array(&$this, 'read'),
array(&$this, 'write'),
array(&$this, 'destroy'),
array(&$this, 'gc')
); $this->_pdo = $pdo;
$this->_ip = !empty($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
$this->_maxLifeTime = ini_get('session.gc_maxlifetime');
} public function open($path,$name)
{
return true;
} public function close()
{
return true;
} public function read($id)
{
$sql = 'SELECT * FROM session where PHPSESSID = ?';
$stmt = $this->_pdo->prepare($sql);
$stmt->execute(array($id)); if (!$result = $stmt->fetch(PDO::FETCH_ASSOC)) {
return null;
} elseif ($this->_ip != $result['client_ip']) {
return null;
} elseif ($result['update_time']+$this->_maxLifeTime < time()){
$this->destroy($id);
return null;
} else {
return $result['data'];
}
} public function write($id,$data)
{
$sql = 'SELECT * FROM session where PHPSESSID = ?';
$stmt = $this->_pdo->prepare($sql);
$stmt->execute(array($id)); if ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($result['data'] != $data) {
$sql = 'UPDATE session SET update_time =? , date = ? WHERE PHPSESSID = ?'; $stmt = $this->_pdo->prepare($sql);
$stmt->execute(array(time(), $data, $id));
}
} else {
if (!empty($data)) {
$sql = 'INSERT INTO session (PHPSESSID, update_time, client_ip, data) VALUES (?,?,?,?)';
$stmt = $this->_pdo->prepare($sql);
$stmt->execute(array($id, time(), $this->_ip, $data));
}
} return true;
} public function destroy($id)
{
$sql = 'DELETE FROM session WHERE PHPSESSID = ?';
$stmt = $this->_pdo->prepare($sql);
$stmt->execute(array($id)); return true;
} public function gc($maxLifeTime)
{
$sql = 'DELETE FROM session WHERE update_time < ?';
$stmt = $this->_pdo->prepare($sql);
$stmt->execute(array(time() - $maxLifeTime)); return true;
}
}