php实现session入库

为什么要把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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值