<?php
/**
 * mysql session
 * @copyright reginx.com
 * $Id$
 */
class mysql_sess {
    
    /**
     * 会话 ID
     *
     * @var unknown_type
     */
    private $_sessid = null;
    
    /**
     * GC 概率 (注: 当前算法中 0.01 的概率效果是等于 0.0x的 ; 概率只能是 0.1 的10倍数)
     *
     * @var unknown_type
     */
    private $_gcpro  = 0.01;
    
    /**
     * 表操作对象
     *
     * @var unknown_type
     */
    private $_tobj   = null;
    
    /**
     * 存储 sessid 的 cookie名称
     *
     * @var unknown_type
     */
    private $_sname  = 'REGINXSESSID';
    
    /**
     * 超时时长
     *
     * @var unknown_type
     */
    private $_ttl    = 900;
    
    /**
     * sess 数据
     *
     * @var unknown_type
     */
    private $_sdata  = array();
    
    
    private $_domain = '';
    
    /**
     * 架构函数
     *
     */
    public function  __construct($conf = array() , $extra = true){
        $this->_domain = $_SERVER['HTTP_HOST'];
        if(substr_count($_SERVER['HTTP_HOST'] , '.') >= 2 ){
            $this->_domain = substr($_SERVER['HTTP_HOST'] , strpos($_SERVER['HTTP_HOST'] , '.'));
        }else{
            $this->_domain = '.' . $_SERVER['HTTP_HOST'];
        }
        $this->_sessid = $_COOKIE[$this->_sname];
        if(empty($this->_sessid) || !preg_match('/^\w+$/' , $this->_sessid)){
            $this->_sessid =  $this->_getsessid();
        }
        if(empty($this->_tobj)){
            $this->_tobj = OBJ('sess_tab');
        }
        $this->open();
    }
    
    /**
     * 生成 session Id
     *
     * @return unknown
     */
    private function _getsessid(){
        return md5(core::getip() . $_SERVER['HTTP_USER_AGENT'] . REQUEST_TIME .uniqid());
    }
    
    /**
     * 开启会话
     *
     * @param unknown_type $sessid
     */
    public function open(){
        $data = array();
        $ip   = sprintf('%u',ip2long(core::getip()));
        $data = $this->_tobj->where("sessid = '{$this->_sessid}' and lastvisit >= " . (REQUEST_TIME - $this->_ttl))->get();
        if(!empty($data)){
            $this->_sdata  = unserialize(htmlspecialchars_decode($data['sdata'] , ENT_QUOTES));
            $this->_tobj->exec("update sess_tab set ip = {$ip} , lastvisit = " . REQUEST_TIME . " where sessid = '{$this->_sessid}'");
        }else{
            $data['sessid'] = $this->_sessid;
            $data['ip']     = $ip;
            $data['lastvisit'] = REQUEST_TIME;
            $data['sdata']  = serialize($this->_sdata);
            if($this->_tobj->load($data)){
                $this->_tobj->replace();
            }
        }
        header("Cache-control: private");
        setcookie($this->_sname , $this->_sessid , REQUEST_TIME + $this->_ttl , '/' , $this->_domain);
    }
    
    /**
     * 写入
     *
     * @param unknown_type $key
     * @param unknown_type $v
     */
    public function set($key , $v){
        $this->_sdata[$key] = $v;
        $this->_tobj->exec("update sess_tab set sdata = '" . filter::code(serialize($this->_sdata)) . "' where sessid = '{$this->_sessid}'");
    }
    
    /**
     * 删除
     *
     * @param unknown_type $k
     */
    public function del($key){
        $this->_sdata[$key] = null;
        unset($this->_sdata[$key]);
        $this->_tobj->exec("update sess_tab set sdata = '" . filter::code(serialize($this->_sdata)) . "' where sessid = '{$this->_sessid}'");
    }
    
    /**
     * 读取
     *
     * @param unknown_type $key
     * @return unknown
     */
    public function get($key){
        return isset($this->_sdata[$key]) ? $this->_sdata[$key] : null;
    }
    
    
    /**
     * 注销会话
     *
     */
    public function remove(){
        $this->_tobj->where("sessid = '{$this->_sessid}'")->del();
        //unset($_COOKIE[$this->_sname]);
        //setcookie($this->_sname);
        $this->gc();
    }
    
    /**
     * 是否已经赋值
     *
     * @param unknown_type $key
     * @return unknown
     */
    public function has($key){
        return isset($this->_sdata[$key]);
    }
    
    /**
     * 清理回收
     *
     * @param unknown_type $force
     */
    private function gc($force = false){
        if($force){
            // 强力清除所有sess数据
            $this->_tobj->where("lastvisit <= " . (REQUEST_TIME - $this->_ttl))->del();
        }else{
            // 按照概率清除
            if( intval(mt_rand(1 , intval(1 / $this->_gcpro))) == intval( (1 / $this->_gcpro) * $this->_gcpro)){
                $this->_tobj->where("lastvisit <= " . (REQUEST_TIME - $this->_ttl))->del();
            }
        }
    }
    
    /**
     * 对象销毁
     */
    public function __destruct(){
        $this->_sdata = null;
    }
    
}