redis.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.5
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2013 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. // --------------------------------------------------------------------
  14. class Session_Redis extends \Session_Driver
  15. {
  16. /**
  17. * array of driver config defaults
  18. */
  19. protected static $_defaults = array(
  20. 'cookie_name' => 'fuelrid', // name of the session cookie for redis based sessions
  21. 'database' => 'default' // name of the redis database to use (as configured in config/db.php)
  22. );
  23. /*
  24. * @var storage for the redis object
  25. */
  26. protected $redis = false;
  27. // --------------------------------------------------------------------
  28. public function __construct($config = array())
  29. {
  30. // merge the driver config with the global config
  31. $this->config = array_merge($config, is_array($config['redis']) ? $config['redis'] : static::$_defaults);
  32. $this->config = $this->_validate_config($this->config);
  33. }
  34. // --------------------------------------------------------------------
  35. /**
  36. * driver initialisation
  37. *
  38. * @access public
  39. * @return void
  40. */
  41. public function init()
  42. {
  43. // generic driver initialisation
  44. parent::init();
  45. if ($this->redis === false)
  46. {
  47. // get the redis database instance
  48. $this->redis = \Redis::instance($this->config['database']);
  49. }
  50. }
  51. // --------------------------------------------------------------------
  52. /**
  53. * create a new session
  54. *
  55. * @access public
  56. * @return Fuel\Core\Session_Redis
  57. */
  58. public function create()
  59. {
  60. // create a new session
  61. $this->keys['session_id'] = $this->_new_session_id();
  62. $this->keys['previous_id'] = $this->keys['session_id']; // prevents errors if previous_id has a unique index
  63. $this->keys['ip_hash'] = md5(\Input::ip().\Input::real_ip());
  64. $this->keys['user_agent'] = \Input::user_agent();
  65. $this->keys['created'] = $this->time->get_timestamp();
  66. $this->keys['updated'] = $this->keys['created'];
  67. return $this;
  68. }
  69. // --------------------------------------------------------------------
  70. /**
  71. * read the session
  72. *
  73. * @access public
  74. * @param boolean, set to true if we want to force a new session to be created
  75. * @return Fuel\Core\Session_Driver
  76. */
  77. public function read($force = false)
  78. {
  79. // initialize the session
  80. $this->data = array();
  81. $this->keys = array();
  82. $this->flash = array();
  83. // get the session cookie
  84. $cookie = $this->_get_cookie();
  85. // if a cookie was present, find the session record
  86. if ($cookie and ! $force and isset($cookie[0]))
  87. {
  88. // read the session file
  89. $payload = $this->_read_redis($cookie[0]);
  90. if ($payload === false)
  91. {
  92. // cookie present, but session record missing. force creation of a new session
  93. return $this->read(true);
  94. }
  95. // unpack the payload
  96. $payload = $this->_unserialize($payload);
  97. // session referral?
  98. if (isset($payload['rotated_session_id']))
  99. {
  100. $payload = $this->_read_redis($payload['rotated_session_id']);
  101. if ($payload === false)
  102. {
  103. // cookie present, but session record missing. force creation of a new session
  104. return $this->read(true);
  105. }
  106. else
  107. {
  108. // update the session
  109. $this->keys['previous_id'] = $this->keys['session_id'];
  110. $this->keys['session_id'] = $payload['rotated_session_id'];
  111. // unpack the payload
  112. $payload = $this->_unserialize($payload);
  113. }
  114. }
  115. if ( ! isset($payload[0]) or ! is_array($payload[0]))
  116. {
  117. // not a valid cookie payload
  118. }
  119. elseif ($payload[0]['updated'] + $this->config['expiration_time'] <= $this->time->get_timestamp())
  120. {
  121. // session has expired
  122. }
  123. elseif ($this->config['match_ip'] and $payload[0]['ip_hash'] !== md5(\Input::ip().\Input::real_ip()))
  124. {
  125. // IP address doesn't match
  126. }
  127. elseif ($this->config['match_ua'] and $payload[0]['user_agent'] !== \Input::user_agent())
  128. {
  129. // user agent doesn't match
  130. }
  131. else
  132. {
  133. // session is valid, retrieve the rest of the payload
  134. if (isset($payload[0]) and is_array($payload[0])) $this->keys = $payload[0];
  135. if (isset($payload[1]) and is_array($payload[1])) $this->data = $payload[1];
  136. if (isset($payload[2]) and is_array($payload[2])) $this->flash = $payload[2];
  137. }
  138. }
  139. return parent::read();
  140. }
  141. // --------------------------------------------------------------------
  142. /**
  143. * write the session
  144. *
  145. * @access public
  146. * @return Fuel\Core\Session_Redis
  147. */
  148. public function write()
  149. {
  150. // do we have something to write?
  151. if ( ! empty($this->keys) or ! empty($this->data) or ! empty($this->flash))
  152. {
  153. parent::write();
  154. // rotate the session id if needed
  155. $this->rotate(false);
  156. // session payload
  157. $payload = $this->_serialize(array($this->keys, $this->data, $this->flash));
  158. // create the session file
  159. $this->_write_redis($this->keys['session_id'], $payload);
  160. // was the session id rotated?
  161. if ( isset($this->keys['previous_id']) and $this->keys['previous_id'] != $this->keys['session_id'])
  162. {
  163. // point the old session file to the new one, we don't want to lose the session
  164. $payload = $this->_serialize(array('rotated_session_id' => $this->keys['session_id']));
  165. $this->_write_redis($this->keys['previous_id'], $payload);
  166. }
  167. $this->_set_cookie(array($this->keys['session_id']));
  168. }
  169. return $this;
  170. }
  171. // --------------------------------------------------------------------
  172. /**
  173. * destroy the current session
  174. *
  175. * @access public
  176. * @return Fuel\Core\Session_Redis
  177. */
  178. public function destroy()
  179. {
  180. // do we have something to destroy?
  181. if ( ! empty($this->keys))
  182. {
  183. // delete the key from the redis server
  184. $this->redis->del($this->keys['session_id']);
  185. }
  186. parent::destroy();
  187. return $this;
  188. }
  189. // --------------------------------------------------------------------
  190. /**
  191. * Writes the redis entry
  192. *
  193. * @access private
  194. * @return boolean, true if it was an existing session, false if not
  195. */
  196. protected function _write_redis($session_id, $payload)
  197. {
  198. // write it to the redis server
  199. $this->redis->set($session_id, $payload);
  200. $this->redis->expire($session_id, $this->config['expiration_time']);
  201. }
  202. // --------------------------------------------------------------------
  203. /**
  204. * Reads the redis entry
  205. *
  206. * @access private
  207. * @return mixed, the payload if the file exists, or false if not
  208. */
  209. protected function _read_redis($session_id)
  210. {
  211. // fetch the session data from the Memcached server
  212. return $this->redis->get($session_id);
  213. }
  214. // --------------------------------------------------------------------
  215. /**
  216. * validate a driver config value
  217. *
  218. * @param array array with configuration values
  219. * @access public
  220. * @return array validated and consolidated config
  221. */
  222. public function _validate_config($config)
  223. {
  224. $validated = array();
  225. foreach ($config as $name => $item)
  226. {
  227. // filter out any driver config
  228. if (!is_array($item))
  229. {
  230. switch ($item)
  231. {
  232. case 'cookie_name':
  233. if ( empty($item) or ! is_string($item))
  234. {
  235. $item = 'fuelrid';
  236. }
  237. break;
  238. case 'database':
  239. // do we have a servers config
  240. if ( empty($item) or ! is_array($item))
  241. {
  242. $item = 'default';
  243. }
  244. break;
  245. default:
  246. break;
  247. }
  248. // global config, was validated in the driver
  249. $validated[$name] = $item;
  250. }
  251. }
  252. // validate all global settings as well
  253. return parent::_validate_config($validated);
  254. }
  255. }