数据库保存session

一般情况下,php.ini里的session.save_handler默认是file,也就是用文件来保存session,这种方式有几个缺点:
1、如果单靠session自己的垃圾回收机制,时间久了,保存session的文件会越来越多,影响查找效率;
2、对于需要统计同时在线用户的系统,实现起来很不方便;
3、分布式系统难以共享session。

如果将session.save_handler设置为user,php可以通过session_set_save_handler函数来重载session的几个底层会话处理方法,以达到使用数据库来保存session的目的,下面以mysql数据库为例,数据库连接方式采用PDO。

session.sql

CREATE TABLE `session` (  
  `session_id` varchar(32) NOT NULL default '',  
  `session_content` text NOT NULL,  
  `last_visit` int(11) NOT NULL,  
  PRIMARY KEY (`session_id`)  
) ENGINE=MyISAM; 
此处建议使用ENGINE=MEMORY,MEMORY引擎采用内存表,所有数据存储在内存,操作速度快,对于session这种形式的数据正好适用。

session.php

<?PHP   
// --------------------------------------------------------------------------  
// File name   : session.php  
// Description : 数据库存放session  
// Copyright(C), MagicLab.cn, 2008, All Rights Reserved.  
// Author: xinglu   QQ:330708730   MSN:xinglu_1983@hotmail.com  
// --------------------------------------------------------------------------  
class Session {  
	var $lifeTime;  
	var $domain;  
	var $dbh;  
	function __construct()  
	{  
		//定义生存期  
		$this->lifeTime = 3600;  
		//定义域  
		$this->domain = $_SERVER['SERVER_NAME'];  
		try   
		{  
			$this->dbh = new PDO('mysql:host=localhost;dbname=session', 'root', '');  
			$this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);  
			//PDO出错方式 跑出异常  
			$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  
		}  
		catch (PDOException $e)  
		{  
			throw $e;  
		}  
  
		//设置session生存期  
		ini_set('session.gc_maxlifetime',  $this->lifeTime);  
  
		//设置客户端使用COOKIE保存SESSIONID  
		ini_set('session.use_cookies', 1);  
		ini_set('session.cookie_path', '/');  
  
		//多主机共享保存SESSIONID的COOKIE(使二级域名可以共享session)
		ini_set('session.cookie_domain', $this->domain);  
  
		//设置客户端保存 SESSIONID 的cookie的生存期  
		ini_set('session.cookie_lifetime', $this->lifeTime);  
  
		//为保持客户端cookie生命期与服务端session生命期相同,进行写cookie操作  
		$sessionid = session_id();  
		$sessionname = session_name();  
		setcookie($sessionname, $sessionid, $this->lifeTime, '/', $this->domain);  
  
		//将session.save_handler设置为user,而不是默认的 files  
		session_module_name('user');  
		  
		//重载session函数  
		session_set_save_handler(array(&$this,"open"),  
					array(&$this,"close"),  
					array(&$this,"read"),  
					array(&$this,"write"),  
					array(&$this,"destroy"),  
					array(&$this,"gc")  
					);  
  
	}  
  
	function open($savePath, $sessName)   
	{  
		$this->gc();  
		return true;  
	}  
  
	function close()   
	{  
		$this->gc();  
		unset($this->dbh);  
		return true;  
	}  
  
	function read($session_id)   
	{  
		if (!isset($session_id))   
			return "";  
  
		$last = time() - $this->lifeTime;  
  
		$sql = sprintf("SELECT session_content  
						FROM session 
						WHERE session_id = '%s'  
							AND last_visit > ".$last  
						,$session_id);  
		try  
		{  
			$query = $this->dbh->query($sql);  
			if($row = $query->fetch(PDO::FETCH_ASSOC))  
			return $row['session_content'];  
		}  
		catch(PDOException $e)  
		{  
			echo $e->getMessage();  
			die();  
		}  
		return "";  
	}  
  
	function write($session_id, $session_content)   
	{  
		if (!isset($session_id))   
			return "";  
  
		$sql = sprintf("SELECT * FROM session WHERE session_id='%s'", $session_id);  
		  
		try  
		{  
			$sth = $this->dbh->query($sql);  
			$rs = $sth->fetchAll(PDO::FETCH_ASSOC);  
			if (is_array($rs) && !empty($rs))  
			{  
				$sql = sprintf("UPDATE session  
								SET session_content='%s',last_visit=%d  
								WHERE session_id='%s';"  
								,$session_content  
								,time()  
								,$session_id  
								);  
			}  
			else  
			{  
				$sql = sprintf("INSERT INTO session  
								SET session_id='%s',session_content='%s',last_visit=%d;"  
								,$session_id  
								,$session_content  
								,time()  
								);  
			}  
  
			$rs = $this->dbh->exec($sql);  
			if($rs)  
				return true;  
		}  
		catch(PDOException $e)  
		{  
			echo $e->getMessage();  
			die();  
		}  
		return false;  
	}  
  
	function destroy($session_id)   
	{  
		if (!isset($session_id))   
			return true;  
  
		$sql = sprintf("DELETE FROM session WHERE session_id = '%s'", $session_id);  
		try  
		{  
			$rs = $this->dbh->exec($sql);  
			if($rs)  
			return true;  
		}  
		catch(PDOException $e)  
		{  
			echo $e->getMessage();  
			die();  
		}  
		return false;  
	}  
  
	function gc()   
	{  
		$last = time() - $this->lifeTime;  
		$sql = sprintf("DELETE FROM session WHERE last_visit < ".$last);  
		$sth = $this->dbh->exec($sql);  
		return $sth;  
	}  
}  
  
?>  
使用方法:
test.php

<?php  
require_once('session.php');  
$session = new Session;  
session_start();  
?>
类文件里有一个有些特别的地方:

//为保持客户端cookie生命期与服务端session生命期相同,进行写cookie操作  
$sessionid = session_id();  
$sessionname = session_name();  
setcookie($sessionname, $sessionid, $this->lifeTime, '/', $this->domain); 


如果只是单单将session.gc_maxlifetime和session.cookie_lifetime的设置成相同的时间,那么以后在每次session_start()的时候,服务端session的生存期都会自动得到延长,但是保存sessionid的cookie却没有。当然,也可以直接将session.cookie_lifetime设置成一个非常大的数,只是这样显得比较霸道。

posted @ 2014-10-02 11:26  moqiang02  阅读(153)  评论(0编辑  收藏  举报