session相關儲存擴充
作者 三石 sanshi0815
mail sanshi0815@tom.com
對於session的儲存,現在解決方案很多,利用最近的時間,完善了,一下。並使用程式實現。
現在使用了一個session的工程類,來控制session的調用跟使用。當前實現的是mysql,
跟memcached的2中儲存方式,並解決了memcache擴充沒有安裝使用php程式調用的可能性。
所以我們先說下memcache的安裝問題。
首先下載 memcached 網站是 www.danga.com
解壓,然後安裝,如果提示缺少libevent 就到他提示的網站去下載安裝。
安裝完,在回頭安裝memcached,這個時候,如果安裝libevent的時候,指定了,安裝目錄,那麼這個時候會提示一個
so檔案找不到,但是去libevent 安裝目錄下,lib下面是有這個檔案的,這個時候,需要做個串連把這個缺少的檔案
串連到/usr/lib下也就是說,在系統的預設的載入庫中做個串連,讓memcache能夠找的到。
編譯完成,memcached也就安裝完成了,然後啟動memcached ,去memcached的bin目錄下執行,./memcache -h這個命令
如果正式運行就算是啟動完畢了,然後根據提示啟動memcached的服務
命令如下,請根據自己的實際情況修改 /usr/local/memcache/memcached -d -u root -m 64 -l 192.168.241.195 -p 11211
這個時候,memcached的伺服器就算安裝完成了
現在我們安裝php的擴充
網上有現成的,但是我安裝的是時候發現了一些問題。
使用phpize運行下
然後開始編譯php的載入模組
運行
解壓,進入運行
./configure --enable-memcache --with-php-config=/usr/local/bin/php-config --with-zlib-dir
這個時候提示php-config 找不到
大家要注意了 --with-php-config 這個參數,是要我們告訴他再剛開始編譯php的時候,把php放在了那個目錄下面
如果我們編譯php的時候指定了,就換成那個目錄,然後加上php-config 就行了,如果我們編譯php的時候,沒有指定的話,
那麼我們會麻煩些,我們不知道我們的php放在那個目錄下面了,那麼我們就去php源碼下,運行./configure -h這個命令,
看看php預設安裝在那裡了。
然後繼續運行 ./configure --enable-memcache --with-php-config=/usr/local/bin/php-config --with-zlib-dir 這個時候,
如果我們在編譯php目錄的話,還會提示一個錯誤,說php-session.h這個檔案找不到。這個地方,可就麻煩了,我看了下configure
這個指令碼,他裡面session_inc_path 這樣的一個變數,因為我們編譯php的時候沒有指定php的存放目錄,所以這個.h的檔案,不在
這個指令碼裡嘗試判斷的檔案中,所以我們要手動修改這個指令碼,在if完成後,加上一句
session_inc_path="/usr/local/include/php/ext/php_session.h"
當然,是你這個.h檔案一定存在的情況下。編譯完成,記住最後給你那個目錄,然後修改php.ini檔案,
修改so檔案的載入目錄,然後載入so模組,最後重新啟動你的apache,然後跑個測試程式如果成功,那麼恭喜你,你順利完成了,
memcache的全部安裝。
關於適用範圍,我們不多說了,因為現在我們做的這三種儲存,一個是檔案,一個資料庫,一個是memcache,
有著不同的使用範圍,這個需要個人去體會了。
現在開始說下程式,為了更加方便的使用這個session的不同的儲存機制,我做了一個session的工廠類,來降低耦合性,這樣對我們以後的擴充
會有很大的好處。
sessionFartory.class.php
[code]
<?php
/**
* base class
* @version 1.0.0
* @author sanshi0815
* @mail sanshi0815@tom.com
*/
class sessionFartory
{
function __construct($module_name="")
{
$this->sessionFartory($module_name);
}
function sessionFartory($module_name="")
{
//設定session的有效時間
//$maxLife = get_cfg_var('session.gc_maxlifetime') ? get_cfg_var('session.gc_maxlifetime') : 1440;
if($module_name=="mysql")
{
$this->setSessionObject($module_name);
}else if($module_name=="memcache"){
$this->setSessionObject($module_name);
}else{
}
session_start();
}
function setSessionObject($module_name)
{
//設定sesion模組的名字
//session_module_name(__CLASS__);
$objectName = "{$module_name}Session";
//通過工廠類取得
include_once(dirname(__FILE__)."/factryObject.class.php");
$sesionObject = factryObject::getClass($objectName);
//設定執行的方法
session_set_save_handler
(
array (& $sesionObject, "__open"),
array (& $sesionObject, "__close"),
array (& $sesionObject, "__read"),
array (& $sesionObject, "__write"),
array (& $sesionObject, "__destroy"),
array (& $sesionObject, "__gc")
);
}
}
?>
[/code]
這段代碼並不麻煩,但是有一些潛在的規範
關於/**
* 銷毀到期session
*/
function __gc($maxlifetime)
這個方法,我在實際測試的過程中,沒有發現這個方法在什麼時候調用,如果有知道的請告訴我下
我們現在看看,mysql資料庫的儲存
mysqlSession.class.php
[code]
<?php
/**
* base class
* @version 1.0.0
* @author sanshi0815
* @mail sanshi0815@tom.com
*/
include_once(dirname(__FILE__)."/adodbObject.class.php");
class mysqlSession extends adodbObject
{
var $tableName = "session";
var $sessionID = "session_id";
var $tableF = array("session_data","expiry","last_time");
var $dbConfigType = "";
function mysqlSession()
{
//設定session的有效時間
$this->maxLife = get_cfg_var('session.gc_maxlifetime') ? get_cfg_var('session.gc_maxlifetime') : 1440;
}
/**
* 開啟session
*/
function __open($save_path, $session_name)
{
$this->adodbObject($this->dbConfigType);
return true;
}
/**
* 關閉session
*/
function __close()
{
return true;
}
/**
* 讀取session
*/
function __read($sessionID)
{
//$this->__gc($this->maxLife);
//設定where條件
$where = "{$this->tableF[1]} > '".time()."' AND {$this->sessionID}='{$sessionID}'";
//取得資料
$sql="SELECT * FROM {$this->tableName} WHERE ".$where;
$sessionData = $this->select($sql);
$sessionData = isset($sessionData[0])?$sessionData[0]:"";
$curTime = time();
$expiry = $curTime+$this->maxLife;
//更新session操作時間
$this->update(
$this->tableName,
array(
$this->tableF[0]=>isset($sessionData[$this->tableF[0]])?$sessionData[$this->tableF[0]]:'',
$this->tableF[1]=>$expiry,
$this->tableF[2]=>$curTime
),
$where);
return isset($sessionData[$this->tableF[0]]) ? unserialize($sessionData[$this->tableF[0]]) : false;
}
/**
* 寫入session
*/
function __write($sessionID, $sessionData)
{
//設定where條件
$where = "{$this->sessionID}='{$sessionID}'";
//取得資料
$sql="SELECT * FROM {$this->tableName} WHERE ".$where;
$data = $this->select($sql);
$curTime = time();
$expiry = $curTime+$this->maxLife;
if(empty($data))
{
//插入資料
$this->insert(
$this->tableName,
array($this->sessionID=>$sessionID,$this->tableF[0]=>serialize($sessionData),$this->tableF[1]=>$expiry,$this->tableF[2]=>$curTime)
);
}else{
//更新資料
$this->update(
$this->tableName,
array($this->tableF[0]=>serialize($sessionData),$this->tableF[1]=>$expiry,$this->tableF[2]=>$curTime),
$where);
}
}
/**
* 登出session
*/
function __destroy($sessionID)
{
$where = "{$this->sessionID}='{$sessionID}'";
$del = $this->delete($this->tableName,$where);
return $del==1 ? true : false;
}
/**
* 銷毀到期session
*/
function __gc($maxlifetime)
{
$where = "{$this->tableF[1]} <= '".time()."'";
return $this->delete($this->tableName,$where);
}
}
?>
[/code]
下面是對應的sql語句
[code]
CREATE TABLE `session` (
`session_id` varchar(32) NOT NULL,
`session_data` mediumtext NOT NULL,
`expiry` varchar(100) NOT NULL,
`last_time` varchar(100) NOT NULL,
KEY `session_id` (`session_id`),
KEY `expiry` (`expiry`),
KEY `last_time` (`last_time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
[/code]
這裡是可以擴充的,要去修改對應的方法裡的設定。
這個也是靈活性,最強的,比如再線統計等等,都能實現
下面是memcache的這個跟php本身的那個檔案儲存體差不多,不可排序,等等,功能都不能實現
memcacheSession.class.php
[code]
<?php
/**
* base class
* @version 1.0.0
* @author sanshi0815
* @mail sanshi0815@tom.com
*/
include_once(dirname(__FILE__)."/memcacheObject.class.php");
class memcacheSession extends memcacheObject
{
function memcacheSession()
{
//設定session的有效時間
$this->maxLife = get_cfg_var('session.gc_maxlifetime') ? get_cfg_var('session.gc_maxlifetime') : 1440;
}
function __open($save_path, $session_name)
{
$this->memcacheObject();
return true;
}
function __close()
{
$this->close();
return true;
}
/**
* 讀取session
*/
function __read($sessionID)
{
$data = $this->get($sessionID);
if(is_array($data))
$this->update($sessionID,$data,$this->maxLife);
return $data;
}
/**
* 寫入session
*/
function __write($sessionID, $sessionData)
{
return $this->set($sessionID,$sessionData,$this->maxLife);
}
/**
* 登出session
*/
function __destroy($sessionID)
{
return $this->delete($sessionID);
}
/**
* 銷毀到期session
*/
function __gc($sessionID)
{
return true;
}
}
?>
[/code]
關於memcache的非擴充也擴充的相容性是在 memcacheObject 裡做的
現在我們看下
memcacheObject.class.php
[code]
<?php
/**
* base class
* @version 1.0.0
* @author sanshi0815
* @mail sanshi0815@tom.com
*/
class memcacheObject
{
var $flag=0;
var $mObject="";
var $isPhp;
function memcacheObject()
{
$this->isPhp = class_exists("Memcache");
if(!$this->isPhp)
{
include_once("MemCachedClient.class.php");
}
return $this->connect();
}
function connect()
{
global $memcacheConfig;
if($this->isPhp)
{
$this->mObject = new Memcache();
$this->mObject->addServer($memcacheConfig['server'],$memcacheConfig['port']);
//$this->mObject->connect($memcacheConfig['server'],$memcacheConfig['port']) or die("Could not connect memcache server!");
}else{
$options["servers"]=array("{$memcacheConfig['server']}:{$memcacheConfig['port']}");
$options["debug"]=false;
$this->mObject = new MemCachedClient($options);
}
}
function set($key,$value,$maxLeft=0)
{
is_object($this->mObject) or $this->connect();
return $this->mObject->set($key,$value,$this->flag,$maxLeft) ? true : false;//die("memcache set valuse is failed");
}
function get($key)
{
is_object($this->mObject) or $this->connect();
return $this->mObject->get($key);
}
function update($key,$value,$maxLeft=0)
{
is_object($this->mObject) or $this->connect();
return $this->mObject->replace($key,$value,$this->flag,$maxLeft) ? true : false;//die("memcache update valuse is failed");
}
function delete($key)
{
is_object($this->mObject) or $this->connect();
return $this->mObject->delete($key,10) ? true : false;//die("memcache delete valuse is failed");
}
function close()
{
is_object($this->mObject) or $this->connect();
$this->mObject->close();
}
}
?>
[/code]
現在我們看下測試程式
現在看一個發送session的
[code]
<?php
/**
* base class
* @version 1.0.0
* @author sanshi0815
* @mail sanshi0815@tom.com
*/
include_once("config/config.inc.php");
include_once("classes/sessionFartory.class.php");
new sessionFartory('memcache');
//new sessionFartory('mysql');
echo $_SESSION['time'] = array("a",'b');
?>
[/code]
這是一個接受並登出的測試
[code]
<?php
/**
* base class
* @version 1.0.0
* @author sanshi0815
* @mail sanshi0815@tom.com
*/
include_once("config/config.inc.php");
include_once("classes/sessionFartory.class.php");
new sessionFartory('memcache');
//new sessionFartory('mysql');
print_r($_SESSION);
session_destroy();
print_r($_SESSION);
?>
[/code]
作者 三石 sanshi0815
mail sanshi0815@tom.com
轉載請著名作者!並說明出處