Session.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. <?php
  2. /**
  3. * Base session class.
  4. *
  5. * @package Kohana
  6. * @category Session
  7. * @author Kohana Team
  8. * @copyright (c) Kohana Team
  9. * @license https://koseven.ga/LICENSE.md
  10. */
  11. abstract class Kohana_Session {
  12. /**
  13. * @var string default session adapter
  14. */
  15. public static $default = 'native';
  16. /**
  17. * @var array session instances
  18. */
  19. public static $instances = [];
  20. /**
  21. * Creates a singleton session of the given type. Some session types
  22. * (native, database) also support restarting a session by passing a
  23. * session id as the second parameter.
  24. *
  25. * $session = Session::instance();
  26. *
  27. * [!!] [Session::write] will automatically be called when the request ends.
  28. *
  29. * @param string $type type of session (native, cookie, etc)
  30. * @param string $id session identifier
  31. * @return Session
  32. * @uses Kohana::$config
  33. */
  34. public static function instance($type = NULL, $id = NULL)
  35. {
  36. if ($type === NULL)
  37. {
  38. // Use the default type
  39. $type = Session::$default;
  40. }
  41. if ( ! isset(Session::$instances[$type]))
  42. {
  43. // Load the configuration for this type
  44. $config = Kohana::$config->load('session')->get($type);
  45. // Set the session class name
  46. $class = 'Session_'.ucfirst($type);
  47. // Create a new session instance
  48. Session::$instances[$type] = $session = new $class($config, $id);
  49. // Write the session at shutdown
  50. register_shutdown_function([$session, 'write']);
  51. }
  52. return Session::$instances[$type];
  53. }
  54. /**
  55. * @var string cookie name
  56. */
  57. protected $_name = 'session';
  58. /**
  59. * @var int cookie lifetime
  60. */
  61. protected $_lifetime = 0;
  62. /**
  63. * @var bool encrypt session data?
  64. */
  65. protected $_encrypted = FALSE;
  66. /**
  67. * @var array session data
  68. */
  69. protected $_data = [];
  70. /**
  71. * @var bool session destroyed?
  72. */
  73. protected $_destroyed = FALSE;
  74. /**
  75. * Overloads the name, lifetime, and encrypted session settings.
  76. *
  77. * [!!] Sessions can only be created using the [Session::instance] method.
  78. *
  79. * @param array $config configuration
  80. * @param string $id session id
  81. * @return void
  82. * @uses Session::read
  83. */
  84. public function __construct(array $config = NULL, $id = NULL)
  85. {
  86. if (isset($config['name']))
  87. {
  88. // Cookie name to store the session id in
  89. $this->_name = (string) $config['name'];
  90. }
  91. if (isset($config['lifetime']))
  92. {
  93. // Cookie lifetime
  94. $this->_lifetime = (int) $config['lifetime'];
  95. }
  96. if (isset($config['encrypted']))
  97. {
  98. if ($config['encrypted'] === TRUE)
  99. {
  100. // Use the default Encrypt instance
  101. $config['encrypted'] = 'default';
  102. }
  103. // Enable or disable encryption of data
  104. $this->_encrypted = $config['encrypted'];
  105. }
  106. // Load the session
  107. $this->read($id);
  108. }
  109. /**
  110. * Session object is rendered to a serialized string. If encryption is
  111. * enabled, the session will be encrypted. If not, the output string will
  112. * be encoded.
  113. *
  114. * echo $session;
  115. *
  116. * @return string
  117. * @uses Encrypt::encode
  118. */
  119. public function __toString()
  120. {
  121. // Serialize the data array
  122. $data = $this->_serialize($this->_data);
  123. if ($this->_encrypted)
  124. {
  125. // Encrypt the data using the default key
  126. $data = Encrypt::instance($this->_encrypted)->encode($data);
  127. }
  128. else
  129. {
  130. // Encode the data
  131. $data = $this->_encode($data);
  132. }
  133. return $data;
  134. }
  135. /**
  136. * Returns the current session array. The returned array can also be
  137. * assigned by reference.
  138. *
  139. * // Get a copy of the current session data
  140. * $data = $session->as_array();
  141. *
  142. * // Assign by reference for modification
  143. * $data =& $session->as_array();
  144. *
  145. * @return array
  146. */
  147. public function & as_array()
  148. {
  149. return $this->_data;
  150. }
  151. /**
  152. * Get the current session id, if the session supports it.
  153. *
  154. * $id = $session->id();
  155. *
  156. * [!!] Not all session types have ids.
  157. *
  158. * @return string
  159. * @since 3.0.8
  160. */
  161. public function id()
  162. {
  163. return NULL;
  164. }
  165. /**
  166. * Get the current session cookie name.
  167. *
  168. * $name = $session->name();
  169. *
  170. * @return string
  171. * @since 3.0.8
  172. */
  173. public function name()
  174. {
  175. return $this->_name;
  176. }
  177. /**
  178. * Get a variable from the session array.
  179. *
  180. * $foo = $session->get('foo');
  181. *
  182. * @param string $key variable name
  183. * @param mixed $default default value to return
  184. * @return mixed
  185. */
  186. public function get($key, $default = NULL)
  187. {
  188. return array_key_exists($key, $this->_data) ? $this->_data[$key] : $default;
  189. }
  190. /**
  191. * Get and delete a variable from the session array.
  192. *
  193. * $bar = $session->get_once('bar');
  194. *
  195. * @param string $key variable name
  196. * @param mixed $default default value to return
  197. * @return mixed
  198. */
  199. public function get_once($key, $default = NULL)
  200. {
  201. $value = $this->get($key, $default);
  202. unset($this->_data[$key]);
  203. return $value;
  204. }
  205. /**
  206. * Set a variable in the session array.
  207. *
  208. * $session->set('foo', 'bar');
  209. *
  210. * @param string $key variable name
  211. * @param mixed $value value
  212. * @return $this
  213. */
  214. public function set($key, $value)
  215. {
  216. $this->_data[$key] = $value;
  217. return $this;
  218. }
  219. /**
  220. * Set a variable by reference.
  221. *
  222. * $session->bind('foo', $foo);
  223. *
  224. * @param string $key variable name
  225. * @param mixed $value referenced value
  226. * @return $this
  227. */
  228. public function bind($key, & $value)
  229. {
  230. $this->_data[$key] =& $value;
  231. return $this;
  232. }
  233. /**
  234. * Removes a variable in the session array.
  235. *
  236. * $session->delete('foo');
  237. *
  238. * @param string $key,... variable name
  239. * @return $this
  240. */
  241. public function delete($key)
  242. {
  243. $args = func_get_args();
  244. foreach ($args as $key)
  245. {
  246. unset($this->_data[$key]);
  247. }
  248. return $this;
  249. }
  250. /**
  251. * Loads existing session data.
  252. *
  253. * $session->read();
  254. *
  255. * @param string $id session id
  256. * @return void
  257. */
  258. public function read($id = NULL)
  259. {
  260. $data = NULL;
  261. try
  262. {
  263. if (is_string($data = $this->_read($id)))
  264. {
  265. if ($this->_encrypted)
  266. {
  267. // Decrypt the data using the default key
  268. $data = Encrypt::instance($this->_encrypted)->decode($data);
  269. }
  270. else
  271. {
  272. // Decode the data
  273. $data = $this->_decode($data);
  274. }
  275. // Unserialize the data
  276. $data = $this->_unserialize($data);
  277. }
  278. else
  279. {
  280. // Ignore these, session is valid, likely no data though.
  281. }
  282. }
  283. catch (Exception $e)
  284. {
  285. // Error reading the session, usually a corrupt session.
  286. throw new Session_Exception('Error reading session data.', NULL, Session_Exception::SESSION_CORRUPT);
  287. }
  288. if (is_array($data))
  289. {
  290. // Load the data locally
  291. $this->_data = $data;
  292. }
  293. }
  294. /**
  295. * Generates a new session id and returns it.
  296. *
  297. * $id = $session->regenerate();
  298. *
  299. * @return string
  300. */
  301. public function regenerate()
  302. {
  303. return $this->_regenerate();
  304. }
  305. /**
  306. * Sets the last_active timestamp and saves the session.
  307. *
  308. * $session->write();
  309. *
  310. * [!!] Any errors that occur during session writing will be logged,
  311. * but not displayed, because sessions are written after output has
  312. * been sent.
  313. *
  314. * @return boolean
  315. * @uses Kohana::$log
  316. */
  317. public function write()
  318. {
  319. if (headers_sent() OR $this->_destroyed)
  320. {
  321. // Session cannot be written when the headers are sent or when
  322. // the session has been destroyed
  323. return FALSE;
  324. }
  325. // Set the last active timestamp
  326. $this->_data['last_active'] = time();
  327. try
  328. {
  329. return $this->_write();
  330. }
  331. catch (Exception $e)
  332. {
  333. // Log & ignore all errors when a write fails
  334. Kohana::$log->add(Log::ERROR, Kohana_Exception::text($e))->write();
  335. return FALSE;
  336. }
  337. }
  338. /**
  339. * Completely destroy the current session.
  340. *
  341. * $success = $session->destroy();
  342. *
  343. * @return boolean
  344. */
  345. public function destroy()
  346. {
  347. if ($this->_destroyed === FALSE)
  348. {
  349. if ($this->_destroyed = $this->_destroy())
  350. {
  351. // The session has been destroyed, clear all data
  352. $this->_data = [];
  353. }
  354. }
  355. return $this->_destroyed;
  356. }
  357. /**
  358. * Restart the session.
  359. *
  360. * $success = $session->restart();
  361. *
  362. * @return boolean
  363. */
  364. public function restart()
  365. {
  366. if ($this->_destroyed === FALSE)
  367. {
  368. // Wipe out the current session.
  369. $this->destroy();
  370. }
  371. // Allow the new session to be saved
  372. $this->_destroyed = FALSE;
  373. return $this->_restart();
  374. }
  375. /**
  376. * Serializes the session data.
  377. *
  378. * @param array $data data
  379. * @return string
  380. */
  381. protected function _serialize($data)
  382. {
  383. return serialize($data);
  384. }
  385. /**
  386. * Unserializes the session data.
  387. *
  388. * @param string $data data
  389. * @return array
  390. */
  391. protected function _unserialize($data)
  392. {
  393. return unserialize($data);
  394. }
  395. /**
  396. * Encodes the session data using [base64_encode].
  397. *
  398. * @param string $data data
  399. * @return string
  400. */
  401. protected function _encode($data)
  402. {
  403. return base64_encode($data);
  404. }
  405. /**
  406. * Decodes the session data using [base64_decode].
  407. *
  408. * @param string $data data
  409. * @return string
  410. */
  411. protected function _decode($data)
  412. {
  413. return base64_decode($data);
  414. }
  415. /**
  416. * Loads the raw session data string and returns it.
  417. *
  418. * @param string $id session id
  419. * @return string
  420. */
  421. abstract protected function _read($id = NULL);
  422. /**
  423. * Generate a new session id and return it.
  424. *
  425. * @return string
  426. */
  427. abstract protected function _regenerate();
  428. /**
  429. * Writes the current session.
  430. *
  431. * @return boolean
  432. */
  433. abstract protected function _write();
  434. /**
  435. * Destroys the current session.
  436. *
  437. * @return boolean
  438. */
  439. abstract protected function _destroy();
  440. /**
  441. * Restarts the current session.
  442. *
  443. * @return boolean
  444. */
  445. abstract protected function _restart();
  446. }