PageRenderTime 56ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/vendor/symfony/lib/storage/sfCacheSessionStorage.class.php

https://github.com/openpne/OpenPNE3
PHP | 290 lines | 165 code | 34 blank | 91 comment | 18 complexity | ae56002a05bb4cc09be5c22f0d9acee6 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * sfCacheSessionStorage manages session storage via a signed cookie and cache backend.
  4. *
  5. * This class stores the session data in via sfCache instance and with an id issued in a
  6. * signed cookie. Useful when you don't want to store the session.
  7. *
  8. * @package symfony
  9. * @subpackage storage
  10. * @author Dustin Whittle <dustin.whittle@symfony-project.com>
  11. */
  12. class sfCacheSessionStorage extends sfStorage
  13. {
  14. protected
  15. $id = null,
  16. $context = null,
  17. $dispatcher = null,
  18. $request = null,
  19. $response = null,
  20. $cache = null,
  21. $data = array(),
  22. $dataChanged = false;
  23. /**
  24. * Initialize this Storage.
  25. *
  26. * @param array $options An associative array of initialization parameters.
  27. * session_name [required] name of session to use
  28. * session_cookie_path [required] cookie path
  29. * session_cookie_domain [required] cookie domain
  30. * session_cookie_lifetime [required] liftime of cookie
  31. * session_cookie_secure [required] send only if secure connection
  32. * session_cookie_http_only [required] accessible only via http protocol
  33. *
  34. * @return bool true, when initialization completes successfully.
  35. *
  36. * @throws <b>sfInitializationException</b> If an error occurs while initializing this Storage.
  37. */
  38. public function initialize($options = array())
  39. {
  40. // initialize parent
  41. // bc with a slightly different name formerly used here, let's be
  42. // compatible with the base class name for it from here on out
  43. if (isset($options['session_cookie_http_only']))
  44. {
  45. $options['session_cookie_httponly'] = $options['session_cookie_http_only'];
  46. }
  47. parent::initialize(array_merge(array('session_name' => 'sfproject',
  48. 'session_cookie_lifetime' => '+30 days',
  49. 'session_cookie_path' => '/',
  50. 'session_cookie_domain' => null,
  51. 'session_cookie_secure' => false,
  52. 'session_cookie_httponly' => true,
  53. 'session_cookie_secret' => 'sf$ecret'), $options));
  54. // create cache instance
  55. if (isset($this->options['cache']) && $this->options['cache']['class'])
  56. {
  57. $this->cache = new $this->options['cache']['class'](is_array($this->options['cache']['param']) ? $this->options['cache']['param'] : array());
  58. }
  59. else
  60. {
  61. throw new InvalidArgumentException('sfCacheSessionStorage requires cache option.');
  62. }
  63. $this->context = sfContext::getInstance();
  64. $this->dispatcher = $this->context->getEventDispatcher();
  65. $this->request = $this->context->getRequest();
  66. $this->response = $this->context->getResponse();
  67. $cookie = $this->request->getCookie($this->options['session_name']);
  68. if(strpos($cookie, ':') !== false)
  69. {
  70. // split cookie data id:signature(id+secret)
  71. list($id, $signature) = explode(':', $cookie, 2);
  72. if($signature == sha1($id.':'.$this->options['session_cookie_secret']))
  73. {
  74. // cookie is valid
  75. $this->id = $id;
  76. }
  77. else
  78. {
  79. // cookie signature broken
  80. $this->id = null;
  81. }
  82. }
  83. else
  84. {
  85. // cookie format wrong
  86. $this->id = null;
  87. }
  88. if(empty($this->id))
  89. {
  90. $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'localhost';
  91. $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'ua';
  92. // generate new id based on random # / ip / user agent / secret
  93. $this->id = md5(mt_rand(0, 999999).$ip.$ua.$this->options['session_cookie_secret']);
  94. if(sfConfig::get('sf_logging_enabled'))
  95. {
  96. $this->dispatcher->notify(new sfEvent($this, 'application.log', array('New session created')));
  97. }
  98. // only send cookie when id is issued
  99. $this->response->setCookie($this->options['session_name'],
  100. $this->id.':'.sha1($this->id.':'.$this->options['session_cookie_secret']),
  101. $this->options['session_cookie_lifetime'],
  102. $this->options['session_cookie_path'],
  103. $this->options['session_cookie_domain'],
  104. $this->options['session_cookie_secure'],
  105. $this->options['session_cookie_httponly']);
  106. $this->data = array();
  107. }
  108. else
  109. {
  110. // load data from cache. Watch out for the default case. We could
  111. // serialize(array()) as the default to the call but that would be a performance hit
  112. $raw = $this->cache->get($this->id, null);
  113. if (null === $raw)
  114. {
  115. $this->data = array();
  116. }
  117. else
  118. {
  119. $data = @unserialize($raw);
  120. // We test 'b:0' special case, because such a string would result
  121. // in $data being === false, while raw is serialized
  122. // see http://stackoverflow.com/questions/1369936/check-to-see-if-a-string-is-serialized
  123. if ( $raw === 'b:0;' || $data !== false)
  124. {
  125. $this->data = $data;
  126. }
  127. else
  128. {
  129. // Probably an old cached value (BC)
  130. $this->data = $raw;
  131. }
  132. }
  133. if(sfConfig::get('sf_logging_enabled'))
  134. {
  135. $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Restored previous session')));
  136. }
  137. }
  138. session_id($this->id);
  139. $this->response->addCacheControlHttpHeader('private');
  140. return true;
  141. }
  142. /**
  143. * Write data to this storage.
  144. *
  145. * The preferred format for a key is directory style so naming conflicts can be avoided.
  146. *
  147. * @param string $key A unique key identifying your data.
  148. * @param mixed $data Data associated with your key.
  149. *
  150. * @return void
  151. */
  152. public function write($key, $data)
  153. {
  154. $this->dataChanged = true;
  155. $this->data[$key] =& $data;
  156. }
  157. /**
  158. * Read data from this storage.
  159. *
  160. * The preferred format for a key is directory style so naming conflicts can be avoided.
  161. *
  162. * @param string $key A unique key identifying your data.
  163. *
  164. * @return mixed Data associated with the key.
  165. */
  166. public function read($key)
  167. {
  168. $retval = null;
  169. if (isset($this->data[$key]))
  170. {
  171. $retval =& $this->data[$key];
  172. }
  173. return $retval;
  174. }
  175. /**
  176. * Remove data from this storage.
  177. *
  178. * The preferred format for a key is directory style so naming conflicts can be avoided.
  179. *
  180. * @param string $key A unique key identifying your data.
  181. *
  182. * @return mixed Data associated with the key.
  183. */
  184. public function remove($key)
  185. {
  186. $retval = null;
  187. if (isset($this->data[$key]))
  188. {
  189. $this->dataChanged = true;
  190. $retval =& $this->data[$key];
  191. unset($this->data[$key]);
  192. }
  193. return $retval;
  194. }
  195. /**
  196. * Regenerates id that represents this storage.
  197. *
  198. * @param boolean $destroy Destroy session when regenerating?
  199. *
  200. * @return boolean True if session regenerated, false if error
  201. *
  202. * @throws <b>sfStorageException</b> If an error occurs while regenerating this storage
  203. */
  204. public function regenerate($destroy = false)
  205. {
  206. if($destroy)
  207. {
  208. $this->data = array();
  209. $this->cache->remove($this->id);
  210. }
  211. // generate session id
  212. $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'ua';
  213. $this->id = md5(mt_rand(0, 999999).$_SERVER['REMOTE_ADDR'].$ua.$this->options['session_cookie_secret']);
  214. // save data to cache
  215. $this->cache->set($this->id, serialize($this->data));
  216. // update session id in signed cookie
  217. $this->response->setCookie($this->options['session_name'],
  218. $this->id.':'.sha1($this->id.':'.$this->options['session_cookie_secret']),
  219. $this->options['session_cookie_lifetime'],
  220. $this->options['session_cookie_path'],
  221. $this->options['session_cookie_domain'],
  222. $this->options['session_cookie_secure'],
  223. $this->options['session_cookie_httponly']);
  224. session_id($this->id);
  225. return true;
  226. }
  227. /**
  228. * Expires the session storage instance.
  229. */
  230. public function expire()
  231. {
  232. // destroy data and regenerate id
  233. $this->regenerate(true);
  234. if(sfConfig::get('sf_logging_enabled'))
  235. {
  236. $this->dispatcher->notify(new sfEvent($this, 'application.log', array('new session created due to expiraton')));
  237. }
  238. }
  239. /**
  240. * Executes the shutdown procedure.
  241. *
  242. * @throws <b>sfStorageException</b> If an error occurs while shutting down this storage
  243. */
  244. public function shutdown()
  245. {
  246. // only update cache if session has changed
  247. if($this->dataChanged === true)
  248. {
  249. $this->cache->set($this->id, serialize($this->data));
  250. if(sfConfig::get('sf_logging_enabled'))
  251. {
  252. $this->dispatcher->notify(new sfEvent($this, 'application.log', array('Storing session to cache')));
  253. }
  254. }
  255. }
  256. }