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

时间:2023-03-09 09:49:04
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
)
);