Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
session_handler_memcache.inc
1 <?php
18 require_once SQ_CORE_PACKAGE_PATH.'/system/session_handling/session_handler/session_handler.inc';
19 
20 
35 {
36 
37 
42  function __construct()
43  {
44  parent::__construct();
45 
46  }//end constructor
47 
48 
60  public static function init()
61  {
62  $host_str = self::getHostString();
63 
64  // Calculate the domain and path for the session cookie.
65  $domain = strip_url(sq_web_path('root_url'), TRUE);
66  $pos = strpos($domain, '/');
67  $path = '/';
68  if ($pos !== FALSE) {
69  $path = substr($domain, $pos);
70  $domain = substr($domain, 0, $pos);
71  }
72 
73  // Remove the port number from the host part, if any.
74  // Session cookies cannot have a port in the domain.
75  $domain = preg_replace('|:\d+$|', '', $domain);
76 
77  $secure = FALSE;
78  if (current_protocol() === 'https' && (defined('SQ_CONF_COOKIE_OPTION_SECURE') && SQ_CONF_COOKIE_OPTION_SECURE)) $secure = TRUE;
79 
80  $http_only = FALSE;
81  $php_version_suits = (version_compare(PHP_VERSION, '5.2.0') >= 0);
82  if ($php_version_suits && (defined('SQ_CONF_COOKIE_OPTION_HTTP_ONLY') && SQ_CONF_COOKIE_OPTION_HTTP_ONLY)) $http_only = TRUE;
83  // Now, set to the 'memcache' module and set the
84  // appropriate save path (ie. the connection string to thee
85  // memcached server).
86  session_name('SQ_SYSTEM_SESSION');
87  if ($php_version_suits) {
88  session_set_cookie_params(0, $path, $domain, $secure, $http_only);
89  } else {
90  session_set_cookie_params(0, $path, $domain, $secure);
91  }
92  session_module_name('memcache');
93 
94  session_save_path($host_str);
95 
96  }//end init()
97 
98 
111  function unserialiseSession($session_id)
112  {
113  $host_str = self::getHostString();
114  $memcache = new Memcache();
115  $memcache->addServer($host_str);
116  $session_str = $memcache->get($session_id);
117 
118  if ($session_str === FALSE) {
119  throw new Exception('Passed primary session does not exist on Memcache server');
120  }
121 
122  // break the session at the word boundaries and the pipes
123  $parts = preg_split('/\w+\|/', $session_str, -1, PREG_SPLIT_OFFSET_CAPTURE);
124  $session_arr = Array();
125 
126  for ($i = 0; $i < count($parts); $i++) {
127  if ($i == count($parts) - 1) continue;
128  $offset = $parts[$i][1] + strlen($parts[$i][0]);
129  $len = $parts[$i + 1][1] - 1 - $offset;
130 
131  $key = substr($session_str, $offset, $len);
132  $session_arr[$key] = unserialize($parts[$i + 1][0]);
133  }
134  return $session_arr;
135 
136  }//end unserialiseSession()
137 
138 
149  function serialiseSession($session_id, $session_contents)
150  {
151  $host_str = self::getHostString();
152  $memcache = new Memcache();
153  $memcache->addServer($host_str);
154 
155  if (!is_array($session_contents)) {
156  trigger_localised_error('CORE0004', E_USER_WARNING, gettype($session_contents));
157  return FALSE;
158  }
159 
160  $session_str = '';
161  foreach ($session_contents as $key => $val) {
162  $session_str .= $key.'|'.serialize($val);
163  }
164 
165  $result = $memcache->set($session_id, $session_str);
166 
167  if ($result === FALSE) {
168  throw new Exception('Unable to update session\'s contents into Memcache');
169  }
170 
171  return TRUE;
172 
173  }//end serialiseSession()
174 
175 
183  public static function sessionExists($session_id)
184  {
185  $host_str = self::getHostString();
186  $memcache = new Memcache();
187  $memcache->addServer($host_str);
188  $return = $memcache->get($session_id);
189  return ($return !== FALSE);
190 
191  }//end sessionExists()
192 
193 
206  public static function syncSession($primary_session_id)
207  {
208  $host_str = self::getHostString();
209  $memcache = new Memcache();
210  $memcache->addServer($host_str);
211 
212  $pri_sess = self::unserialiseSession($primary_session_id);
213 
214  $pri_timestamp = array_get_index($pri_sess, 'SQ_SESSION_TIMESTAMP', -1);
215  $sec_timestamp = array_get_index($_SESSION, 'SQ_SESSION_TIMESTAMP', -1);
216  $pri_login_key = array_get_index($pri_sess, 'SQ_LOGIN_KEY', NULL);
217  $sec_login_key = array_get_index($_SESSION, 'SQ_LOGIN_KEY', NULL);
218 
219  // if primary is younger
220  if ($pri_timestamp > $sec_timestamp || $pri_timestamp == -1) {
221  // copy primary to secondary
222  $_SESSION = $pri_sess;
223  } else {
224  // copy secondary to primary
225  $pri_sess = $_SESSION;
226  }
227 
228  $now = time();
229  $pri_sess['SQ_SESSION_TIMESTAMP'] = $now;
230  $_SESSION['SQ_SESSION_TIMESTAMP'] = $now;
231 
232  // preserve login keys
233  if (!is_null($pri_login_key)) {
234  $pri_sess['SQ_LOGIN_KEY'] = $pri_login_key;
235  }
236  if (!is_null($sec_login_key)) {
237  $_SESSION['SQ_LOGIN_KEY'] = $sec_login_key;
238  }
239 
240  // save the sessionid of the primary so that we
241  // know that we have run this script before. We won't have to
242  // do anther browser refresh if we know this.
243  $_SESSION['PRIMARY_SESSIONID'] = $primary_session_id;
244  $pri_sess['PRIMARY_SESSIONID'] = $primary_session_id;
245 
246  self::serialiseSession($primary_session_id, $pri_sess);
247 
248  return TRUE;
249 
250  }//end syncSession()
251 
252 
253  public static function getHostString()
254  {
255  assert_true(extension_loaded('memcache'), 'Cannot use Memcache Session Handler; it requires the memcache PECL extension installed within PHP, which is not installed');
256  assert_true(file_exists(SQ_DATA_PATH.'/private/conf/memcache.inc'), 'Cannot use Memcache Session Handler; the Memcache configuration file is not set');
257 
258  $memcache_conf = require(SQ_DATA_PATH.'/private/conf/memcache.inc');
259  $hosts =& $memcache_conf['hosts'];
260  $services =& $memcache_conf['services'];
261 
262  assert_true(count($hosts) > 0, 'Cannot use Memcache Session Handler; no hosts are defined in the Memcache configuration file');
263  assert_true(array_key_exists('session_handling', $services) === TRUE, 'Cannot use Memcache Session Handler; no Memcache hosts are assigned to session handling');
264  assert_true(count($services['session_handling']) > 0, 'Cannot use Memcache Session Handler; no Memcache hosts are assigned to session handling');
265 
266  // Convert the host array (or the ones to be used for sessions) to the
267  // URL format expected by the session handler, which requires options to
268  // be specified by GET variables.
269  $host_str = Array();
270  foreach ($services['session_handling'] as $host_key => $weight) {
271  assert_true(array_key_exists($host_key, $hosts) === TRUE, 'Cannot use Memcache Session Handler; host key "'.$host_key.'" assigned for use in session handling but not defined as a host');
272  $this_host = $hosts[$host_key];
273  $this_host_str = 'tcp://'.$this_host['host'].':'.$this_host['port'];
274 
275  $query_str = Array();
276  $query_str[] = 'weight='.rawurlencode($weight);
277 
278  if (array_key_exists('persistent', $this_host) === TRUE) {
279  $query_str[] = 'persistent='.rawurlencode($this_host['persistent'] ? '1' : '0');
280  }
281  if (array_key_exists('timeout', $this_host) === TRUE) {
282  $query_str[] = 'timeout='.rawurlencode($this_host['timeout']);
283  }
284  if (array_key_exists('retry_interval', $this_host) === TRUE) {
285  $query_str[] = 'retry_interval='.rawurlencode($this_host['retry_interval']);
286  }
287  if (array_key_exists('status', $this_host) === TRUE) {
288  $query_str[] = 'status='.rawurlencode($this_host['status'] ? '1' : '0');
289  }
290  $host_str[] = $this_host_str.'?'.implode('&', $query_str);
291  }
292  $host_str = implode(', ', $host_str);
293  return $host_str;
294  }
295 }//end class
296 
297 
298 ?>