session默认是以文件形式存储的,当网站的访问量很大的情况下,因为文件的IO性能问题,会让服务器的开销巨大,比较典型做法是把session存入数据库或内存,本文是以数据库为例。
主要有两个步骤:
1. 自定义实现session的操作方法,比如读、写、删除、垃圾回收…
2. 告诉系统的session机制调用自定义的方法去处理session.
数据库创建语句:
CREATE TABLE `t_session` (
`sess_id` varchar(50) NOT NULL COMMENT 'session id',
`sess_content` text NOT NULL COMMENT 'session内容',
`last_write` int(10) unsigned NOT NULL COMMENT '最后写入时间',
PRIMARY KEY (`sess_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
代码如下:
session_db.php
<?php
require_once 'MyPdo.class.php';
require_once 'ModelFactory.class.php';
require_once 'SessionModel.class.php';
// function __autoload($class){
// $filename = $class.".class.php";
// if(file_exists($filename)){
// require_once $filename;
// }
// }
//让系统的session机制调用自定义的方法去处理session.
session_set_save_handler('sessionOpen', 'sessionClose', 'sessionRead', 'sessionWrite', 'sessionDestroy', 'sessionGc');
//打开session
function sessionOpen(){
echo "<br>sessionOpen";
}
//关闭session
function sessionClose(){
echo "<br>sessionClose";
return true;
}
//session根据id读取数据
function sessionRead($sess_id){
echo "<br>sessionRead";
$model = ModelFactory::M("SessionModel");
return $model->read($sess_id);
}
//session根据id写入数据
function sessionWrite($sess_id,$content){
echo "<br>sessionWrite";
$model = ModelFactory::M("SessionModel");
$model->write($sess_id,$content);
}
/**
* 销毁session,调用session_destroy()触发
* @param string $sess_id
*/
function sessionDestroy($sess_id){
echo "<br>sessionDestroy";
$model = ModelFactory::M("SessionModel");
$model->destroy($sess_id);
}
//垃圾session数据回收
function sessionGc($lifetime){
echo "<br>sessionGc";
$model = ModelFactory::M("SessionModel");
$model->gc($lifetime);
}
?>
MyPdo.class.php
<?php
class MyPdo
{
private static $_instance = null;
private $dbh;
private function __construct($config)
{
$dsn = "mysql:host={$config['host']}; port={$config['port']}; dbname={$config['dbname']}";
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => "set names {$config['charset']}"
);
try {
$this->dbh = new PDO($dsn, $config['username'], $config['passwd'], $options);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
$this->dbh -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );
}
private function __clone()
{}
public static function getInstance($config = array('host'=>'localhost','port'=>'3306','dbname'=>'db7','charset'=>'utf8','username'=>'root',"passwd"=>'root'))
{
return isset(self::$_instance) ? self::$_instance : (self::$_instance = new self($config));
}
public function getPdo(){
return $this->dbh;
}
public function close() {
$this->dbh = null;
self::$_instance = null;
}
public function query($sql) {
try {
$stmt = $this->dbh->query($sql);
return $stmt;
} catch (PDOException $e) {
echo "<p>sql语句执行失败,请参考如下信息:</p>";
echo "<br>错误文件:" .$e->getFile();
echo "<br>错误行号:" .$e->getLine();
echo "<br>错误代号:" .$e->getCode();
echo "<br>错误信息:" .$e->getMessage();
echo "<br>错误语句:" .$sql;
}
}
public function exec($sql) {
try {
$num = $this->dbh->exec($sql);//失败返回false,成功返回受影响的行数,也可能是0
if($num >= 0){
return true;
}
return $num;
} catch (PDOException $e) {
echo "<p>sql语句执行失败,请参考如下信息:</p>";
echo "<br>错误文件:" .$e->getFile();
echo "<br>错误行号:" .$e->getLine();
echo "<br>错误代号:" .$e->getCode();
echo "<br>错误信息:" .$e->getMessage();
echo "<br>错误语句:" .$sql;
}
}
/**
* 获取一行的结果
* @param string $sql
* @return array 数组
*/
public function fetchRow($sql){
$stmt = $this->query($sql);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
/**
* 获取多行结果
* @param unknown $sql
* @return array 二维数组
*/
public function fetchAll($sql) {
$stmt = $this->query($sql);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* 获取一个数据
* @param string $sql
* @return string
*/
public function fetchData($sql) {
$stmt = $this->query($sql);
$result = $stmt->fetch(PDO::FETCH_NUM);
if($result){
return $result[0];
}
return '';
}
}
?>
ModelFactory.class.php
<?php
class ModelFactory
{
private static $arr = array();
static function M($class) {
if(!array_key_exists($class, static::$arr)){
static::$arr[$class] = new $class();
}
return static::$arr[$class];
}
}
?>
SessionModel.class.php
<?php
class SessionModel
{
/**
* 写入session_id的内容
* @param string $sess_id
* @param string $content
*/
public function write($sess_id,$content) {
$sql = "replace into t_session (sess_id, sess_content, last_write) values ('$sess_id', '$content', UNIX_TIMESTAMP());";
return MyPdo::getInstance()->exec($sql);
}
/**
* 根据session_id读取内容
* @param string $sess_id
* @return string
*/
public function read($sess_id) {
$sql = "select sess_content from t_session where sess_id = '$sess_id'";
return MyPdo::getInstance()->fetchData($sql);
}
/**
* 销毁session_id数据
* @param string $sess_id
*/
public function destroy($sess_id) {
$sql = "delete from t_session where sess_id = '$sess_id'";
return MyPdo::getInstance()->exec($sql);
}
/***
* gc垃圾回收删除超过有效期的session数据
* @param int $lifetime
* @return Ambigous <boolean, int>
*/
public function gc($lifetime){
$sql = "delete from t_session where last_write < (UNIX_TIMESTAMP()- $lifetime)";
return MyPdo::getInstance()->exec($sql);
}
}
?>
use_session_db.php
<?php
require 'session_db.php';
//每2次访问服务器,可能进行1次垃圾扫描回收
ini_set('session.gc_probability', '1');
ini_set('session.gc_divisor', '2');
//设置session的有效期10秒
ini_set('session.gc_maxlifetime', '10');
@session_start();
echo '<br>current session id= '.session_id();
echo '<br>';
print_r($_SESSION);
$_SESSION['name'] = 'jack';
$_SESSION['age'] = 60;
$_SESSION['city'] = 'guangzhou';
$_SESSION['age'] = 88;
// session_destroy();
echo "<br>I am the last code!!";
session_destroy() 会触发sessionDestroy(),并且马上关闭session