PageRenderTime 36ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/session/file.php

https://github.com/mjphaynes/core
PHP | 355 lines | 182 code | 64 blank | 109 comment | 26 complexity | b2908258b60f8a5cbc95dd6838acf1e1 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 Fuel\Core\Session_File
  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. return $this;
  51. }
  52. // --------------------------------------------------------------------
  53. /**
  54. * read the session
  55. *
  56. * @access public
  57. * @param boolean, set to true if we want to force a new session to be created
  58. * @return Fuel\Core\Session_Driver
  59. */
  60. public function read($force = false)
  61. {
  62. // get the session cookie
  63. $cookie = $this->_get_cookie();
  64. // if no session cookie was present, create it
  65. if ($cookie === false or $force)
  66. {
  67. $this->create();
  68. }
  69. // read the session file
  70. $payload = $this->_read_file($this->keys['session_id']);
  71. if ($payload === false)
  72. {
  73. // try to find the previous one
  74. $payload = $this->_read_file($this->keys['previous_id']);
  75. if ($payload === false)
  76. {
  77. // cookie present, but session record missing. force creation of a new session
  78. $this->read(true);
  79. return;
  80. }
  81. }
  82. // unpack the payload
  83. $payload = $this->_unserialize($payload);
  84. // session referral?
  85. if (isset($payload['rotated_session_id']))
  86. {
  87. $payload = $this->_read_file($payload['rotated_session_id']);
  88. if ($payload === false)
  89. {
  90. // cookie present, but session record missing. force creation of a new session
  91. $this->read(true);
  92. return;
  93. }
  94. else
  95. {
  96. // update the session
  97. $this->keys['previous_id'] = $this->keys['session_id'];
  98. $this->keys['session_id'] = $payload['rotated_session_id'];
  99. // unpack the payload
  100. $payload = $this->_unserialize($payload);
  101. }
  102. }
  103. if (isset($payload[0])) $this->data = $payload[0];
  104. if (isset($payload[1])) $this->flash = $payload[1];
  105. parent::read();
  106. }
  107. // --------------------------------------------------------------------
  108. /**
  109. * write the session
  110. *
  111. * @access public
  112. * @return Fuel\Core\Session_File
  113. */
  114. public function write()
  115. {
  116. // do we have something to write?
  117. if ( ! empty($this->keys))
  118. {
  119. parent::write();
  120. // rotate the session id if needed
  121. $this->rotate(false);
  122. // session payload
  123. $payload = $this->_serialize(array($this->data, $this->flash));
  124. // create the session file
  125. $this->_write_file($this->keys['session_id'], $payload);
  126. // was the session id rotated?
  127. if ( isset($this->keys['previous_id']) and $this->keys['previous_id'] != $this->keys['session_id'])
  128. {
  129. // point the old session file to the new one, we don't want to lose the session
  130. $payload = $this->_serialize(array('rotated_session_id' => $this->keys['session_id']));
  131. $this->_write_file($this->keys['previous_id'], $payload);
  132. }
  133. $this->_set_cookie();
  134. // do some garbage collection
  135. if (mt_rand(0,100) < $this->config['gc_probability'])
  136. {
  137. if ($handle = opendir($this->config['path']))
  138. {
  139. $expire = $this->time->get_timestamp() - $this->config['expiration_time'];
  140. while (($file = readdir($handle)) !== false)
  141. {
  142. if (filetype($this->config['path'] . $file) == 'file' and
  143. strpos($file, $this->config['cookie_name'].'_') === 0 and
  144. filemtime($this->config['path'] . $file) < $expire)
  145. {
  146. @unlink($this->config['path'] . $file);
  147. }
  148. }
  149. closedir($handle);
  150. }
  151. }
  152. }
  153. return $this;
  154. }
  155. // --------------------------------------------------------------------
  156. /**
  157. * destroy the current session
  158. *
  159. * @access public
  160. * @return Fuel\Core\Session_File
  161. */
  162. public function destroy()
  163. {
  164. // do we have something to destroy?
  165. if ( ! empty($this->keys))
  166. {
  167. // delete the session file
  168. $file = $this->config['path'].$this->config['cookie_name'].'_'.$this->keys['session_id'];
  169. if (file_exists($file))
  170. {
  171. unlink($file);
  172. }
  173. }
  174. // reset the stored session data
  175. $this->keys = $this->flash = $this->data = array();
  176. return $this;
  177. }
  178. // --------------------------------------------------------------------
  179. /**
  180. * Writes the session file
  181. *
  182. * @access private
  183. * @return boolean, true if it was an existing session, false if not
  184. */
  185. protected function _write_file($session_id, $payload)
  186. {
  187. // create the session file
  188. $file = $this->config['path'].$this->config['cookie_name'].'_'.$session_id;
  189. $exists = file_exists($file);
  190. $handle = fopen($file,'c');
  191. if ($handle)
  192. {
  193. // wait for a lock
  194. while(!flock($handle, LOCK_EX));
  195. // erase existing contents
  196. ftruncate($handle, 0);
  197. // write the session data
  198. fwrite($handle, $payload);
  199. //release the lock
  200. flock($handle, LOCK_UN);
  201. // close the file
  202. fclose($handle);
  203. }
  204. return $exists;
  205. }
  206. // --------------------------------------------------------------------
  207. /**
  208. * Reads the session file
  209. *
  210. * @access private
  211. * @return mixed, the payload if the file exists, or false if not
  212. */
  213. protected function _read_file($session_id)
  214. {
  215. $payload = false;
  216. $file = $this->config['path'].$this->config['cookie_name'].'_'.$session_id;
  217. if (file_exists($file))
  218. {
  219. $handle = fopen($file,'r');
  220. if ($handle)
  221. {
  222. // wait for a lock
  223. while(!flock($handle, LOCK_EX));
  224. // read the session data
  225. $payload = fread($handle, filesize($file));
  226. //release the lock
  227. flock($handle, LOCK_UN);
  228. // close the file
  229. fclose($handle);
  230. }
  231. }
  232. return $payload;
  233. }
  234. // --------------------------------------------------------------------
  235. /**
  236. * validate a driver config value
  237. *
  238. * @param array array with configuration values
  239. * @access public
  240. * @return array validated and consolidated config
  241. */
  242. public function _validate_config($config)
  243. {
  244. $validated = array();
  245. foreach ($config as $name => $item)
  246. {
  247. // filter out any driver config
  248. if (!is_array($item))
  249. {
  250. switch ($name)
  251. {
  252. case 'cookie_name':
  253. if ( empty($item) OR ! is_string($item))
  254. {
  255. $item = 'fuelfid';
  256. }
  257. break;
  258. case 'path':
  259. // do we have a path?
  260. if ( empty($item) OR ! is_dir($item))
  261. {
  262. throw new \Fuel_Exception('You have specify a valid path to store the session data files.');
  263. }
  264. // and can we write to it?
  265. if ( ! is_writable($item))
  266. {
  267. throw new \Fuel_Exception('The webserver doesn\'t have write access to the path to store the session data files.');
  268. }
  269. // update the path, and add the trailing slash
  270. $item = realpath($item).'/';
  271. break;
  272. case 'gc_probability':
  273. // do we have a path?
  274. if ( ! is_numeric($item) OR $item < 0 OR $item > 100)
  275. {
  276. // default value: 5%
  277. $item = 5;
  278. }
  279. break;
  280. default:
  281. // no config item for this driver
  282. break;
  283. }
  284. // global config, was validated in the driver
  285. $validated[$name] = $item;
  286. }
  287. }
  288. // validate all global settings as well
  289. return parent::_validate_config($validated);
  290. }
  291. }