即使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类:

  1. class Cache_Session_Handler
  2. {
  3. public $_memcache;
  4. public function __construct()
  5. {
  6. $this->_memcache = new Memcache;
  7. $this->_memcache->addServer(
  8. '192.168.11.23', 11211, 1
  9. );
  10. session_set_save_handler(
  11. array($this, "open"),
  12. array($this, "close"),
  13. array($this, "read"),
  14. array($this, "write"),
  15. array($this, "destroy"),
  16. array($this, "gc")
  17. );
  18. }
  19.  
  20. public function open()
  21. {
  22. echo "open<br/>";
  23. $this->_lifetime = ini_get('session.gc_maxlifetime');
  24. return TRUE;
  25. }
  26.  
  27. public function read($id)
  28. {
  29. echo "read--{$id}<br/>";
  30. $data = $this->_memcache->get($id);
  31. return $data;
  32. }
  33.  
  34. public function write($id, $data)
  35. {
  36. echo "write--{$id},--{$data}<br/>";
  37. $ttl = 1200;
  38. //var_dump($data);
  39. $result = $this->_memcache->replace($id, $data, 0, $ttl);
  40. if($result === FALSE)
  41. {
  42. $result = $this->_memcache->add($id, $data, 0, $ttl);
  43. }
  44. return $result;
  45. }
  46.  
  47. public function destroy($id)
  48. {
  49. echo "destory--{$id}<br/>";
  50. return $this->_memcache->delete($id);
  51. }
  52.  
  53. public function gc()
  54. {
  55. echo "gc<br/>";
  56. return TRUE;
  57. }
  58.  
  59. public function close()
  60. {
  61. echo "close<br/>";
  62. return TRUE;
  63. }
  64.  
  65. public function __destruct()
  66. {
  67. //session_write_close();
  68. }
  69. }
  70. new Cache_Session_Handler();
  71. session_start();

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

  1. <?php
  2. Class Usession
  3. {
  4. public static $userdata;
  5. public static $destruct = true;
  6. public $memObj;
  7. public $session_name;
  8. public $session_id;
  9. public $sess_match_ip=false;
  10. public $sess_match_useragent=false;
  11. public $now;
  12. public $config_session = array(
  13. 'cookie_prefix' => "",
  14. 'cookie_domain' => ".mypharma.com",
  15. 'cookie_path' => "/",
  16. 'cookie_secure' => FALSE,
  17. 'cookie_httponly' => FALSE,
  18.  
  19. 'sess_cookie_name' => 'mphsess',
  20. 'sess_expiration' => 0,
  21. 'sess_expire_on_close' => true,
  22. 'sess_memcached_ttl' => 864000,
  23. 'sess_match_ip' => TRUE,
  24. 'sess_match_useragent' => TRUE,
  25. );
  26.  
  27. private static $_instance;
  28.  
  29. protected $_memcache_conf = array(
  30. 'default' => array(
  31. 'default_host' => '127.0.0.1',
  32. 'default_port' => 11211,
  33. 'default_weight' => 1
  34. )
  35. );
  36.  
  37. public static function getInstance($params = array())
  38. {
  39. if(! (self::$_instance instanceof self) )
  40. {
  41. self::$_instance = new self($params);
  42. }
  43. return self::$_instance;
  44. }
  45.  
  46. private function __clone()
  47. {
  48. }
  49.  
  50. private function __construct($params = array())
  51. {
  52. include_once __DIR__."/config_memcached.php";
  53. $this->set_config($config_session,$_memcache_conf);
  54. $this->now = time();
  55. $this->mem_create();
  56. $this->session_name = $config_session['sess_cookie_name'].'_id';
  57. $this->session_id = isset($_COOKIE[$this->session_name]) ? $_COOKIE[$this->session_name] : null;
  58. if(empty($params)){
  59. $this->sess_create();
  60. }
  61. }
  62.  
  63. public function set_config($config_session,$_memcache_conf)
  64. {
  65. if(!empty($config_session) AND is_array($config_session))
  66. {
  67. foreach($config_session as $k => $v){
  68. $this->config_session[$k] = $v;
  69. }
  70. }
  71. if(!empty($_memcache_conf) AND is_array($_memcache_conf))
  72. {
  73. $this->_memcache_conf = null;
  74. foreach($_memcache_conf as $k => $v){
  75. $this->_memcache_conf[$k] = $v;
  76. }
  77. }
  78. }
  79.  
  80. public function set_session_id($session_id)
  81. {
  82. $this->session_id = $session_id;
  83. //$this->set_session_cookie(true,true);
  84. }
  85.  
  86. public function sess_check()
  87. {
  88. // Is the session data we unserialized an array with the correct format?
  89. 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']))
  90. {
  91. $this->sess_destroy();
  92. return FALSE;
  93. }
  94.  
  95. // Does the IP Match?
  96. if ($this->sess_match_ip == TRUE AND self::$userdata['ip_address'] != $this->ip_address())
  97. {
  98. $this->sess_destroy();
  99. return FALSE;
  100. }
  101.  
  102. // Does the User Agent Match?
  103. if ($this->sess_match_useragent == TRUE AND trim(self::$userdata['user_agent']) != trim(substr($this->user_agent(), 0, 120)))
  104. {
  105. $this->sess_destroy();
  106. return FALSE;
  107. }
  108.  
  109. return TRUE;
  110. }
  111.  
  112. public function set_session_cookie($flag=true,$isset=false)
  113. {
  114. $secure = (bool) $this->config_session['cookie_secure'];
  115. $http_only = (bool) $this->config_session['cookie_httponly'];
  116.  
  117. if ($this->config_session['sess_expiration'] !== FALSE)
  118. {
  119. $expire = ($this->config_session['sess_expire_on_close'] == true) ? 0 : $this->config_session['sess_expiration']+time();
  120. }
  121.  
  122. if ($this->config_session['cookie_path'])
  123. {
  124. $path = $this->config_session['cookie_path'];
  125. }
  126.  
  127. if ($this->config_session['cookie_domain'])
  128. {
  129. $domain = $this->config_session['cookie_domain'];
  130. }
  131. $cookieA = array(
  132. 'name' => $this->session_name,
  133. 'value' => $isset ? $this->session_id:uniqid("mph_",true),
  134. 'expire' => $flag ? $expire : time()-3600,
  135. 'domain' => $domain,
  136. 'path' => $path,
  137. 'secure' => $secure,
  138. 'httponly'=>$http_only,
  139. );
  140. $this->set_cookie($cookieA);
  141. $this->session_id=$cookieA['value'];
  142. }
  143.  
  144. public function sess_read()
  145. {
  146. self::$userdata = json_decode($this->memObj->get($this->session_id),true);
  147. }
  148. // --------------------------------------------------------------------
  149.  
  150. /**
  151. * Write the session data
  152. *
  153. * @access public
  154. * @return void
  155. */
  156. public function sess_write($array)
  157. {
  158. foreach($array as $k => $v){
  159. self::$userdata[$k]=$v;
  160. }
  161. $data = json_encode(self::$userdata);
  162. if (get_class($this->memObj) === 'Memcached')
  163. {
  164. return $this->memObj->set($this->session_id, $data, $this->config_session['sess_memcached_ttl']);
  165. }
  166. elseif (get_class($this->memObj) === 'Memcache')
  167. {
  168. return $this->memObj->set($this->session_id, $data, 0, $this->config_session['sess_memcached_ttl']);
  169. }
  170. return FALSE;
  171. }
  172.  
  173. // --------------------------------------------------------------------
  174.  
  175. /**
  176. * Create a new session
  177. *
  178. * @access public
  179. * @return void
  180. */
  181. public function sess_create()
  182. {
  183. if($this->session_id == null)
  184. {
  185. $this->set_session_cookie();
  186. $this->init_data();
  187. }
  188. $this->sess_read();
  189. if($this->sess_check() === false){
  190. $this->set_session_cookie();
  191. $this->init_data();
  192. }
  193. }
  194.  
  195. // --------------------------------------------------------------------
  196.  
  197. /**
  198. * Destroy the current session
  199. *
  200. * @access public
  201. * @return void
  202. */
  203. public function sess_destroy()
  204. {
  205. self::$userdata = array();
  206. self::$destruct = false;
  207. $this->memObj->delete($this->session_id);
  208. return $this->set_session_cookie(false);
  209. }
  210.  
  211. public function userdata($key='')
  212. {
  213. if(empty($key)){
  214. return self::$userdata;
  215. }
  216. if(isset(self::$userdata[$key])){
  217. return self::$userdata[$key];
  218. }else{
  219. return null;
  220. }
  221. }
  222.  
  223. public function set_userdata($key,$val='')
  224. {
  225. if(is_array($key)){
  226. foreach($key as $kk => $vv){
  227. self::$userdata[$kk]=$vv;
  228. }
  229. }else{
  230. self::$userdata[$key]=$val;
  231. }
  232. }
  233.  
  234. protected function init_data()
  235. {
  236. $array['session_id'] = $this->session_id;
  237. $array['ip_address'] = $this->ip_address();
  238. $array['user_agent'] = substr($this->user_agent(), 0, 120);
  239. $array['last_activity'] = $this->now;
  240. $this->sess_write($array);
  241. }
  242.  
  243. protected function mem_create()
  244. {
  245. if (class_exists('Memcached', FALSE))
  246. {
  247. $this->memObj = new Memcached();
  248. }
  249. elseif (class_exists('Memcache', FALSE))
  250. {
  251. $this->memObj = new Memcache();
  252. }
  253. else
  254. {
  255. log_message('error', 'Failed to create object for Memcached Cache; extension not loaded?');
  256. return FALSE;
  257. }
  258.  
  259. foreach ($this->_memcache_conf as $name => $cache_server)
  260. {
  261. if ( ! array_key_exists('hostname', $cache_server))
  262. {
  263. $cache_server['hostname'] = $this->_memcache_conf['default']['default_host'];
  264. }
  265.  
  266. if ( ! array_key_exists('port', $cache_server))
  267. {
  268. $cache_server['port'] = $this->_memcache_conf['default']['default_port'];
  269. }
  270.  
  271. if ( ! array_key_exists('weight', $cache_server))
  272. {
  273. $cache_server['weight'] = $this->_memcache_conf['default']['default_weight'];
  274. }
  275.  
  276. if (get_class($this->memObj) === 'Memcache')
  277. {
  278. // Third parameter is persistance and defaults to TRUE.
  279. $this->memObj->addServer(
  280. $cache_server['hostname'],
  281. $cache_server['port'],
  282. TRUE,
  283. $cache_server['weight']
  284. );
  285. }
  286. else
  287. {
  288. $this->memObj->addServer(
  289. $cache_server['hostname'],
  290. $cache_server['port'],
  291. $cache_server['weight']
  292. );
  293. }
  294. }
  295. return TRUE;
  296. }
  297.  
  298. public function __destruct()
  299. {
  300. if(self::$destruct){
  301. $data = json_encode(self::$userdata);
  302. if (get_class($this->memObj) === 'Memcached')
  303. {
  304. return $this->memObj->set($this->session_id, $data, $this->config_session['sess_memcached_ttl']);
  305. }
  306. elseif (get_class($this->memObj) === 'Memcache')
  307. {
  308. return $this->memObj->set($this->session_id, $data, 0, $this->config_session['sess_memcached_ttl']);
  309. }
  310. }
  311. }
  312.  
  313. // --------------------------------------------------------------------
  314.  
  315. /**
  316. * Does nothing for native sessions
  317. *
  318. * @access public
  319. * @return void
  320. */
  321. public function _sess_gc(){}
  322.  
  323. public function ip_address()
  324. {
  325. $this->ip_address = $_SERVER['REMOTE_ADDR'];
  326.  
  327. if ( ! $this->valid_ip($this->ip_address))
  328. {
  329. $this->ip_address = '0.0.0.0';
  330. }
  331.  
  332. return $this->ip_address;
  333. }
  334.  
  335. public function valid_ip($ip, $which = '')
  336. {
  337. $which = strtolower($which);
  338.  
  339. // First check if filter_var is available
  340. if (is_callable('filter_var'))
  341. {
  342. switch ($which) {
  343. case 'ipv4':
  344. $flag = FILTER_FLAG_IPV4;
  345. break;
  346. case 'ipv6':
  347. $flag = FILTER_FLAG_IPV6;
  348. break;
  349. default:
  350. $flag = '';
  351. break;
  352. }
  353.  
  354. return (bool) filter_var($ip, FILTER_VALIDATE_IP, $flag);
  355. }
  356.  
  357. if ($which !== 'ipv6' && $which !== 'ipv4')
  358. {
  359. if (strpos($ip, ':') !== FALSE)
  360. {
  361. $which = 'ipv6';
  362. }
  363. elseif (strpos($ip, '.') !== FALSE)
  364. {
  365. $which = 'ipv4';
  366. }
  367. else
  368. {
  369. return FALSE;
  370. }
  371. }
  372.  
  373. $func = '_valid_'.$which;
  374. return $this->$func($ip);
  375. }
  376.  
  377. protected function _valid_ipv4($ip)
  378. {
  379. $ip_segments = explode('.', $ip);
  380.  
  381. // Always 4 segments needed
  382. if (count($ip_segments) !== 4)
  383. {
  384. return FALSE;
  385. }
  386. // IP can not start with 0
  387. if ($ip_segments[0][0] == '0')
  388. {
  389. return FALSE;
  390. }
  391.  
  392. // Check each segment
  393. foreach ($ip_segments as $segment)
  394. {
  395. // IP segments must be digits and can not be
  396. // longer than 3 digits or greater then 255
  397. if ($segment == '' OR preg_match("/[^0-9]/", $segment) OR $segment > 255 OR strlen($segment) > 3)
  398. {
  399. return FALSE;
  400. }
  401. }
  402.  
  403. return TRUE;
  404. }
  405.  
  406. // --------------------------------------------------------------------
  407.  
  408. /**
  409. * Validate IPv6 Address
  410. *
  411. * @access protected
  412. * @param string
  413. * @return bool
  414. */
  415. protected function _valid_ipv6($str)
  416. {
  417. // 8 groups, separated by :
  418. // 0-ffff per group
  419. // one set of consecutive 0 groups can be collapsed to ::
  420.  
  421. $groups = 8;
  422. $collapsed = FALSE;
  423.  
  424. $chunks = array_filter(
  425. preg_split('/(:{1,2})/', $str, NULL, PREG_SPLIT_DELIM_CAPTURE)
  426. );
  427.  
  428. // Rule out easy nonsense
  429. if (current($chunks) == ':' OR end($chunks) == ':')
  430. {
  431. return FALSE;
  432. }
  433.  
  434. // PHP supports IPv4-mapped IPv6 addresses, so we'll expect those as well
  435. if (strpos(end($chunks), '.') !== FALSE)
  436. {
  437. $ipv4 = array_pop($chunks);
  438.  
  439. if ( ! $this->_valid_ipv4($ipv4))
  440. {
  441. return FALSE;
  442. }
  443.  
  444. $groups--;
  445. }
  446.  
  447. while ($seg = array_pop($chunks))
  448. {
  449. if ($seg[0] == ':')
  450. {
  451. if (--$groups == 0)
  452. {
  453. return FALSE; // too many groups
  454. }
  455.  
  456. if (strlen($seg) > 2)
  457. {
  458. return FALSE; // long separator
  459. }
  460.  
  461. if ($seg == '::')
  462. {
  463. if ($collapsed)
  464. {
  465. return FALSE; // multiple collapsed
  466. }
  467.  
  468. $collapsed = TRUE;
  469. }
  470. }
  471. elseif (preg_match("/[^0-9a-f]/i", $seg) OR strlen($seg) > 4)
  472. {
  473. return FALSE; // invalid segment
  474. }
  475. }
  476.  
  477. return $collapsed OR $groups == 1;
  478. }
  479.  
  480. protected function set_cookie($name = '', $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = FALSE)
  481. {
  482. if (is_array($name))
  483. {
  484. // always leave 'name' in last place, as the loop will break otherwise, due to $$item
  485. foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'name') as $item)
  486. {
  487. if (isset($name[$item]))
  488. {
  489. $$item = $name[$item];
  490. }
  491. }
  492. }
  493.  
  494. if ($prefix == '' AND $this->config_session['cookie_prefix'] != '')
  495. {
  496. $prefix = $this->config_session['cookie_prefix'];
  497. }
  498. if ($domain == '' AND $this->config_session['cookie_domain'] != '')
  499. {
  500. $domain = $this->config_session['cookie_domain'];
  501. }
  502. if ($path == '/' AND $this->config_session['cookie_path'] != '/')
  503. {
  504. $path = $this->config_session['cookie_path'];
  505. }
  506. if ($secure == FALSE AND $this->config_session['cookie_secure'] != FALSE)
  507. {
  508. $secure = $this->config_session['cookie_secure'];
  509. }
  510.  
  511. if ( ! is_numeric($expire))
  512. {
  513. $expire = time() - 86500;
  514. }
  515. else
  516. {
  517. $expire = ($expire > 0) ? time() + $expire : 0;
  518. }
  519.  
  520. setcookie($prefix.$name, $value, $expire, $path, $domain, $secure);
  521. }
  522.  
  523. protected function user_agent()
  524. {
  525. return ( ! isset($_SERVER['HTTP_USER_AGENT'])) ? FALSE : $_SERVER['HTTP_USER_AGENT'];
  526. }
  527. }

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

  1. <?php
  2. $config_session['cookie_prefix'] = "";
  3. $config_session['cookie_domain'] = ".mypharma.com";
  4. $config_session['cookie_path'] = "/";
  5. $config_session['cookie_secure'] = FALSE;
  6. $config_session['cookie_httponly'] = FALSE;
  7.  
  8. $config_session['sess_cookie_name'] = 'mphsess';
  9. $config_session['sess_expiration'] = 0;
  10. $config_session['sess_expire_on_close'] = true;
  11. $config_session['sess_memcached_ttl'] = 10*24*60*60;
  12. $config_session['sess_match_ip'] = TRUE;
  13. $config_session['sess_match_useragent'] = TRUE;
  14.  
  15. $_memcache_conf = array(
  16. '23'=>array(
  17. 'hostname'=>'192.168.11.23',
  18. 'port'=>11211,
  19. 'weight'=>1
  20. )
  21. );

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

  1. 分布式Session共享(一):tomcat+redis实现session共享

    一.前言 本文主要测试redis实现session共享的实现方式,不讨论如何让nginx参与实现负载均衡等. 二.环境配置 本测试在Window下进行 name version port Tomcat ...

  2. 分布式Session共享(二):tomcat+memcached实现session共享

    一.前言 本文主要测试memcached实现session共享的实现方式,不讨论如何让nginx参与实现负载均衡等. 二.环境配置 本测试在Window下进行 name version port To ...

  3. ajax 发送json数据时为什么需要设置contentType: "application/json”

    1. ajax发送json数据时设置contentType: "application/json”和不设置时到底有什么区别? contentType: "application/j ...

  4. ajax发送json数据时为什么需要设置contentType: "application/json”

    1. ajax发送json数据时设置contentType: "application/json”和不设置时到底有什么区别?contentType: "application/js ...

  5. Tomcat利用MSM实现Session共享方案解说

    Session共享有多种解决方法,常用的有四种:1)客户端Cookie保存2)服务器间Session同步3)使用集群管理Session(如MSM) 4)把Session持久化到数据库 针对上面Sess ...

  6. 分布式中使用Redis实现Session共享(二)

    上一篇介绍了一些redis的安装及使用步骤,本篇开始将介绍redis的实际应用场景,先从最常见的session开始,刚好也重新学习一遍session的实现原理.在阅读之前假设你已经会使用nginx+i ...

  7. Tomcat7基于Redis的Session共享实战二

    目前,为了使web能适应大规模的访问,需要实现应用的集群部署.集群最有效的方案就是负载均衡,而实现负载均衡用户每一个请求都有可能被分配到不固定的服务器上,这样我们首先要解决session的统一来保证无 ...

  8. 集群间Session共享问题解决方案

    两个基本概念的生命周期 session: 当新客户端发现一个HTTP请求时服务端会创建一个session.并分配一个sessionID作为服务端来客户端的识别,session对象会保存在服务端.此时s ...

  9. 使用nginx做负载均衡的session共享问题

    查了一些资料,看了一些别人写的文档,总结如下,实现nginx session的共享PHP服务器有多台,用nginx做负载均衡,这样同一个IP访问同一个页面会被分配到不同的服务器上,如果session不 ...

