PHP中多服務器共享SESSION的方法

   在PHP中SESSION默認是用文件來進行保存的,如session.save_path=/tmp,則是將session數據保存在/tmp目錄下,如果併發用戶量很大,在這個目錄下就會存在大量類似sess_xxxxxx的session文件,導致性能下降,不少朋友可能都沒有注意到php.ini裏面Session設置部分中有這樣一項:

   ; session.save_path = "N; MODE; /path"

  這項設置提供給我們可以給session存放目錄進行多級散列,其中“N”表示要設置的目錄級數,“MODE”表示目錄的權限屬性,默認爲600,在WINDOWS上基本是不用設置的,*NIX上也可以不用設置,後面的“/path”表示session文件存放的根目錄路徑,比如我們設置爲下面的格式

session.save_path = "2; d:/php5/tmp"
  上面的設置表示我們把d:/php5/tmp目錄作爲php的session文件存放根目錄,在該目錄下進行兩級目錄散列,每一級目錄分別是0-9和a-z共36個字母數字爲目錄名,這樣存放session的目錄可以達到36*36個,相信作爲單臺服務器來說,這是完全夠用了,如果說您的系統架構設計爲多臺服務器共享session數據,可以把目錄級增加到3級或者更多。
  需要注意的是,php自己並不會自動創建子目錄,需要您自己動手去創建,網上找到這樣的自動創建目錄的代碼,大家可以做個參考。下面的代碼自動創建3級子目錄,可以自己動手根據需要進行修改。

<?php
set_time_limit(0);
$string = '0123456789abcdefghijklmnopqrstuvwxyz';
$length = strlen($string);
function makeDir($param)
{
if(!file_exists($param)) {
makeDir(dirname($param));
mkdir($param);
}
}
for($i = 0; $i < $length; $i++) {
for($j = 0; $j < $length; $j++) {
for($k = 0; $k < $length; $k++) {
makeDir($string[$i].'/'.$string[$j].'/'.$string[$k]);
}
}
}
?>

多服務器共享session的方法:

1.通過NFS文件共享的方式,多臺WEB服務器共享保存session文件的磁盤

2.保存在數據庫中,這種方式的擴展性很強,可以隨意增加WEB而不受影響

3.可以將session數據保存在memcached中,memcached是基於內存存儲數據的,性能很高,用戶併發量很大的時候尤其合適,參考PHP實現多服務器session共享之memcache共享

4.文件方式保存session時,可以採用php的擴展eaccelerator來存儲sesion,參考

eaccelerator 應用之“使用共享內存存儲Session”

首先創建表,用來保存session數據

CREATE TABLE `sessions` (                            
            `sessionid` varchar(32) NOT NULL default '',       
            `data` mediumtext NOT NULL,                        
            `lastvisit` int(10) unsigned NOT NULL default '0', 
            PRIMARY KEY  (`sessionid`)                         
          ) ENGINE=MyISAM DEFAULT CHARSET=gbk

主要的代碼如下:

session_mysql.class.php

<?php
class session
{
 var $lifetime = 1800;
    var $op = '';

    function __construct($op = '')
    {
        $this -> op = $op;
     session_set_save_handler(array(&$this,'open'), array(&$this,'close'), array(&$this,'read'), array(&$this,'write'), array(&$this,'destroy'), array(&$this,'gc'));
        $this->debug('session_id:' . $_COOKIE[session_name()]);
        //確保讀寫session時session id保存在同一個域下,否則有可能會每次重新生成一個session id
        ini_set('session.cookie_domain', '.chf.com');
  session_start();
    }

    function debug($str) {
        //echo $str . "<br />\n";
        $file = dirname(__FILE__) . '/session.log';
        $content = date("Y-m-d H:i:s") . ' operate:' . $this -> op . ' ' . $str . "\n";
        $fp = @fopen($file, "ab");
        if (!$fp) die("Open file $file failed!");
        @fwrite($fp, $content);
        if ($fp) @fclose($fp);
    }

    function session()
    {
  $this->__construct();
    }

    /**
     * 這個函數被session處理程序調用來作初始化工作。
   * @param string $save_path 參數$sess_path對應php.ini文件中的session.save_path選項
     * @param string $session_name 參數$session_name對應php.ini中的session.name 選項。
     */
    function open($save_path, $session_name)
 {
        $this->debug('opening...');
  global $db;
     $this->lifetime = 20; //session超時時間
     $this->time = time();
  $this->sess = &$db;
        $this->pre = '';
  return true;
    }

    /*
    sess_close();
  這個函數在頁面結束執行並且session處理程序需要關閉時被調用
    */
    function close()
 {
        $this->debug('closing...');
  $this->gc($this->lifetime);
        return $this->sess->close();
    }

    //根據session id取出指定的session數據是否爲空,然後判斷用戶登錄與否或操作是否超時
    /*
    這個函數在session處理程序讀取指定session鍵值($key)時,檢索並返回標識爲$key的session數據.(注意:序列化是將變量或對象在程序結束或需要時保存在文件中,在下次程序運行或需要時再調入內存的技術,有別於只保存數據的方法。)

    例如讀session數據時會調用此函數
    $name = $_SESSION['name'];
    echo "name:$name<br />";

    要測試,給session賦值時也調用此函數
    $_SESSION['name'] = 'caihf';

    @param string $id session id通常通過cookie來保存用戶的session id,如650fcm4p8aodn1cfrusc5ehql0
    */
    function read($id)
 {
        $this->debug('reading...');
        $sql = "SELECT data FROM `{$this->pre}sessions` WHERE sessionid='$id'";
  $r = $this->sess->get_one($sql);
        $this->debug("sql:$sql");
  return $r ? $r['data'] : '';
    }

