2012年2月13日 星期一

Session To DB/MemCache

前言:避免系統產生過多儲存session用的暫存檔,直接將session存於DB
# above PHP 5.4.0
class sessionMemCache implements SessionHandlerInterface{
 protected $_maxLifeTime = 5400;
 
 public function getMaxLifeTime(){
  return $this->_maxLifeTime;
 }
 
 public function open($path, $id){
  return true;
 }
 
 public function close(){
  return true;
 }
 
 public function read($id){
  $memCache = new Memcache;
  $memCache->connect(SESS_MEMCACHE, 11211) OR die('MemCache Error');
  $session = $memCache->get('SESSION'. $id);
  $memCache->close();
  return $session['data'];
 }
 
 public function write($id, $value){
  if(trim($id) == '') return '';
  
  $expire = time() + $this->_maxLifeTime;
  $session = array();
  $session['data'] = $value;
  $session['expire'] = $expire;
  
  $memCache = new Memcache;
  $memCache->connect(SESS_MEMCACHE, 11211) OR die('MemCache Error');
  $memCache->set('SESSION'. $id, $session, MEMCACHE_COMPRESSED, $this->_maxLifeTime);
  $memCache->close();
  
  return;
 }
 
 public function destroy($id){
  $memCache = new Memcache;
  $memCache->connect(SESS_MEMCACHE, 11211) OR die('MemCache Error');
  $memCache->delete('SESSION'.$id);
  $memCache->close();
  return true;
 }
 
 public function gc($maxLifeTime){
  return true;
 }
}
session_set_save_handler($sessionMemCache, true);
session_start();

# less than PHP 5.4.0
class sessionToDB{
    protected $_connector = null;
    protected $_maxLifeTime = 1800;
    protected $_expiration = 0;

    public function __construct(){
        session_set_save_handler(
            array(&$this, 'open'),
            array(&$this, 'close'),
            array(&$this, 'read'),
            array(&$this, 'write'),
            array(&$this, 'destroy'),
            array(&$this, 'gc')
        );

        $factory = new factory();
        $this->_connector = $factory->dbFactory();

        #判斷IP是否為127.0.0.1,再決定cookie有效網域
        if($_SERVER['REMOTE_ADDR'] != '127.0.0.1'){
            session_set_cookie_params('','/','.abc.com');
        }

        session_start();
        # bug??? 程式不會自動執行gc,所以手動執行
        $this->gc();
    }

    public function __destruct(){
        session_write_close();
    }

    public function open(){
        return true;
    }

    public function close(){
        return true;
    }

    public function read($id){
        $row = $this->_connector->select()
                         ->from('sessions')
                         ->where('id = ? and expiration > ?')
                         ->exe(array($id, time()))
                         ->fetch();

        return $row['value'];
    }

    public function write($id, $value){
        $this->_expiration = time() + $this->_maxLifeTime;

        $data['id'] = $id;
        $data['ip'] = $_SERVER['REMOTE_ADDR'];
        $data['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
        $data['expiration'] = $this->_expiration;
        $data['value'] = $value;

        try{
            #檢查session table內是否已有此id,有=>update,無=>insert
            $row = $this->_connector->select('id')
                   ->from('sessions')
                   ->where('id = ?')
                   ->exe(array($id))
                   ->fetch();

            if(!empty($row['id'])){
                $dummy = $this->_connector->setTableName('sessions')
                     ->enableValidate()
                     ->update($data, 'id = ?', array($data['id']));
            }else{
                $dummy = $this->_connector->setTableName('sessions')
                     ->enableValidate()
                     ->insert($data);
            }
            return true;
        }catch(Exception $e){
            #echo $e->getMessage();
        }
    }

    public function destroy($id){
        $dummy = $this->_connector->setTableName('sessions')
             ->delete('id = ?', array($id));
        return true;
    }

    public function gc(){
        $dummy = $this->_connector->setTableName('sessions')
             ->delete('expiration < ?', array(time()));
        return true;
    }
}
?>

沒有留言:

張貼留言