session共享,格式json,php不能简单的设置session.serialize_handler=json,目前只有php,wddx(xml),安装扩展后还有igbinary(二进制)

即使session_save_handler被自己的类或者方法重写,write与read的出入数据都还是被序列化的,而且被session序列化不是一般的序列化...还是不能解解决memcached保存session数据为json的格式。

貌似php_memcached扩展有个option是可以选择序列化方式的有json方式的选项,这个还没试过,就怕只有是test|s:4:"data"中右边的部分json编码,再就是自己实现session的过程。。。

session被重新handler后的执行session_start的顺序:

在类析构函数里执行session_write_close函数

open
read--eke723bndobd24jhtn4sivb1i6
gc(有一定的概率执行)
write--eke723bndobd24jhtn4sivb1i6,
close

执行:$_SESSON['test']='data';$_SESSION['test2']=2;赋值操作:

open
read--eke723bndobd24jhtn4sivb1i6
------------------
write--eke723bndobd24jhtn4sivb1i6,--test|s:4:"data";test2|i:2;
close
不管session被赋值几次,都只有一次读取和写入操作。

 

执行:echo $_SESSION['test'];echo $_SESSION['test2'];

open
read--eke723bndobd24jhtn4sivb1i6
------------------
12 write--eke723bndobd24jhtn4sivb1i6,--test|i:1;test2|i:2;
close

读取之后也要最后写入一次。即使没有session写操作。

 

 

 

附上session_save_handler类:

class Cache_Session_Handler
{
    public $_memcache;
   public function __construct()
   {
        $this->_memcache = new Memcache;
        $this->_memcache->addServer(
                '192.168.11.23', 11211, 1
        );
      session_set_save_handler(
         array($this, "open"),
         array($this, "close"),
         array($this, "read"),
         array($this, "write"),
         array($this, "destroy"),
         array($this, "gc")
      );
    }

    public function open()
    {
        echo "open<br/>";
        $this->_lifetime = ini_get('session.gc_maxlifetime');
        return TRUE;
    }

    public function read($id)
    {
        echo "read--{$id}<br/>";
        $data = $this->_memcache->get($id);
        return $data;
    }

    public function write($id, $data)
    {
        echo "write--{$id},--{$data}<br/>";
        $ttl = 1200;
        //var_dump($data);
        $result = $this->_memcache->replace($id, $data, 0, $ttl);
        if($result === FALSE)
        {
            $result = $this->_memcache->add($id, $data, 0, $ttl);
        }
        return $result;
    }

    public function destroy($id)
    {
        echo "destory--{$id}<br/>";
        return $this->_memcache->delete($id);
    }

    public function gc()
    {
        echo "gc<br/>";
        return TRUE;
    }

    public function close()
    {
        echo "close<br/>";
        return TRUE;
    }

    public function __destruct()
    {
        //session_write_close();
    }
}
new Cache_Session_Handler();
session_start();

 

 

 

自己实现的session的功能,借用session_start产生cookie,也可以手动生成session_id自己控制cookie。

