PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/sources/Session.php

https://github.com/Arantor/Elkarte
PHP | 239 lines | 130 code | 30 blank | 79 comment | 37 complexity | 63668dac7c97979f9ef554f32e6f6fc2 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0
  1. <?php
  2. /**
  3. * @name ElkArte Forum
  4. * @copyright ElkArte Forum contributors
  5. * @license BSD http://opensource.org/licenses/BSD-3-Clause
  6. *
  7. * This software is a derived product, based on:
  8. *
  9. * Simple Machines Forum (SMF)
  10. * copyright: 2011 Simple Machines (http://www.simplemachines.org)
  11. * license: BSD, See included LICENSE.TXT for terms and conditions.
  12. *
  13. * @version 1.0 Alpha
  14. *
  15. * Implementation of PHP's session API.
  16. * What it does:
  17. * - it handles the session data in the database (more scalable.)
  18. * - it uses the databaseSession_lifetime setting for garbage collection.
  19. * - the custom session handler is set by loadSession().
  20. *
  21. */
  22. if (!defined('ELKARTE'))
  23. die('No access...');
  24. /**
  25. * Attempt to start the session, unless it already has been.
  26. */
  27. function loadSession()
  28. {
  29. global $HTTP_SESSION_VARS, $modSettings, $boardurl, $sc;
  30. // Attempt to change a few PHP settings.
  31. @ini_set('session.use_cookies', true);
  32. @ini_set('session.use_only_cookies', false);
  33. @ini_set('url_rewriter.tags', '');
  34. @ini_set('session.use_trans_sid', false);
  35. @ini_set('arg_separator.output', '&amp;');
  36. if (!empty($modSettings['globalCookies']))
  37. {
  38. $parsed_url = parse_url($boardurl);
  39. if (preg_match('~^\d{1,3}(\.\d{1,3}){3}$~', $parsed_url['host']) == 0 && preg_match('~(?:[^\.]+\.)?([^\.]{2,}\..+)\z~i', $parsed_url['host'], $parts) == 1)
  40. @ini_set('session.cookie_domain', '.' . $parts[1]);
  41. }
  42. // @todo Set the session cookie path?
  43. // If it's already been started... probably best to skip this.
  44. if ((ini_get('session.auto_start') == 1 && !empty($modSettings['databaseSession_enable'])) || session_id() == '')
  45. {
  46. // Attempt to end the already-started session.
  47. if (ini_get('session.auto_start') == 1)
  48. session_write_close();
  49. // This is here to stop people from using bad junky PHPSESSIDs.
  50. if (isset($_REQUEST[session_name()]) && preg_match('~^[A-Za-z0-9,-]{16,64}$~', $_REQUEST[session_name()]) == 0 && !isset($_COOKIE[session_name()]))
  51. {
  52. $session_id = md5(md5('smf_sess_' . time()) . mt_rand());
  53. $_REQUEST[session_name()] = $session_id;
  54. $_GET[session_name()] = $session_id;
  55. $_POST[session_name()] = $session_id;
  56. }
  57. // Use database sessions? (they don't work in 4.1.x!)
  58. if (!empty($modSettings['databaseSession_enable']))
  59. {
  60. session_set_save_handler('sessionOpen', 'sessionClose', 'sessionRead', 'sessionWrite', 'sessionDestroy', 'sessionGC');
  61. @ini_set('session.gc_probability', '1');
  62. }
  63. elseif (ini_get('session.gc_maxlifetime') <= 1440 && !empty($modSettings['databaseSession_lifetime']))
  64. @ini_set('session.gc_maxlifetime', max($modSettings['databaseSession_lifetime'], 60));
  65. // Use cache setting sessions?
  66. if (empty($modSettings['databaseSession_enable']) && !empty($modSettings['cache_enable']) && php_sapi_name() != 'cli')
  67. {
  68. call_integration_hook('integrate_session_handlers');
  69. // @todo move these to a plugin.
  70. if (function_exists('mmcache_set_session_handlers'))
  71. mmcache_set_session_handlers();
  72. elseif (function_exists('eaccelerator_set_session_handlers'))
  73. eaccelerator_set_session_handlers();
  74. }
  75. session_start();
  76. // Change it so the cache settings are a little looser than default.
  77. if (!empty($modSettings['databaseSession_loose']))
  78. header('Cache-Control: private');
  79. }
  80. // Set the randomly generated code.
  81. if (!isset($_SESSION['session_var']))
  82. {
  83. $_SESSION['session_value'] = md5(session_id() . mt_rand());
  84. $_SESSION['session_var'] = substr(preg_replace('~^\d+~', '', sha1(mt_rand() . session_id() . mt_rand())), 0, rand(7, 12));
  85. }
  86. $sc = $_SESSION['session_value'];
  87. }
  88. /**
  89. * Implementation of sessionOpen() replacing the standard open handler.
  90. * It simply returns true.
  91. *
  92. * @param string $save_path
  93. * @param string $session_name
  94. * @return boolean
  95. */
  96. function sessionOpen($save_path, $session_name)
  97. {
  98. return true;
  99. }
  100. /**
  101. * Implementation of sessionClose() replacing the standard close handler.
  102. * It simply returns true.
  103. *
  104. * @return boolean
  105. */
  106. function sessionClose()
  107. {
  108. return true;
  109. }
  110. /**
  111. * Implementation of sessionRead() replacing the standard read handler.
  112. *
  113. * @param string $session_id
  114. * @return string
  115. */
  116. function sessionRead($session_id)
  117. {
  118. global $smcFunc;
  119. if (preg_match('~^[A-Za-z0-9,-]{16,64}$~', $session_id) == 0)
  120. return false;
  121. // Look for it in the database.
  122. $result = $smcFunc['db_query']('', '
  123. SELECT data
  124. FROM {db_prefix}sessions
  125. WHERE session_id = {string:session_id}
  126. LIMIT 1',
  127. array(
  128. 'session_id' => $session_id,
  129. )
  130. );
  131. list ($sess_data) = $smcFunc['db_fetch_row']($result);
  132. $smcFunc['db_free_result']($result);
  133. return $sess_data;
  134. }
  135. /**
  136. * Implementation of sessionWrite() replacing the standard write handler.
  137. *
  138. * @param string $session_id
  139. * @param string $data
  140. * @return boolean
  141. */
  142. function sessionWrite($session_id, $data)
  143. {
  144. global $smcFunc;
  145. if (preg_match('~^[A-Za-z0-9,-]{16,64}$~', $session_id) == 0)
  146. return false;
  147. // First try to update an existing row...
  148. $result = $smcFunc['db_query']('', '
  149. UPDATE {db_prefix}sessions
  150. SET data = {string:data}, last_update = {int:last_update}
  151. WHERE session_id = {string:session_id}',
  152. array(
  153. 'last_update' => time(),
  154. 'data' => $data,
  155. 'session_id' => $session_id,
  156. )
  157. );
  158. // If that didn't work, try inserting a new one.
  159. if ($smcFunc['db_affected_rows']() == 0)
  160. $result = $smcFunc['db_insert']('ignore',
  161. '{db_prefix}sessions',
  162. array('session_id' => 'string', 'data' => 'string', 'last_update' => 'int'),
  163. array($session_id, $data, time()),
  164. array('session_id')
  165. );
  166. return $result;
  167. }
  168. /**
  169. * Implementation of sessionDestroy() replacing the standard destroy handler.
  170. *
  171. * @param string $session_id
  172. * @return boolean
  173. */
  174. function sessionDestroy($session_id)
  175. {
  176. global $smcFunc;
  177. if (preg_match('~^[A-Za-z0-9,-]{16,64}$~', $session_id) == 0)
  178. return false;
  179. // Just delete the row...
  180. return $smcFunc['db_query']('', '
  181. DELETE FROM {db_prefix}sessions
  182. WHERE session_id = {string:session_id}',
  183. array(
  184. 'session_id' => $session_id,
  185. )
  186. );
  187. }
  188. /**
  189. * Implementation of sessionGC() replacing the standard gc handler.
  190. * Callback for garbage collection.
  191. *
  192. * @param int $max_lifetime
  193. * @return boolean
  194. */
  195. function sessionGC($max_lifetime)
  196. {
  197. global $modSettings, $smcFunc;
  198. // Just set to the default or lower? Ignore it for a higher value. (hopefully)
  199. if (!empty($modSettings['databaseSession_lifetime']) && ($max_lifetime <= 1440 || $modSettings['databaseSession_lifetime'] > $max_lifetime))
  200. $max_lifetime = max($modSettings['databaseSession_lifetime'], 60);
  201. // Clean up after yerself ;).
  202. return $smcFunc['db_query']('', '
  203. DELETE FROM {db_prefix}sessions
  204. WHERE last_update < {int:last_update}',
  205. array(
  206. 'last_update' => time() - $max_lifetime,
  207. )
  208. );
  209. }