    /*
    這個函數據在session處理程序需要將數據保存時調用,這種情況經常在程序結束時發生。它負責將數據保存在下次能用sess_read($key)函數檢索的地方。
    例如給session賦值時($_SESSION['name'] = 'caihf';)會調用此函數
    @param string $id session id通常通過cookie來保存用戶的session id,如650fcm4p8aodn1cfrusc5ehql0
    @param string $sess_data sessoin數據,一般是自動序列化以後保存在數據庫中的,如name|s:5:\"caihf\";
    */
    function write($id, $sess_data)
 {
        $this->debug('writing...');
        $sql = "REPLACE INTO `{$this->pre}sessions` (sessionid, data, lastvisit) VALUES('$id', '".addslashes($sess_data)."', '".time()."')";
        $this->sess->query($sql);
        $this->debug("sql:$sql");
  return true;
    }

    /*
    這個函數在需要消毀session時。它負責刪除session並且清除環境。
    @param string $id session id通常通過cookie來保存用戶的session id,如650fcm4p8aodn1cfrusc5ehql0
    */
    function destroy($id)
 {
        $this->debug('destroying...');
        $sql = "DELETE FROM `{$this->pre}sessions` WHERE sessionid='$id'";
  $this->sess->query($sql);
        $this->debug("sql:$sql");
  return true;
    }

    //刪除超時的session數據
    /*
    這個函數負責清理碎片。在這種情況下,它負責刪除過時的session數據。session處理程序會偶爾調用它們。
    */
    function gc($maxlifetime)
 {
        $this->debug("gcing...\n");
  $expiretime = $this->time-$maxlifetime;
        $sql = "DELETE FROM `{$this->pre}sessions` WHERE lastvisit<$expiretime";
  $this->sess->query($sql);
        $this->debug("sql:$sql");
  return true;
    }
}

/*
給session賦值時的log,如$_SESSION['name'] = 'caihf';
2008-09-17 03:35:35 operate:write session_id:650fcm4p8aodn1cfrusc5ehql0
2008-09-17 03:35:35 operate:write opening...
2008-09-17 03:35:35 operate:write reading...
2008-09-17 03:35:35 operate:write sql:SELECT data FROM `sessions` WHERE sessionid='650fcm4p8aodn1cfrusc5ehql0'
2008-09-17 03:35:35 operate:write writing...
2008-09-17 03:35:35 operate:write sql:REPLACE INTO `sessions` (sessionid, data, lastvisit) VALUES('650fcm4p8aodn1cfrusc5ehql0', 'name|s:5:\"caihf\";', '1221622535')
2008-09-17 03:35:35 operate:write closing...
2008-09-17 03:35:35 operate:write gcing...
2008-09-17 03:35:35 operate:write sql:DELETE FROM `sessions` WHERE lastvisit<1221622515

從session中讀數據時的log,如$name = $_SESSION['name'];echo "name:$name<br />";
2008-09-17 03:44:24 operate:read session_id:650fcm4p8aodn1cfrusc5ehql0
2008-09-17 03:44:24 operate:read opening...
2008-09-17 03:44:24 operate:read reading...
2008-09-17 03:44:24 operate:read sql:SELECT data FROM `sessions` WHERE sessionid='650fcm4p8aodn1cfrusc5ehql0'
2008-09-17 03:44:24 operate:read writing...
2008-09-17 03:44:24 operate:read sql:REPLACE INTO `sessions` (sessionid, data, lastvisit) VALUES('650fcm4p8aodn1cfrusc5ehql0', 'name|s:5:\"caihf\";', '1221623064')
2008-09-17 03:44:24 operate:read closing...
2008-09-17 03:44:24 operate:read gcing...
2008-09-17 03:44:24 operate:read sql:DELETE FROM `sessions` WHERE lastvisit<1221623044
*/
?>

session_test1.php

<?php
include_once('session_mysql.class.php');
include_once('db_mysql.class.php');

$db = new db_mysql();
$db -> connect('localhost', 'root', 'home', 'test');
$session = new session('write');
$_SESSION['name'] = 'caihf';
//echo "name:" . $_SESSION['name'] . "<br />\n";
echo 'Assign value to session over!';
?>

session_test2.php

<?php
include_once('session_mysql.class.php');
include_once('db_mysql.class.php');

$db = new db_mysql();
$db -> connect('localhost', 'root', 'home', 'test');
$session = new session('read');

function is_login() {
    return strlen($_SESSION['name']) > 0 ? 1 : 0;
}

if (is_login()) {
    echo "Hello {$_SESSION['name']} <br />\n";
} else {
    echo "User not loggined! <br />\n";
}
//unset($_SESSION['name']);
/*
執行完unset($_SESSION['name']);操作,然後再刷新此頁面時,字段data的值就變爲空了
sessionid                  data lastvisit
am1dmhbd2dsq9fpglpdh81u0d6  1221634486
*/
?>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章