PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/webapp-php/system/libraries/Session.php

https://github.com/AlinT/socorro
PHP | 458 lines | 238 code | 75 blank | 145 comment | 32 complexity | 679bf4fccf2919b7cfe3da7777758d58 MD5 | raw file
  1. <?php defined('SYSPATH') or die('No direct script access.');
  2. /**
  3. * Session library.
  4. *
  5. * $Id: Session.php 3231 2008-07-29 07:30:50Z Geert $
  6. *
  7. * @package Core
  8. * @author Kohana Team
  9. * @copyright (c) 2007-2008 Kohana Team
  10. * @license http://kohanaphp.com/license.html
  11. */
  12. class Session_Core {
  13. // Session singleton
  14. private static $instance;
  15. // Protected key names (cannot be set by the user)
  16. protected static $protect = array('session_id', 'user_agent', 'last_activity', 'ip_address', 'total_hits', '_kf_flash_');
  17. // Configuration and driver
  18. protected static $config;
  19. protected static $driver;
  20. // Flash variables
  21. protected static $flash;
  22. // Input library
  23. protected $input;
  24. /**
  25. * Singleton instance of Session.
  26. */
  27. public static function instance()
  28. {
  29. if (self::$instance == NULL)
  30. {
  31. // Create a new instance
  32. new Session;
  33. }
  34. return self::$instance;
  35. }
  36. /**
  37. * On first session instance creation, sets up the driver and creates session.
  38. */
  39. public function __construct()
  40. {
  41. $this->input = Input::instance();
  42. // This part only needs to be run once
  43. if (self::$instance === NULL)
  44. {
  45. // Load config
  46. self::$config = Kohana::config('session');
  47. // Makes a mirrored array, eg: foo=foo
  48. self::$protect = array_combine(self::$protect, self::$protect);
  49. // Configure garbage collection
  50. ini_set('session.gc_probability', (int) self::$config['gc_probability']);
  51. ini_set('session.gc_divisor', 100);
  52. ini_set('session.gc_maxlifetime', (self::$config['expiration'] == 0) ? 86400 : self::$config['expiration']);
  53. // Create a new session
  54. $this->create();
  55. if (self::$config['regenerate'] > 0 AND ($_SESSION['total_hits'] % self::$config['regenerate']) === 0)
  56. {
  57. // Regenerate session id and update session cookie
  58. $this->regenerate();
  59. }
  60. else
  61. {
  62. // Always update session cookie to keep the session alive
  63. cookie::set(self::$config['name'], $_SESSION['session_id'], self::$config['expiration']);
  64. }
  65. // Close the session just before sending the headers, so that
  66. // the session cookie(s) can be written.
  67. Event::add('system.send_headers', array($this, 'write_close'));
  68. // Make sure that sessions are closed before exiting
  69. register_shutdown_function(array($this, 'write_close'));
  70. // Singleton instance
  71. self::$instance = $this;
  72. }
  73. Kohana::log('debug', 'Session Library initialized');
  74. }
  75. /**
  76. * Get the session id.
  77. *
  78. * @return string
  79. */
  80. public function id()
  81. {
  82. return $_SESSION['session_id'];
  83. }
  84. /**
  85. * Create a new session.
  86. *
  87. * @param array variables to set after creation
  88. * @return void
  89. */
  90. public function create($vars = NULL)
  91. {
  92. // Destroy any current sessions
  93. $this->destroy();
  94. if (self::$config['driver'] !== 'native')
  95. {
  96. // Set driver name
  97. $driver = 'Session_'.ucfirst(self::$config['driver']).'_Driver';
  98. // Load the driver
  99. if ( ! Kohana::auto_load($driver))
  100. throw new Kohana_Exception('core.driver_not_found', self::$config['driver'], get_class($this));
  101. // Initialize the driver
  102. self::$driver = new $driver();
  103. // Validate the driver
  104. if ( ! (self::$driver instanceof Session_Driver))
  105. throw new Kohana_Exception('core.driver_implements', self::$config['driver'], get_class($this), 'Session_Driver');
  106. // Register non-native driver as the session handler
  107. session_set_save_handler
  108. (
  109. array(self::$driver, 'open'),
  110. array(self::$driver, 'close'),
  111. array(self::$driver, 'read'),
  112. array(self::$driver, 'write'),
  113. array(self::$driver, 'destroy'),
  114. array(self::$driver, 'gc')
  115. );
  116. }
  117. // Validate the session name
  118. if ( ! preg_match('~^(?=.*[a-z])[a-z0-9_]++$~iD', self::$config['name']))
  119. throw new Kohana_Exception('session.invalid_session_name', self::$config['name']);
  120. // Name the session, this will also be the name of the cookie
  121. session_name(self::$config['name']);
  122. // Set the session cookie parameters
  123. session_set_cookie_params
  124. (
  125. self::$config['expiration'],
  126. Kohana::config('cookie.path'),
  127. Kohana::config('cookie.domain'),
  128. Kohana::config('cookie.secure'),
  129. Kohana::config('cookie.httponly')
  130. );
  131. // Start the session!
  132. session_start();
  133. // Put session_id in the session variable
  134. $_SESSION['session_id'] = session_id();
  135. // Set defaults
  136. if ( ! isset($_SESSION['_kf_flash_']))
  137. {
  138. $_SESSION['total_hits'] = 0;
  139. $_SESSION['_kf_flash_'] = array();
  140. $_SESSION['user_agent'] = Kohana::$user_agent;
  141. $_SESSION['ip_address'] = $this->input->ip_address();
  142. }
  143. // Set up flash variables
  144. self::$flash =& $_SESSION['_kf_flash_'];
  145. // Increase total hits
  146. $_SESSION['total_hits'] += 1;
  147. // Validate data only on hits after one
  148. if ($_SESSION['total_hits'] > 1)
  149. {
  150. // Validate the session
  151. foreach (self::$config['validate'] as $valid)
  152. {
  153. switch ($valid)
  154. {
  155. // Check user agent for consistency
  156. case 'user_agent':
  157. if ($_SESSION[$valid] !== Kohana::$user_agent)
  158. return $this->create();
  159. break;
  160. // Check ip address for consistency
  161. case 'ip_address':
  162. if ($_SESSION[$valid] !== $this->input->$valid())
  163. return $this->create();
  164. break;
  165. // Check expiration time to prevent users from manually modifying it
  166. case 'expiration':
  167. if (time() - $_SESSION['last_activity'] > ini_get('session.gc_maxlifetime'))
  168. return $this->create();
  169. break;
  170. }
  171. }
  172. // Expire flash keys
  173. $this->expire_flash();
  174. }
  175. // Update last activity
  176. $_SESSION['last_activity'] = time();
  177. // Set the new data
  178. self::set($vars);
  179. }
  180. /**
  181. * Regenerates the global session id.
  182. *
  183. * @return void
  184. */
  185. public function regenerate()
  186. {
  187. if (self::$config['driver'] === 'native')
  188. {
  189. // Generate a new session id
  190. // Note: also sets a new session cookie with the updated id
  191. session_regenerate_id(TRUE);
  192. // Update session with new id
  193. $_SESSION['session_id'] = session_id();
  194. }
  195. else
  196. {
  197. // Pass the regenerating off to the driver in case it wants to do anything special
  198. $_SESSION['session_id'] = self::$driver->regenerate();
  199. }
  200. // Get the session name
  201. $name = session_name();
  202. if (isset($_COOKIE[$name]))
  203. {
  204. // Change the cookie value to match the new session id to prevent "lag"
  205. $_COOKIE[$name] = $_SESSION['session_id'];
  206. }
  207. }
  208. /**
  209. * Destroys the current session.
  210. *
  211. * @return void
  212. */
  213. public function destroy()
  214. {
  215. if (session_id() !== '')
  216. {
  217. // Get the session name
  218. $name = session_name();
  219. // Destroy the session
  220. session_destroy();
  221. // Re-initialize the array
  222. $_SESSION = array();
  223. // Delete the session cookie
  224. cookie::delete($name);
  225. }
  226. }
  227. /**
  228. * Runs the system.session_write event, then calls session_write_close.
  229. *
  230. * @return void
  231. */
  232. public function write_close()
  233. {
  234. static $run;
  235. if ($run === NULL)
  236. {
  237. $run = TRUE;
  238. // Run the events that depend on the session being open
  239. Event::run('system.session_write');
  240. // Expire flash keys
  241. $this->expire_flash();
  242. // Close the session
  243. session_write_close();
  244. }
  245. }
  246. /**
  247. * Set a session variable.
  248. *
  249. * @param string|array key, or array of values
  250. * @param mixed value (if keys is not an array)
  251. * @return void
  252. */
  253. public function set($keys, $val = FALSE)
  254. {
  255. if (empty($keys))
  256. return FALSE;
  257. if ( ! is_array($keys))
  258. {
  259. $keys = array($keys => $val);
  260. }
  261. foreach ($keys as $key => $val)
  262. {
  263. if (isset(self::$protect[$key]))
  264. continue;
  265. // Set the key
  266. $_SESSION[$key] = $val;
  267. }
  268. }
  269. /**
  270. * Set a flash variable.
  271. *
  272. * @param string|array key, or array of values
  273. * @param mixed value (if keys is not an array)
  274. * @return void
  275. */
  276. public function set_flash($keys, $val = FALSE)
  277. {
  278. if (empty($keys))
  279. return FALSE;
  280. if ( ! is_array($keys))
  281. {
  282. $keys = array($keys => $val);
  283. }
  284. foreach ($keys as $key => $val)
  285. {
  286. if ($key == FALSE)
  287. continue;
  288. self::$flash[$key] = 'new';
  289. self::set($key, $val);
  290. }
  291. }
  292. /**
  293. * Freshen one, multiple or all flash variables.
  294. *
  295. * @param string variable key(s)
  296. * @return void
  297. */
  298. public function keep_flash($keys = NULL)
  299. {
  300. $keys = ($keys === NULL) ? array_keys(self::$flash) : func_get_args();
  301. foreach ($keys as $key)
  302. {
  303. if (isset(self::$flash[$key]))
  304. {
  305. self::$flash[$key] = 'new';
  306. }
  307. }
  308. }
  309. /**
  310. * Expires old flash data and removes it from the session.
  311. *
  312. * @return void
  313. */
  314. public function expire_flash()
  315. {
  316. static $run;
  317. // Method can only be run once
  318. if ($run === TRUE)
  319. return;
  320. if ( ! empty(self::$flash))
  321. {
  322. foreach (self::$flash as $key => $state)
  323. {
  324. if ($state === 'old')
  325. {
  326. // Flash has expired
  327. unset(self::$flash[$key], $_SESSION[$key]);
  328. }
  329. else
  330. {
  331. // Flash will expire
  332. self::$flash[$key] = 'old';
  333. }
  334. }
  335. }
  336. // Method has been run
  337. $run = TRUE;
  338. }
  339. /**
  340. * Get a variable. Access to sub-arrays is supported with key.subkey.
  341. *
  342. * @param string variable key
  343. * @param mixed default value returned if variable does not exist
  344. * @return mixed Variable data if key specified, otherwise array containing all session data.
  345. */
  346. public function get($key = FALSE, $default = FALSE)
  347. {
  348. if (empty($key))
  349. return $_SESSION;
  350. $result = isset($_SESSION[$key]) ? $_SESSION[$key] : Kohana::key_string($_SESSION, $key);
  351. return ($result === NULL) ? $default : $result;
  352. }
  353. /**
  354. * Get a variable, and delete it.
  355. *
  356. * @param string variable key
  357. * @param mixed default value returned if variable does not exist
  358. * @return mixed
  359. */
  360. public function get_once($key, $default = FALSE)
  361. {
  362. $return = self::get($key, $default);
  363. self::delete($key);
  364. return $return;
  365. }
  366. /**
  367. * Delete one or more variables.
  368. *
  369. * @param string variable key(s)
  370. * @return void
  371. */
  372. public function delete($keys)
  373. {
  374. $args = func_get_args();
  375. foreach ($args as $key)
  376. {
  377. if (isset(self::$protect[$key]))
  378. continue;
  379. // Unset the key
  380. unset($_SESSION[$key]);
  381. }
  382. }
  383. } // End Session Class