PageRenderTime 40ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/symphony/lib/core/class.session.php

https://github.com/vlad-ghita/symphony-2
PHP | 257 lines | 108 code | 27 blank | 122 comment | 17 complexity | 445e4d979dd48184e30c6747290cd884 MD5 | raw file
Possible License(s): BSD-3-Clause-No-Nuclear-License-2014
  1. <?php
  2. /**
  3. * @package core
  4. */
  5. /**
  6. * The Session class is a handler for all Session related logic in PHP. The functions
  7. * map directly to all handler functions as defined by session_set_save_handler in
  8. * PHP. In Symphony, this function is used in conjunction with the `Cookie` class.
  9. * Based on: http://php.net/manual/en/function.session-set-save-handler.php#81761
  10. * by klose at openriverbed dot de which was based on
  11. * http://php.net/manual/en/function.session-set-save-handler.php#79706 by
  12. * maria at junkies dot jp
  13. *
  14. * @link http://php.net/manual/en/function.session-set-save-handler.php
  15. */
  16. require_once(CORE . '/class.cacheable.php');
  17. Class Session{
  18. /**
  19. * If a Session has been created, this will be true, otherwise false
  20. *
  21. * @var boolean
  22. */
  23. private static $_initialized = false;
  24. /**
  25. * Starts a Session object, only if one doesn't already exist. This function maps
  26. * the Session Handler functions to this classes methods by reading the default
  27. * information from the PHP ini file.
  28. *
  29. * @link http://php.net/manual/en/function.session-set-save-handler.php
  30. * @link http://php.net/manual/en/function.session-set-cookie-params.php
  31. * @param integer $lifetime
  32. * How long a Session is valid for, by default this is 0, which means it
  33. * never expires
  34. * @param string $path
  35. * The path the cookie is valid for on the domain
  36. * @param string $domain
  37. * The domain this cookie is valid for
  38. * @param boolean $httpOnly
  39. * Whether this cookie can be read by Javascript. By default the cookie
  40. * cannot be read by Javascript
  41. * @param boolean $secure
  42. * Whether this cookie should only be sent on secure servers. By default this is
  43. * false, which means the cookie can be sent over HTTP and HTTPS
  44. * @throws Exception
  45. * @return string|boolean
  46. * Returns the Session ID on success, or false on error.
  47. */
  48. public static function start($lifetime = 0, $path = '/', $domain = NULL, $httpOnly = true, $secure = false) {
  49. if (!self::$_initialized) {
  50. if(!is_object(Symphony::Database()) || !Symphony::Database()->isConnected()) return false;
  51. if (session_id() == '') {
  52. ini_set('session.save_handler', 'user');
  53. ini_set('session.gc_maxlifetime', $lifetime);
  54. ini_set('session.gc_probability', '1');
  55. ini_set('session.gc_divisor', Symphony::Configuration()->get('session_gc_divisor', 'symphony'));
  56. }
  57. session_set_save_handler(
  58. array('Session', 'open'),
  59. array('Session', 'close'),
  60. array('Session', 'read'),
  61. array('Session', 'write'),
  62. array('Session', 'destroy'),
  63. array('Session', 'gc')
  64. );
  65. session_set_cookie_params($lifetime, $path, ($domain ? $domain : self::getDomain()), $secure, $httpOnly);
  66. if(session_id() == ''){
  67. if(headers_sent()){
  68. throw new Exception('Headers already sent. Cannot start session.');
  69. }
  70. register_shutdown_function('session_write_close');
  71. session_start();
  72. }
  73. self::$_initialized = true;
  74. }
  75. return session_id();
  76. }
  77. /**
  78. * Returns the current domain for the Session to be saved to, if the installation
  79. * is on localhost, this returns null and just allows PHP to take care of setting
  80. * the valid domain for the Session, otherwise it will return the non-www version
  81. * of the domain host.
  82. *
  83. * @return string|null
  84. * Null if on localhost, or HTTP_HOST is not set, a string of the domain name sans
  85. * www otherwise
  86. */
  87. public static function getDomain() {
  88. if(isset($_SERVER['HTTP_HOST'])){
  89. if(preg_match('/(localhost|127\.0\.0\.1)/', $_SERVER['HTTP_HOST']) || $_SERVER['SERVER_ADDR'] == '127.0.0.1'){
  90. return null; // prevent problems on local setups
  91. }
  92. return preg_replace('/(^www\.|:\d+$)/i', NULL, $_SERVER['HTTP_HOST']);
  93. }
  94. return null;
  95. }
  96. /**
  97. * Allows the Session to open without any further logic.
  98. *
  99. * @return boolean
  100. * Always returns true
  101. */
  102. public static function open() {
  103. return true;
  104. }
  105. /**
  106. * Allows the Session to close without any further logic. Acts as a
  107. * destructor function for the Session.
  108. *
  109. * @return boolean
  110. * Always returns true
  111. */
  112. public static function close() {
  113. return true;
  114. }
  115. /**
  116. * Given an ID, and some data, save it into `tbl_sessions`. This uses
  117. * the ID as a unique key, and will override any existing data. If the
  118. * `$data` is deemed to be empty, no row will be saved in the database
  119. * unless there is an existing row.
  120. *
  121. * @param string $id
  122. * The ID of the Session, usually a hash
  123. * @param string $data
  124. * The Session information, usually a serialized object of
  125. * `$_SESSION[Cookie->_index]`
  126. * @throws DatabaseException
  127. * @return boolean
  128. * True if the Session information was saved successfully, false otherwise
  129. */
  130. public static function write($id, $data) {
  131. // Only prevent this record from saving if there isn't already a record
  132. // in the database. This prevents empty Sessions from being created, but
  133. // allows them to be nulled.
  134. $session_data = Session::read($id);
  135. if(is_null($session_data)) {
  136. $empty = true;
  137. $unserialized_data = Session::unserialize_session($session_data);
  138. foreach ($unserialized_data as $d) {
  139. if (!empty($d)) {
  140. $empty = false;
  141. }
  142. }
  143. if ($empty) {
  144. return false;
  145. }
  146. }
  147. $fields = array(
  148. 'session' => $id,
  149. 'session_expires' => time(),
  150. 'session_data' => $data
  151. );
  152. return Symphony::Database()->insert($fields, 'tbl_sessions', true);
  153. }
  154. /**
  155. * Given raw session data return the unserialized array.
  156. * Used to check if the session is really empty before writing.
  157. *
  158. * @since Symphony 2.3.3
  159. * @param string $data
  160. * The serialized session data
  161. * @return string
  162. * The unserialised session data
  163. */
  164. private static function unserialize_session($data) {
  165. $hasBuffer = isset($_SESSION);
  166. $buffer = $_SESSION;
  167. session_decode($data);
  168. $session = $_SESSION;
  169. if($hasBuffer) {
  170. $_SESSION = $buffer;
  171. }
  172. else {
  173. unset($_SESSION);
  174. }
  175. return $session;
  176. }
  177. /**
  178. * Given a session's ID, return it's row from `tbl_sessions`
  179. *
  180. * @param string $id
  181. * The identifier for the Session to fetch
  182. * @return string
  183. * The serialised session data
  184. */
  185. public static function read($id) {
  186. return Symphony::Database()->fetchVar(
  187. 'session_data', 0,
  188. sprintf(
  189. "SELECT `session_data` FROM `tbl_sessions` WHERE `session` = '%s' LIMIT 1",
  190. Symphony::Database()->cleanValue($id)
  191. )
  192. );
  193. }
  194. /**
  195. * Given a session's ID, remove it's row from `tbl_sessions`
  196. *
  197. * @param string $id
  198. * The identifier for the Session to destroy
  199. * @throws DatabaseException
  200. * @return boolean
  201. * True if the Session was deleted successfully, false otherwise
  202. */
  203. public static function destroy($id) {
  204. return Symphony::Database()->query(
  205. sprintf(
  206. "DELETE FROM `tbl_sessions` WHERE `session` = '%s'",
  207. Symphony::Database()->cleanValue($id)
  208. )
  209. );
  210. }
  211. /**
  212. * The garbage collector, which removes all empty Sessions, or any
  213. * Sessions that have expired. This has a 10% chance of firing based
  214. * off the `gc_probability`/`gc_divisor`.
  215. *
  216. * @param integer $max
  217. * The max session lifetime.
  218. * @throws DatabaseException
  219. * @return boolean
  220. * True on Session deletion, false if an error occurs
  221. */
  222. public static function gc($max) {
  223. return Symphony::Database()->query(
  224. sprintf(
  225. "DELETE FROM `tbl_sessions` WHERE `session_expires` <= '%s'",
  226. Symphony::Database()->cleanValue(time() - $max)
  227. )
  228. );
  229. }
  230. }