PageRenderTime 54ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/bauhouse/symphony-2
PHP | 226 lines | 89 code | 27 blank | 110 comment | 15 complexity | db8eb91c0a092a367a338a9ababdf691 MD5 | raw file
  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. * False until a shutdown function is registered, true after that
  26. *
  27. * @var boolean
  28. */
  29. private static $_registered = false;
  30. /**
  31. * Starts a Session object, only if one doesn't already exist. This function maps
  32. * the Session Handler functions to this classes methods by reading the default
  33. * information from the PHP ini file.
  34. *
  35. * @link http://php.net/manual/en/function.session-set-save-handler.php
  36. * @link http://php.net/manual/en/function.session-set-cookie-params.php
  37. * @param integer $lifetime
  38. * How long a Session is valid for, by default this is 0, which means it
  39. * never expires
  40. * @param string $path
  41. * The path the cookie is valid for on the domain
  42. * @param string $domain
  43. * The domain this cookie is valid for
  44. * @param boolean $httpOnly
  45. * Whether this cookie can be read by Javascript. By default the cookie
  46. * can be read using Javascript and PHP
  47. * @return string|boolean
  48. * Returns the Session ID on success, or false on error.
  49. */
  50. public static function start($lifetime = 0, $path = '/', $domain = NULL, $httpOnly = false) {
  51. if (!self::$_initialized) {
  52. if(!is_object(Symphony::Database()) || !Symphony::Database()->isConnected()) return false;
  53. if (session_id() == '') {
  54. ini_set('session.save_handler', 'user');
  55. ini_set('session.gc_maxlifetime', $lifetime);
  56. ini_set('session.gc_probability', '1');
  57. ini_set('session.gc_divisor', Symphony::Configuration()->get('session_gc_divisor', 'symphony'));
  58. }
  59. session_set_save_handler(
  60. array('Session', 'open'),
  61. array('Session', 'close'),
  62. array('Session', 'read'),
  63. array('Session', 'write'),
  64. array('Session', 'destroy'),
  65. array('Session', 'gc')
  66. );
  67. session_set_cookie_params($lifetime, $path, ($domain ? $domain : self::getDomain()), false, $httpOnly);
  68. if(session_id() == ""){
  69. if(headers_sent()){
  70. throw new Exception('Headers already sent. Cannot start session.');
  71. }
  72. session_start();
  73. }
  74. self::$_initialized = true;
  75. }
  76. return session_id();
  77. }
  78. /**
  79. * Returns the current domain for the Session to be saved to, if the installation
  80. * is on localhost, this returns null and just allows PHP to take care of setting
  81. * the valid domain for the Session, otherwise it will return the non-www version
  82. * of the domain host.
  83. *
  84. * @return string|null
  85. * Null if on localhost, or HTTP_HOST is not set, a string of the domain name sans
  86. * www otherwise
  87. */
  88. public static function getDomain() {
  89. if(isset($_SERVER['HTTP_HOST'])){
  90. if(preg_match('/(localhost|127\.0\.0\.1)/', $_SERVER['HTTP_HOST']) || $_SERVER['SERVER_ADDR'] == '127.0.0.1'){
  91. return null; // prevent problems on local setups
  92. }
  93. return preg_replace('/(^www.|:\d+$)/i', NULL, $_SERVER['HTTP_HOST']);
  94. }
  95. return null;
  96. }
  97. /**
  98. * Called when a Session is created, registers the close function
  99. *
  100. * @return boolean
  101. * Always returns true
  102. */
  103. public static function open() {
  104. if (!self::$_registered) {
  105. register_shutdown_function('session_write_close');
  106. self::$_registered = true;
  107. }
  108. return self::$_registered;
  109. }
  110. /**
  111. * Allows the Session to close without any further logic. Acts as a
  112. * destructor function for the Session.
  113. *
  114. * @return boolean
  115. * Always returns true
  116. */
  117. public static function close() {
  118. return true;
  119. }
  120. /**
  121. * Given an ID, and some data, save it into `tbl_sessions`. This uses
  122. * the ID as a unique key, and will override any existing data. If the
  123. * `$data` is deemed to be empty, no row will be saved in the database
  124. * unless there is an existing row.
  125. *
  126. * @param string $id
  127. * The ID of the Session, usually a hash
  128. * @param string $data
  129. * The Session information, usually a serialized object of
  130. * `$_SESSION[Cookie->_index]`
  131. * @return boolean
  132. * True if the Session information was saved successfully, false otherwise
  133. */
  134. public static function write($id, $data) {
  135. // Only prevent this record from saving if there isn't already a record
  136. // in the database. This prevents empty Sessions from being created, but
  137. // allows them to be nulled.
  138. if(is_null(Session::read($id))) {
  139. if(preg_match('/^([^}]+\|a:0:{})+$/i', $data)) return true;
  140. }
  141. $fields = array(
  142. 'session' => $id,
  143. 'session_expires' => time(),
  144. 'session_data' => $data
  145. );
  146. return Symphony::Database()->insert($fields, 'tbl_sessions', true);
  147. }
  148. /**
  149. * Given a session's ID, return it's row from `tbl_sessions`
  150. *
  151. * @param string $id
  152. * The identifier for the Session to fetch
  153. * @return string
  154. * The serialised session data
  155. */
  156. public static function read($id) {
  157. return Symphony::Database()->fetchVar(
  158. 'session_data', 0,
  159. sprintf(
  160. "SELECT `session_data` FROM `tbl_sessions` WHERE `session` = '%s' LIMIT 1",
  161. Symphony::Database()->cleanValue($id)
  162. )
  163. );
  164. }
  165. /**
  166. * Given a session's ID, remove it's row from `tbl_sessions`
  167. *
  168. * @param string $id
  169. * The identifier for the Session to destroy
  170. * @return boolean
  171. * True if the Session was deleted successfully, false otherwise
  172. */
  173. public static function destroy($id) {
  174. return Symphony::Database()->query(
  175. sprintf(
  176. "DELETE FROM `tbl_sessions` WHERE `session` = '%s'",
  177. Symphony::Database()->cleanValue($id)
  178. )
  179. );
  180. }
  181. /**
  182. * The garbage collector, which removes all empty Sessions, or any
  183. * Sessions that have expired. This has a 10% chance of firing based
  184. * off the `gc_probability`/`gc_divisor`.
  185. *
  186. * @param integer $max
  187. * The max session lifetime.
  188. * @return boolean
  189. * True on Session deletion, false if an error occurs
  190. */
  191. public static function gc($max) {
  192. return Symphony::Database()->query(
  193. sprintf(
  194. "DELETE FROM `tbl_sessions` WHERE `session_expires` <= '%s'",
  195. Symphony::Database()->cleanValue(time() - $max)
  196. )
  197. );
  198. }
  199. }