为什么要把session存入数据库?有什么用?
可以:统计在线人数,现实多站点session共享(通行证),控制同个账号登入人数等。
要实现session的入库,有关键的几个基本知识:
session.gc_divisor = 100 session.gc_probability = 1 。session.gc_probability 与 session.gc_divisor 合起来用来管理 gc(garbage collection 垃圾回收)进程启动的概率。( session.gc_probability/session.gc_divisor = 概率)
session.gc_maxlifetime = 1024 。session.gc_maxlifetime 指定过了多少秒之后数据就会被视为“垃圾”并被清除。
session.save_handler = files 。session.save_handler 定义了来存储和获取与会话关联的数据的处理器的名字。默认为 files。参见 session_set_save_handler()。
首先设计数据库表:
CREATE TABLE IF NOT EXISTS `session` (
`phpsession` char(32) COLLATE utf8_bin NOT NULL,
`uptime` int(10) unsigned NOT NULL,
`data` text COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`phpsession`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
可根据需求增加相应的字段。这里为演示方便,就设置基本的字段。
需要2个class, 一个是数据库的,一个是session的操作类
<?php
/**
* session入库操作类
* @author 删代码工程师 geek-cy.com
*/
include 'DbSession.php'; //引入session数据库操作类
class MySession extends DbSession{
private $dbc = null; //保存数据库资源句柄
private $lifetime = null; // session的生成时间
private $time = null; //当前时间
const uptime = 30; //更新session的时间
static $DEBUG = false; //是否开启错误提示
public function __construct( ){
$this->init();
$this->SessionSetSaveHandler();
}
/**
* 初始化session处理
* @throws Exception
*/
private function init(){
try{
//设置数据库链接资源句柄
$db = DbSession::InitDbSession(); //获取用于数据库操作的对象
if( !($db instanceof DbSession) ){
throw new Exception('需要MySession类的对象');
}else{
$this->dbc = $db;
}
//设置session有效时间
if( !$this->lifetime = ini_get('session.gc_maxlifetime') ){
throw new Exception('session.gc_maxlifetime获取失败');
}
}catch (Exception $e){
$this->ShowErrow( $e->getMessage() );
}
$this->time = time();
// ini_set('session.save_handler', user);
}
/**
* 设置自定义session的回调方法
*/
private function SessionSetSaveHandler(){
session_set_save_handler(
array($this, "open"),
array($this, "close"),
array($this, "read"),
array($this, "write"),
array($this, "destroy"),
array($this, "gc")
);
session_start();//开启session
}
/**
* 打开session
* @param string $savePath
* @param string $sessName
* @return boolean
*/
public function open($savePath, $sessName){
if(is_null( $this->dbc )){ //判断数据库连接是否正常
return false;
}else{
return true;
}
}
/**
* 关闭session
*/
public function close(){
$this->gc($this->lifetime); //触发垃圾回收机制
return $this->dbc->MysqlClose(); //关闭数据库连接
}
/**
* 读取session
* @param string $sessionid
* @return boolean|unknown
*/
public function read( $sessionid ){
$selectData = array(0=>$this->phpsession,1=>$this->uptime,2=>$this->data); // 需要读取的字段,数组形式
$sessionData = $this->dbc->ReadSession($sessionid, $selectData);
//是否返回有效值
if( $sessionData == false){
return false;
}
//是否过期判断
if( $sessionData[$this->uptime] + $this->lifetime < $this->time ){
$this->destroy( $sessionData[$this->phpsession] );
return false;
}
return $sessionData[$this->data];
}
/**
* 写入session
* @param string $sessionid
* @param string $data
* @return boolean
*/
public function write( $sessionid, $data ){
$selectData = array(0=>$this->phpsession,1=>$this->uptime,2=>$this->data);// 需要读取的字段,数组形式
$sessionData = $this->dbc->ReadSession($sessionid, $selectData);
if( $sessionData == false){ //没有session数据
if( !empty( $data ) ){ //判断是否用需要插入的session值
//数组形式组装要插入的字段和对应值
$insertData = array(
$this->phpsession => $sessionid,
$this->uptime => $this->time,
$this->data => $data
);
$this->dbc->InsertSession( $insertData );
}
}else{//已经有了session数据
//判断session数据是否有改变,或者需要更新有效时间。
if($sessionData[$this->data] != $data || $this->time > ($sessionData[$this->uptime]+self::uptime)){
//以数组形式组装要更新的数据
$updateData = array(
$this->uptime => $this->time,
$this->data => $data
);
$this->dbc->UpdateSession($sessionData[$this->phpsession], $updateData );
}
}
return true;
}
/**
* 销毁session
* @param string $sessionid
*/
public function destroy( $sessionid ){
return $this->dbc->DeleteSession( $sessionid );
}
/**
* session的回收机制
* @param string $lifetime
*/
public function gc( $lifetime ){
$this->dbc->GcSession( $lifetime );
}
}
?>
<?php
/**
* session入库的数据库操作类
* @author 删代码工程师 geek-cy.com
*
*/
class DbSession{
public static $db = null;
private $con = null; //保存数据库链接资源句柄
private $HOSTNAME = 'localhost';
private $DB = 'phptest';
private $USER = 'root';
private $PASSWORD = '';
const CHARSET = 'UTF8'; //编码设置
static $DEBUG = true; //是否开启错误提示
//session表与表字段
private $TableName = 'session';
protected $phpsession = 'phpsession';
protected $uptime = 'uptime';
protected $data = 'data';
private function __construct(){
$this->contect();
}
private function __clone(){
}
/**
* 初始化链接数据库
* @return Ambigous <NULL, string>
*/
public static function InitDbSession(){
if( is_null(self::$db) || !(self::$db instanceof self) ){
self::$db = new DbSession;
}
return self::$db; //返回类对象
}
/**
* 链接数据库
*
*/
private function contect(){
$this->con = mysql_connect($this->HOSTNAME, $this->USER, $this->PASSWORD); //保存数据库连接资源句柄
try{
if( is_null($this->con) ){
throw new Exception('链接数据库失败');
}
if(!mysql_select_db($this->DB, $this->con)){
throw new Exception('选择数据库失败');
}
mysql_query("SET NAMES self::CHARSET");
}catch (Exception $e){
$this->ShowErrow( $e->getMessage() );
}
}
/**
* 输出错误
* @param string $msg
*/
protected function ShowErrow( $msg ){
if(static::$DEBUG){ //判断是否打印错误
echo $msg;
}
}
/**
* 读取数据库中保存的session
* @param string $sessionid
* @param array $selectData
* @return boolean|Ambigous <boolean, multitype:>
*/
public function ReadSession( $sessionid, array $selectData ){
$selectData = $this->doSelectData($selectData);
if(!$selectData){
return false;
}
if( $this->CheckSessionId($sessionid) ){
$sql = 'SELECT '.$selectData.' FROM `'.$this->TableName.'` WHERE '.$this->phpsession.' = \''.$sessionid.'\' LIMIT 1';
$result = mysql_query($sql, $this->con);
return $this->fetch($result);
}
}
/**
* 写入新session到数据库中
* @param array $insertData
* @return boolean
*/
public function InsertSession( array $insertData ){
if( $insertData = $this->doInsertData($insertData) ){
$sql = 'INSERT INTO '.$this->TableName.'('.$insertData[0].') VALUES('.$insertData[1].')';
mysql_query($sql, $this->con);
return true;
}else{
return false;
}
}
/**
* 更新数据库中保存的session
* @param string $sessionid
* @param array $updateData
* @return boolean
*/
public function UpdateSession( $sessionid, array $updateData){
if( !$this->CheckSessionId($sessionid) ){
return false;
}
if( $updateData = $this->doUpadateData($updateData) ){
$sql = 'UPDATE '.$this->TableName.' SET '.$updateData.' WHERE '.$this->phpsession.' = \''.$sessionid.'\'';
mysql_query($sql, $this->con);
return true;
}else{
return false;
}
}
/**
* 删除数据库中的session
* @param string $sessionid
* @return boolean
*/
public function DeleteSession( $sessionid ){
if( !$this->CheckSessionId($sessionid) ){
return false;
}
$sql = 'DELETE FROM '.$this->TableName.' WHERE \''.$sessionid.'\' = '.$this->phpsession;
mysql_query($sql,$this->con);
return true;
}
/**
* 回收清除数据库中已经获取无用的session
* @param string $lifetime
* @return boolean
*/
public function GcSession( $lifetime ){
if( !ctype_digit($lifetime )){
return false;
}
$checktime = time()-$lifetime;
$sql = 'DELETE FROM '.$this->TableName.' WHERE '.$this->uptime.' < '.$checktime ;
mysql_query($sql,$this->con);
return true;
}
/**
* 关闭数据库连接
*/
public function MysqlClose(){
mysql_close( $this->con );
}
public function __destruct(){
self::$db = null;
if($this->con instanceof self){
mysql_close( $this->con );
}
}
/**
* 对session id 做合法性检查
* @param string $sessionid
* @return boolean
*/
private function CheckSessionId( $sessionid ){
return ctype_alnum($sessionid);
}
/**
* 返回select取得的结果集
* @param $result
* @return boolean|multitype:
*/
private function fetch( $result ){
if( $result && mysql_num_rows($result) == 1){
$resultArray = array();
$resultArray = mysql_fetch_array($result, MYSQL_ASSOC);
if( !$resultArray || count($resultArray)== 0 ){
return false;
}else{
return $resultArray;
}
}else{
return false;
}
}
/**
* 处理select要查询的字段
* @param array $data
* @return boolean|string
*/
private function doSelectData( array $data ){
$keyString = '';
foreach ($data as $value){
$keyString .= '`'.$value.'`,';
}
$keyString = substr($keyString,0,-1);
if($keyString == ''){
return false;
}
return $keyString;
}
/**
* 处理要insert进数据库的字段和对应的值
* @param array $data
* @return boolean|string
*/
private function doInsertData( array $data ){
$keyString = '';
$valueString = '';
if(array_key_exists($this->phpsession, $data)){
if( !$this->CheckSessionId($data[$this->phpsession]) ){
return false;
}
}
foreach ($data as $key => $value){
$keyString .= '`'.$key.'`,';
if(ctype_digit($value)){
$valueString .= ''.$value.',';
}else{
$valueString .= '\''.$value.'\',';
}
}
if( $keyString != '' && $valueString != ''){
$keyString = substr($keyString,0,-1);
$valueString = substr($valueString,0,-1);
$dataArray[0] = $keyString; //字段
$dataArray[1] = $valueString;//值
return $dataArray;
}else{
return false;
}
}
/**
* 处理update的字段和对应的值
* @param array $data
* @return boolean|string
*/
private function doUpadateData( array $data ){
$upDataString = '';
foreach($data as $key => $value){
if(ctype_digit($value)){
$value = ''.$value.'';
}else{
$value = '\''.$value.'\'';
}
$upDataString .= '`'.$key.'` = '.$value.',';
}
$upDataString = substr($upDataString,0,-1);
if( $upDataString == ''){
return false;
}
return $upDataString;
}
}
下面是使用方法:
<?php
include 'MySession.php';
$session = new MySession( );
$_SESSION['test1'] = 'test1';
$_SESSION['test2'] = 2;
$_SESSION['test3'] = array(1,2,3,4);
// session_destroy();
?>
更多: geek-cy