随机推荐

  1. mvc5 @RenderSection("scripts", required: false) 什么意思

    在模板中 相当于占位符 使用方法如下 @section scripts{ //coding }

  2. C#编程使用Managed Wifi API连接无线SSID

    C#编程使用Managed Wifi API连接无线SSIDhttp://www.2cto.com/kf/201307/227623.html Managed Wifi API - Homehttp: ...

  3. ExtJs之 Ext.JSON

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  4. Windows 7,64位机器上安装DB2 7.2+FP7

    1.要想在Windows 7,64位机器上安装DB2 7.2+FP7,注意:1)拷贝所有安装文件到本地2)设置setup.exe文件兼容windows 20003)使得users用户勾选“完全控制”权 ...

  5. uva 12589 - Learning Vector

    思路: 容易知道加向量的顺序是按向量斜率的大小顺序来的.由于数据不是很大,可以用背包解决!! dp[i][j]:加入最大面积为i时,加入了j个向量. 代码如下: #include<iostrea ...

  6. 几个经常用到的字符串的截取(java)

    几个经常用到的字符串的截取 string str="123abc456";int i=3;1 取字符串的前i个字符   str=str.Substring(0,i); // or  ...

  7. lintcode :最近公共祖先

    题目 最近公共祖先 给定一棵二叉树,找到两个节点的最近公共父节点(LCA). 最近公共祖先是两个节点的公共的祖先节点且具有最大深度. 样例 对于下面这棵二叉树 4 / \ 3 7 / \ 5 6 LC ...

  8. BeanUtils.copyProperties与PropertyUtils.copyProperties用法及区别

    一.简介: BeanUtils提供对Java反射和自省API的包装.其主要目的是利用反射机制对JavaBean的属性进行处理.我们知道,一个JavaBean 通常包含了大量的属性,很多情况下,对Jav ...

  9. React组件生命周期-正确执行初始化阶段的函数

    一. 二.代码 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&quo ...

  10. Android 等比例缩放图片

    // 缩放图片 public static Bitmap zoomImg(String img, int newWidth ,int newHeight){ // 图片源 Bitmap bm = Bi ...