<?php
Class Usession
{
    public static $userdata;
    public static $destruct = true;
    public $memObj;
    public $session_name;
    public $session_id;
    public $sess_match_ip=false;
    public $sess_match_useragent=false;
    public $now;
    public $config_session = array(
        'cookie_prefix'    => "",
        'cookie_domain'    => ".mypharma.com",
        'cookie_path'       => "/",
        'cookie_secure'    => FALSE,
        'cookie_httponly'    => FALSE,
        
        'sess_cookie_name'        => 'mphsess',
        'sess_expiration'            => 0,
        'sess_expire_on_close'    => true,
        'sess_memcached_ttl'      => 864000,
        'sess_match_ip'            => TRUE,
        'sess_match_useragent'    => TRUE,
    );
    
    private static $_instance;
    
    protected $_memcache_conf    = array(
        'default' => array(
            'default_host'        => '127.0.0.1',
            'default_port'        => 11211,
            'default_weight'    => 1
        )
    );
    
    public static function getInstance($params = array())
    {
        if(! (self::$_instance instanceof self) )   
        {    
            self::$_instance = new self($params);    
        }  
        return self::$_instance;
    }
    
    private function __clone()  
    {  
    }
    
    private function __construct($params = array())
    {
        include_once __DIR__."/config_memcached.php";
        $this->set_config($config_session,$_memcache_conf);
        $this->now = time();
        $this->mem_create();
        $this->session_name = $config_session['sess_cookie_name'].'_id';
        $this->session_id = isset($_COOKIE[$this->session_name]) ? $_COOKIE[$this->session_name] : null;
        if(empty($params)){
            $this->sess_create();
        }
    }
    
    public function set_config($config_session,$_memcache_conf)
    {
        if(!empty($config_session) AND is_array($config_session))
        {
            foreach($config_session as $k => $v){
                $this->config_session[$k] = $v;
            }
        }
        if(!empty($_memcache_conf) AND is_array($_memcache_conf))
        {
            $this->_memcache_conf = null;
            foreach($_memcache_conf as $k => $v){
                $this->_memcache_conf[$k] = $v;
            }
        }
    }
    
    public function set_session_id($session_id)
    {
        $this->session_id = $session_id;
        //$this->set_session_cookie(true,true);
    }
    
    public function sess_check()
    {
        // Is the session data we unserialized an array with the correct format?
        if ( ! is_array(self::$userdata) OR ! isset(self::$userdata['session_id']) OR ! isset(self::$userdata['ip_address']) OR ! isset(self::$userdata['user_agent']) OR ! isset(self::$userdata['last_activity']))
        {
            $this->sess_destroy();
            return FALSE;
        }

        // Does the IP Match?
        if ($this->sess_match_ip == TRUE AND self::$userdata['ip_address'] != $this->ip_address())
        {
            $this->sess_destroy();
            return FALSE;
        }

        // Does the User Agent Match?
        if ($this->sess_match_useragent == TRUE AND trim(self::$userdata['user_agent']) != trim(substr($this->user_agent(), 0, 120)))
        {
            $this->sess_destroy();
            return FALSE;
        }

        return TRUE;
    }
    
    public function set_session_cookie($flag=true,$isset=false)
    {
        $secure = (bool) $this->config_session['cookie_secure'];
        $http_only = (bool) $this->config_session['cookie_httponly'];

        if ($this->config_session['sess_expiration'] !== FALSE)
        {
            $expire = ($this->config_session['sess_expire_on_close'] == true) ? 0 : $this->config_session['sess_expiration']+time();
        }

        if ($this->config_session['cookie_path'])
        {
            $path = $this->config_session['cookie_path'];
        }

        if ($this->config_session['cookie_domain'])
        {
            $domain = $this->config_session['cookie_domain'];
        }
        $cookieA = array(
            'name'   => $this->session_name,
            'value'  => $isset ? $this->session_id:uniqid("mph_",true),
            'expire' => $flag ? $expire : time()-3600,
            'domain' => $domain,
            'path'   => $path,
            'secure' => $secure,
            'httponly'=>$http_only,
        );
        $this->set_cookie($cookieA);
        $this->session_id=$cookieA['value'];
    }
    
    public function sess_read()
    {
        self::$userdata = json_decode($this->memObj->get($this->session_id),true);
    }
        // --------------------------------------------------------------------

    /**
     * Write the session data
     *
     * @access        public
     * @return        void
     */
    public function sess_write($array)
    {
        foreach($array as $k => $v){
            self::$userdata[$k]=$v;
        }
        $data = json_encode(self::$userdata);
        if (get_class($this->memObj) === 'Memcached')
        {
            return $this->memObj->set($this->session_id, $data, $this->config_session['sess_memcached_ttl']);
        }
        elseif (get_class($this->memObj) === 'Memcache')
        {
            return $this->memObj->set($this->session_id, $data, 0, $this->config_session['sess_memcached_ttl']);
        }
        return FALSE;
    }

    // --------------------------------------------------------------------

    /**
     * Create a new session
     *
     * @access        public
     * @return        void
     */
    public function sess_create()
    {
        if($this->session_id == null)
        {
            $this->set_session_cookie();
            $this->init_data();
        }
        $this->sess_read();
        if($this->sess_check() === false){
            $this->set_session_cookie();
            $this->init_data();
        }
    }

    // --------------------------------------------------------------------

    /**
     * Destroy the current session
     *
     * @access        public
     * @return        void
     */
    public function sess_destroy()
    {
        self::$userdata = array();
        self::$destruct = false;
        $this->memObj->delete($this->session_id);
        return $this->set_session_cookie(false);
    }
    
    public function userdata($key='')
    {
        if(empty($key)){
            return self::$userdata;
        }
        if(isset(self::$userdata[$key])){
            return self::$userdata[$key];
        }else{
            return null;
        }
    }
    
    public function set_userdata($key,$val='')
    {
        if(is_array($key)){
            foreach($key as $kk => $vv){
                self::$userdata[$kk]=$vv;
            }
        }else{
            self::$userdata[$key]=$val;
        }
    }
    
    protected function init_data()
    {
        $array['session_id']          = $this->session_id;
        $array['ip_address']          = $this->ip_address();
        $array['user_agent']          = substr($this->user_agent(), 0, 120);
        $array['last_activity']       = $this->now;
        $this->sess_write($array);
    }
    
    protected function mem_create()
    {
        if (class_exists('Memcached', FALSE))
        {
            $this->memObj = new Memcached();
        }
        elseif (class_exists('Memcache', FALSE))
        {
            $this->memObj = new Memcache();
        }
        else
        {
            log_message('error', 'Failed to create object for Memcached Cache; extension not loaded?');
            return FALSE;
        }

        foreach ($this->_memcache_conf as $name => $cache_server)
        {
            if ( ! array_key_exists('hostname', $cache_server))
            {
                $cache_server['hostname'] = $this->_memcache_conf['default']['default_host'];
            }

            if ( ! array_key_exists('port', $cache_server))
            {
                $cache_server['port'] = $this->_memcache_conf['default']['default_port'];
            }

            if ( ! array_key_exists('weight', $cache_server))
            {
                $cache_server['weight'] = $this->_memcache_conf['default']['default_weight'];
            }

            if (get_class($this->memObj) === 'Memcache')
            {
                // Third parameter is persistance and defaults to TRUE.
                $this->memObj->addServer(
                    $cache_server['hostname'],
                    $cache_server['port'],
                    TRUE,
                    $cache_server['weight']
                );
            }
            else
            {
                $this->memObj->addServer(
                    $cache_server['hostname'],
                    $cache_server['port'],
                    $cache_server['weight']
                );
            }
        }
        return TRUE;
    }
    
    public function __destruct()
    {
        if(self::$destruct){
            $data = json_encode(self::$userdata);
            if (get_class($this->memObj) === 'Memcached')
            {
                return $this->memObj->set($this->session_id, $data, $this->config_session['sess_memcached_ttl']);
            }
            elseif (get_class($this->memObj) === 'Memcache')
            {
                return $this->memObj->set($this->session_id, $data, 0, $this->config_session['sess_memcached_ttl']);
            }
        }
    }
    
    // --------------------------------------------------------------------

    /**
     * Does nothing for native sessions
     *
     * @access public
     * @return void
     */
    public function _sess_gc(){}
    
    
    public function ip_address()
    {
        $this->ip_address = $_SERVER['REMOTE_ADDR'];

        if ( ! $this->valid_ip($this->ip_address))
        {
            $this->ip_address = '0.0.0.0';
        }

        return $this->ip_address;
    }
    
    
    public function valid_ip($ip, $which = '')
    {
        $which = strtolower($which);

        // First check if filter_var is available
        if (is_callable('filter_var'))
        {
            switch ($which) {
                case 'ipv4':
                    $flag = FILTER_FLAG_IPV4;
                    break;
                case 'ipv6':
                    $flag = FILTER_FLAG_IPV6;
                    break;
                default:
                    $flag = '';
                    break;
            }

            return (bool) filter_var($ip, FILTER_VALIDATE_IP, $flag);
        }

        if ($which !== 'ipv6' && $which !== 'ipv4')
        {
            if (strpos($ip, ':') !== FALSE)
            {
                $which = 'ipv6';
            }
            elseif (strpos($ip, '.') !== FALSE)
            {
                $which = 'ipv4';
            }
            else
            {
                return FALSE;
            }
        }

        $func = '_valid_'.$which;
        return $this->$func($ip);
    }
    
    protected function _valid_ipv4($ip)
    {
        $ip_segments = explode('.', $ip);

        // Always 4 segments needed
        if (count($ip_segments) !== 4)
        {
            return FALSE;
        }
        // IP can not start with 0
        if ($ip_segments[0][0] == '0')
        {
            return FALSE;
        }

        // Check each segment
        foreach ($ip_segments as $segment)
        {
            // IP segments must be digits and can not be
            // longer than 3 digits or greater then 255
            if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)
            {
                return FALSE;
            }
        }

        return TRUE;
    }

    // --------------------------------------------------------------------

    /**
    * Validate IPv6 Address
    *
    * @access    protected
    * @param    string
    * @return    bool
    */
    protected function _valid_ipv6($str)
    {
        // 8 groups, separated by :
        // 0-ffff per group
        // one set of consecutive 0 groups can be collapsed to ::

        $groups = 8;
        $collapsed = FALSE;

        $chunks = array_filter(
            preg_split('/(:{1,2})/', $str, NULL, PREG_SPLIT_DELIM_CAPTURE)
        );

        // Rule out easy nonsense
        if (current($chunks) == ':' OR end($chunks) == ':')
        {
            return FALSE;
        }

        // PHP supports IPv4-mapped IPv6 addresses, so we'll expect those as well
        if (strpos(end($chunks), '.') !== FALSE)
        {
            $ipv4 = array_pop($chunks);

            if ( ! $this->_valid_ipv4($ipv4))
            {
                return FALSE;
            }

            $groups--;
        }

        while ($seg = array_pop($chunks))
        {
            if ($seg[0] == ':')
            {
                if (--$groups == 0)
                {
                    return FALSE;    // too many groups
                }

                if (strlen($seg) > 2)
                {
                    return FALSE;    // long separator
                }

                if ($seg == '::')
                {
                    if ($collapsed)
                    {
                        return FALSE;    // multiple collapsed
                    }

                    $collapsed = TRUE;
                }
            }
            elseif (preg_match("/[^0-9a-f]/i", $seg) OR strlen($seg) > 4)
            {
                return FALSE; // invalid segment
            }
        }

        return $collapsed OR $groups == 1;
    }
    
    protected function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE)
    {
        if (is_array($name))
        {
            // always leave 'name' in last place, as the loop will break otherwise, due to $$item
            foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item)
            {
                if (isset($name[$item]))
                {
                    $$item = $name[$item];
                }
            }
        }

        if ($prefix == '' AND $this->config_session['cookie_prefix'] != '')
        {
            $prefix = $this->config_session['cookie_prefix'];
        }
        if ($domain == '' AND $this->config_session['cookie_domain'] != '')
        {
            $domain = $this->config_session['cookie_domain'];
        }
        if ($path == '/' AND $this->config_session['cookie_path'] != '/')
        {
            $path = $this->config_session['cookie_path'];
        }
        if ($secure == FALSE AND $this->config_session['cookie_secure'] != FALSE)
        {
            $secure = $this->config_session['cookie_secure'];
        }

        if ( ! is_numeric($expire))
        {
            $expire = time() - 86500;
        }
        else
        {
            $expire = ($expire > 0) ? time() + $expire : 0;
        }

        setcookie($prefix.$name, $value, $expire, $path, $domain, $secure);
    }
    
    protected function user_agent()
    {
        return ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];
    }
}

配置文件与上面的类文件同目录:

<?php
$config_session['cookie_prefix']    = "";
$config_session['cookie_domain']    = ".mypharma.com";
$config_session['cookie_path']        = "/";
$config_session['cookie_secure']    = FALSE;
$config_session['cookie_httponly']    = FALSE;

$config_session['sess_cookie_name']        = 'mphsess';
$config_session['sess_expiration']            = 0;
$config_session['sess_expire_on_close']    = true;
$config_session['sess_memcached_ttl']      = 10*24*60*60;
$config_session['sess_match_ip']            = TRUE;
$config_session['sess_match_useragent']    = TRUE;

$_memcache_conf = array(
    '23'=>array(
        'hostname'=>'192.168.11.23',
        'port'=>11211,
        'weight'=>1
    )
);

 

posted on 2013-10-22 11:38  kudosharry  阅读(1806)  评论(0编辑  收藏  举报

导航