1<?php 2namespace DALMP\Sessions; 3 4/** 5 * Sessions\Redis 6 * 7 * @author Nicolas Embriz <nbari@dalmp.com> 8 * @package DALMP 9 * @license BSD License 10 * @version 3.0.3 11 */ 12class Redis implements \SessionHandlerInterface 13{ 14 /** 15 * DALMP\Cache\Redis instance 16 * 17 * @access protected 18 * @var DALMP\Cache\Redis 19 */ 20 protected $cache; 21 22 /** 23 * cache_ref_key key used to store the reference on the cache engine 24 * 25 * @access private 26 * @var string 27 */ 28 private $cache_ref_key; 29 30 /** 31 * REF - field used for storing references 32 * 33 * @access private 34 * @var mixed 35 */ 36 private $dalmp_sessions_ref; 37 38 /** 39 * key used for creating more entropy when storing the sessions on a 40 * key/value cache engine, useful when serving multiple sites 41 * 42 * @access private 43 * @var mixed 44 */ 45 private $dalmp_sessions_key; 46 47 /** 48 * constructor 49 * 50 * @param DALMP\Cache\Redis $cache instance 51 * @param string $sessions_ref global variable to be stored as reference 52 */ 53 public function __construct(\DALMP\Cache\Redis $cache, $sessions_ref = 'UID') 54 { 55 $this->cache = $cache; 56 $this->dalmp_sessions_ref = defined('DALMP_SESSIONS_REF') ? DALMP_SESSIONS_REF : $sessions_ref; 57 $this->dalmp_sessions_key = defined('DALMP_SESSIONS_KEY') ? DALMP_SESSIONS_KEY : __FILE__; 58 $this->cache_ref_key = sprintf('DALMP_REF_%s', sha1($this->dalmp_sessions_ref . $this->dalmp_sessions_key)); 59 } 60 61 public function close() 62 { 63 return true; 64 } 65 66 public function destroy($session_id) 67 { 68 $key = sprintf('DALMP_%s', sha1($this->dalmp_sessions_ref . $session_id)); 69 if ($rs = $this->cache->Delete($key)) { 70 71 /** 72 * destroy REF on cache 73 */ 74 if (isset($GLOBALS[$this->dalmp_sessions_ref]) && !empty($GLOBALS[$this->dalmp_sessions_ref])) { 75 $this->cache->X()->HDEL($this->cache_ref_key, $key); 76 $this->cache->X()->EXPIRE($this->cache_ref_key, 3600); 77 } 78 79 return true; 80 } else { 81 return false; 82 } 83 } 84 85 public function gc($maxlifetime) 86 { 87 $refs = $this->cache->X()->HGETALL($this->cache_ref_key); 88 89 $keys = array($this->cache_ref_key); 90 91 if (is_array($refs)) { 92 foreach ($refs as $key => $sref) { 93 $data = explode('|', $sref); 94 if (current($data) < time()) { 95 $keys[] = $key; 96 } 97 } 98 99 if (count($keys) > 1) { 100 $redis = $this->cache->X(); 101 call_user_func_array(array($redis, 'HDEL'), $keys); 102 $this->cache->X()->EXPIRE($this->cache_ref_key, 3600); 103 } 104 } 105 106 return true; 107 } 108 109 public function open($save_path, $name) 110 { 111 return true; 112 } 113 114 public function read($session_id) 115 { 116 $key = sprintf('DALMP_%s', sha1($this->dalmp_sessions_ref . $session_id)); 117 118 return $this->cache->Get($key); 119 } 120 121 public function write($session_id, $session_data) 122 { 123 $ref = (isset($GLOBALS[$this->dalmp_sessions_ref]) && !empty($GLOBALS[$this->dalmp_sessions_ref])) ? $GLOBALS[$this->dalmp_sessions_ref] : null; 124 $timeout = ini_get('session.gc_maxlifetime'); 125 $expiry = time() + $timeout; 126 127 $key = sprintf('DALMP_%s', sha1($this->dalmp_sessions_ref . $session_id)); 128 $rs = (bool) $this->cache->Set($key, $session_data, $timeout); 129 130 /** 131 * store REF on cache 132 */ 133 if ($rs && $ref) { 134 return (bool) ($this->cache->X()->HSET($this->cache_ref_key, $key, sprintf('%s|%s', $ref, $expiry)) ? $this->cache->X()->EXPIRE($this->cache_ref_key, 3600) : false); 135 } else { 136 return $rs; 137 } 138 } 139 140 /** 141 * getSessionsRefs 142 * 143 * @return array of sessions containing any reference 144 */ 145 public function getSessionsRefs() 146 { 147 $refs = $this->cache->X()->HGetALL($this->cache_ref_key); 148 $rs = array(); 149 150 foreach ($refs as $key => $data) { 151 list($reference, $expiry) = explode('|', $data); 152 $rs[$key] = array($reference => $expiry); 153 } 154 155 return $rs; 156 } 157 158 /** 159 * getSessionRef 160 * 161 * @param string $ref 162 * @return array of session containing a specific reference 163 */ 164 public function getSessionRef($ref) 165 { 166 $refs = $this->cache->X()->HGetALL($this->cache_ref_key); 167 $rs = array(); 168 169 foreach ($refs as $key => $data) { 170 list($reference, $expiry) = explode('|', $data); 171 if ($reference == $ref) { 172 $rs[$key] = array($reference => $expiry); 173 } 174 } 175 176 return $rs; 177 } 178 179 /** 180 * delSessionRef - delete sessions containing a specific reference 181 * 182 * @param string $ref 183 * @return boolean 184 */ 185 public function delSessionRef($ref) 186 { 187 $refs = $this->cache->X()->HGETALL($this->cache_ref_key); 188 189 $keys = array($this->cache_ref_key); 190 191 if (is_array($refs)) { 192 foreach ($refs as $key => $data) { 193 list($reference, $expiry) = explode('|', $data); 194 if ($reference == $ref) { 195 $keys[] = $key; 196 } 197 } 198 } 199 200 if (count($keys) > 1) { 201 $redis = $this->cache->X(); 202 call_user_func_array(array($redis, 'HDEL'), $keys); 203 array_shift($keys); 204 205 return (bool) $this->cache->delete($keys); 206 } else { 207 return false; 208 } 209 } 210 211} 212