PageRenderTime 66ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/session/file.php

https://github.com/joshuarubin/fuel_core
PHP | 349 lines | 179 code | 61 blank | 109 comment | 27 complexity | e396d8441cc95418a9dcf73877624bb2 MD5 | raw file
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP5 framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2011 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. // --------------------------------------------------------------------
  14. class Session_File extends \Session_Driver {
  15. /**
  16. * array of driver config defaults
  17. */
  18. protected static $_defaults = array(
  19. 'cookie_name' => 'fuelfid', // name of the session cookie for file based sessions
  20. 'path' => '/tmp', // path where the session files should be stored
  21. 'gc_probability' => 5 // probability % (between 0 and 100) for garbage collection
  22. );
  23. // --------------------------------------------------------------------
  24. public function __construct($config = array())
  25. {
  26. // merge the driver config with the global config
  27. $this->config = array_merge($config, is_array($config['file']) ? $config['file'] : static::$_defaults);
  28. $this->config = $this->_validate_config($this->config);
  29. }
  30. // --------------------------------------------------------------------
  31. /**
  32. * create a new session
  33. *
  34. * @access public
  35. * @return void
  36. */
  37. public function create()
  38. {
  39. // create a new session
  40. $this->keys['session_id'] = $this->_new_session_id();
  41. $this->keys['previous_id'] = $this->keys['session_id']; // prevents errors if previous_id has a unique index
  42. $this->keys['ip_hash'] = md5(\Input::ip().\Input::real_ip());
  43. $this->keys['user_agent'] = \Input::user_agent();
  44. $this->keys['created'] = $this->time->get_timestamp();
  45. $this->keys['updated'] = $this->keys['created'];
  46. // create the session record
  47. $this->_write_file($this->keys['session_id'], serialize(array()));
  48. // and set the session cookie
  49. $this->_set_cookie();
  50. }
  51. // --------------------------------------------------------------------
  52. /**
  53. * read the session
  54. *
  55. * @access public
  56. * @param boolean, set to true if we want to force a new session to be created
  57. * @return void
  58. */
  59. public function read($force = false)
  60. {
  61. // get the session cookie
  62. $cookie = $this->_get_cookie();
  63. // if no session cookie was present, create it
  64. if ($cookie === false or $force)
  65. {
  66. $this->create();
  67. }
  68. // read the session file
  69. $payload = $this->_read_file($this->keys['session_id']);
  70. if ($payload === false)
  71. {
  72. // try to find the previous one
  73. $payload = $this->_read_file($this->keys['previous_id']);
  74. if ($payload === false)
  75. {
  76. // cookie present, but session record missing. force creation of a new session
  77. $this->read(true);
  78. return;
  79. }
  80. }
  81. // unpack the payload
  82. $payload = $this->_unserialize($payload);
  83. // session referral?
  84. if (isset($payload['rotated_session_id']))
  85. {
  86. $payload = $this->_read_file($payload['rotated_session_id']);
  87. if ($payload === false)
  88. {
  89. // cookie present, but session record missing. force creation of a new session
  90. $this->read(true);
  91. return;
  92. }
  93. else
  94. {
  95. // update the session
  96. $this->keys['previous_id'] = $this->keys['session_id'];
  97. $this->keys['session_id'] = $payload['rotated_session_id'];
  98. // unpack the payload
  99. $payload = $this->_unserialize($payload);
  100. }
  101. }
  102. if (isset($payload[0])) $this->data = $payload[0];
  103. if (isset($payload[1])) $this->flash = $payload[1];
  104. parent::read();
  105. }
  106. // --------------------------------------------------------------------
  107. /**
  108. * write the session
  109. *
  110. * @access public
  111. * @return void
  112. */
  113. public function write()
  114. {
  115. // do we have something to write?
  116. if ( ! empty($this->keys))
  117. {
  118. parent::write();
  119. // rotate the session id if needed
  120. $this->rotate(false);
  121. // session payload
  122. $payload = $this->_serialize(array($this->data, $this->flash));
  123. // create the session file
  124. $this->_write_file($this->keys['session_id'], $payload);
  125. // was the session id rotated?
  126. if ( isset($this->keys['previous_id']) && $this->keys['previous_id'] != $this->keys['session_id'])
  127. {
  128. // point the old session file to the new one, we don't want to lose the session
  129. $payload = $this->_serialize(array('rotated_session_id' => $this->keys['session_id']));
  130. $this->_write_file($this->keys['previous_id'], $payload);
  131. }
  132. $this->_set_cookie();
  133. // do some garbage collection
  134. if (mt_rand(0,100) < $this->config['gc_probability'])
  135. {
  136. if ($handle = opendir($this->config['path']))
  137. {
  138. $expire = $this->time->get_timestamp() - $this->config['expiration_time'];
  139. while (($file = readdir($handle)) !== false)
  140. {
  141. if (filetype($this->config['path'] . $file) == 'file' &&
  142. strpos($file, $this->config['cookie_name'].'_') === 0 &&
  143. filemtime($this->config['path'] . $file) < $expire)
  144. {
  145. @unlink($this->config['path'] . $file);
  146. }
  147. }
  148. closedir($handle);
  149. }
  150. }
  151. }
  152. }
  153. // --------------------------------------------------------------------
  154. /**
  155. * destroy the current session
  156. *
  157. * @access public
  158. * @return void
  159. */
  160. public function destroy()
  161. {
  162. // do we have something to destroy?
  163. if ( ! empty($this->keys))
  164. {
  165. // delete the session file
  166. $file = $this->config['path'].$this->config['cookie_name'].'_'.$this->keys['session_id'];
  167. if (file_exists($file))
  168. {
  169. unlink($file);
  170. }
  171. }
  172. // reset the stored session data
  173. $this->keys = $this->flash = $this->data = array();
  174. }
  175. // --------------------------------------------------------------------
  176. /**
  177. * Writes the session file
  178. *
  179. * @access private
  180. * @return boolean, true if it was an existing session, false if not
  181. */
  182. protected function _write_file($session_id, $payload)
  183. {
  184. // create the session file
  185. $file = $this->config['path'].$this->config['cookie_name'].'_'.$session_id;
  186. $exists = file_exists($file);
  187. $handle = fopen($file,'c');
  188. if ($handle)
  189. {
  190. // wait for a lock
  191. while(!flock($handle, LOCK_EX));
  192. // erase existing contents
  193. ftruncate($handle, 0);
  194. // write the session data
  195. fwrite($handle, $payload);
  196. //release the lock
  197. flock($handle, LOCK_UN);
  198. // close the file
  199. fclose($handle);
  200. }
  201. return $exists;
  202. }
  203. // --------------------------------------------------------------------
  204. /**
  205. * Reads the session file
  206. *
  207. * @access private
  208. * @return mixed, the payload if the file exists, or false if not
  209. */
  210. protected function _read_file($session_id)
  211. {
  212. $payload = false;
  213. $file = $this->config['path'].$this->config['cookie_name'].'_'.$session_id;
  214. if (file_exists($file))
  215. {
  216. $handle = fopen($file,'r');
  217. if ($handle)
  218. {
  219. // wait for a lock
  220. while(!flock($handle, LOCK_EX));
  221. // read the session data
  222. $payload = fread($handle, filesize($file));
  223. //release the lock
  224. flock($handle, LOCK_UN);
  225. // close the file
  226. fclose($handle);
  227. }
  228. }
  229. return $payload;
  230. }
  231. // --------------------------------------------------------------------
  232. /**
  233. * validate a driver config value
  234. *
  235. * @param array array with configuration values
  236. * @access public
  237. * @return array validated and consolidated config
  238. */
  239. public function _validate_config($config)
  240. {
  241. $validated = array();
  242. foreach ($config as $name => $item)
  243. {
  244. // filter out any driver config
  245. if (!is_array($item))
  246. {
  247. switch ($name)
  248. {
  249. case 'cookie_name':
  250. if ( empty($item) OR ! is_string($item))
  251. {
  252. $item = 'fuelfid';
  253. }
  254. break;
  255. case 'path':
  256. // do we have a path?
  257. if ( empty($item) OR ! is_dir($item))
  258. {
  259. throw new \Fuel_Exception('You have specify a valid path to store the session data files.');
  260. }
  261. // and can we write to it?
  262. if ( ! is_writable($item))
  263. {
  264. throw new \Fuel_Exception('The webserver doesn\'t have write access to the path to store the session data files.');
  265. }
  266. // update the path, and add the trailing slash
  267. $item = realpath($item).'/';
  268. break;
  269. case 'gc_probability':
  270. // do we have a path?
  271. if ( ! is_numeric($item) OR $item < 0 OR $item > 100)
  272. {
  273. // default value: 5%
  274. $item = 5;
  275. }
  276. break;
  277. default:
  278. // no config item for this driver
  279. break;
  280. }
  281. // global config, was validated in the driver
  282. $validated[$name] = $item;
  283. }
  284. }
  285. // validate all global settings as well
  286. return parent::_validate_config($validated);
  287. }
  288. }