PageRenderTime 91ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/sessions.php

https://github.com/MightyGorgon/icy_phoenix
PHP | 2213 lines | 1458 code | 280 blank | 475 comment | 316 complexity | eb1c16d33718246d398888cce95be578 MD5 | raw file
Possible License(s): AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. *
  4. * @package Icy Phoenix
  5. * @version $Id$
  6. * @copyright (c) 2008 Icy Phoenix
  7. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8. *
  9. */
  10. /**
  11. * @ignore
  12. */
  13. if (!defined('IN_ICYPHOENIX'))
  14. {
  15. exit;
  16. }
  17. /**
  18. * Session class
  19. * @package phpBB3 / Icy Phoenix
  20. */
  21. class session
  22. {
  23. var $cookie_data = array();
  24. var $cookie_expire = 0;
  25. var $page = array();
  26. var $data = array();
  27. var $browser = '';
  28. var $forwarded_for = '';
  29. var $host = '';
  30. var $session_id = '';
  31. var $ip = '';
  32. var $load = 0;
  33. var $time_now = 0;
  34. var $update_session_page = true;
  35. /**
  36. * Start session management
  37. *
  38. * This is where all session activity begins. We gather various pieces of
  39. * information from the client and server. We test to see if a session already
  40. * exists. If it does, fine and dandy. If it doesn't we'll go on to create a
  41. * new one ... pretty logical heh? We also examine the system load (if we're
  42. * running on a system which makes such information readily available) and
  43. * halt if it's above an admin definable limit.
  44. *
  45. * @param bool $update_session_page if true the session page gets updated.
  46. * This can be set to circumvent certain scripts to update the users last visited page.
  47. */
  48. function session_begin($update_session_page = true)
  49. {
  50. global $SID, $_SID, $_EXTRA_URL, $db, $config;
  51. // ICY PHOENIX - BEGIN
  52. global $lang;
  53. // ICY PHOENIX - END
  54. // Give us some basic information
  55. $this->time_now = time();
  56. $this->cookie_data = array('u' => 0, 'k' => '');
  57. $this->cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000);
  58. $this->update_session_page = (empty($update_session_page) || defined('IMG_THUMB')) ? false : true;
  59. //$this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : '';
  60. $this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? (string) $_SERVER['HTTP_USER_AGENT'] : '';
  61. $this->referer = (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : '';
  62. $this->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? htmlspecialchars((string) $_SERVER['HTTP_X_FORWARDED_FOR']) : '';
  63. $this->host = extract_current_hostname();
  64. $this->page = extract_current_page(IP_ROOT_PATH);
  65. $session_cookie_empty = empty($_COOKIE[$config['cookie_name'] . '_sid']) ? true : false;
  66. $session_get_empty = empty($_GET['sid']) ? true : false;
  67. $session_empty = true;
  68. if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u']))
  69. {
  70. $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
  71. $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
  72. $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true);
  73. // Mighty Gorgon: I'm still not sure if I want to keep 'sid=' in Icy Phoenix as well... maybe better removing it!!!
  74. //$SID = (defined('NEED_SID')) ? ('sid=' . $this->session_id) : 'sid=';
  75. $SID = (defined('NEED_SID')) ? ('sid=' . $this->session_id) : '';
  76. $_SID = (defined('NEED_SID')) ? $this->session_id : '';
  77. $session_empty = empty($this->session_id) ? true : false;
  78. }
  79. // Mighty Gorgon: moved here this IF block... why it was so down in the code???
  80. // if no session id is set, redirect to index.php
  81. //if (defined('NEED_SID') && ($cookie_empty || (!isset($_GET['sid']) || ($this->session_id !== $_GET['sid']))))
  82. if (defined('NEED_SID') && !defined('IN_LOGIN') && ($session_cookie_empty || $session_empty || !isset($_GET['sid']) || ((isset($_GET['sid']) && ($this->session_id !== $_GET['sid'])))))
  83. {
  84. // Mighty Gorgon: I don't know why it isn't working properly, returning blank page!!!
  85. //send_status_line(401, 'Not authorized');
  86. // Mighty Gorgon: removed append_sid as it seems the user doesn't have a valid SID!
  87. redirect(IP_ROOT_PATH . 'index.' . PHP_EXT);
  88. }
  89. if ($session_empty)
  90. {
  91. $this->session_id = request_var('sid', '');
  92. $_SID = $this->session_id;
  93. $SID = 'sid=' . $this->session_id;
  94. $this->cookie_data = array('u' => 0, 'k' => '');
  95. }
  96. $_EXTRA_URL = array();
  97. // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests
  98. // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip.
  99. $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : ((!empty($_ENV['REMOTE_ADDR'])) ? $_ENV['REMOTE_ADDR'] : getenv('REMOTE_ADDR'));
  100. $this->ip = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->ip));
  101. // split the list of IPs
  102. $ips = explode(' ', $this->ip);
  103. // Default IP if REMOTE_ADDR is invalid
  104. $this->ip = '127.0.0.1';
  105. $format_ipv4 = get_preg_expression('ipv4');
  106. $format_ipv6 = get_preg_expression('ipv6');
  107. foreach ($ips as $ip)
  108. {
  109. if (preg_match($format_ipv4, $ip))
  110. {
  111. $this->ip = $ip;
  112. }
  113. elseif (preg_match($format_ipv6, $ip))
  114. {
  115. // Quick check for IPv4-mapped address in IPv6
  116. if (stripos($ip, '::ffff:') === 0)
  117. {
  118. $ipv4 = substr($ip, 7);
  119. if (preg_match($format_ipv4, $ipv4))
  120. {
  121. $ip = $ipv4;
  122. }
  123. }
  124. $this->ip = $ip;
  125. }
  126. else
  127. {
  128. // We want to use the last valid address in the chain
  129. // Leave foreach loop when address is invalid
  130. break;
  131. }
  132. }
  133. $this->load = false;
  134. // Load limit check (if applicable)
  135. if ($config['limit_load'] || $config['limit_search_load'])
  136. {
  137. if ((function_exists('sys_getloadavg') && ($load = sys_getloadavg())) || ($load = explode(' ', @file_get_contents('/proc/loadavg'))))
  138. {
  139. $this->load = array_slice($load, 0, 1);
  140. $this->load = floatval($this->load[0]);
  141. }
  142. else
  143. {
  144. set_config('limit_load', '0');
  145. set_config('limit_search_load', '0');
  146. }
  147. }
  148. // if session id is set
  149. if (!empty($this->session_id))
  150. {
  151. $sql = "SELECT u.*, s.*
  152. FROM " . SESSIONS_TABLE . " s, " . USERS_TABLE . " u
  153. WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "'
  154. AND u.user_id = s.session_user_id";
  155. $result = $db->sql_query($sql);
  156. $this->data = $db->sql_fetchrow($result);
  157. $db->sql_freeresult($result);
  158. // Did the session exist in the DB?
  159. if (isset($this->data['user_id']))
  160. {
  161. if ((strpos($this->ip, ':') !== false) && (strpos($this->data['session_ip'], ':') !== false))
  162. {
  163. $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
  164. $u_ip = short_ipv6($this->ip, $config['ip_check']);
  165. }
  166. else
  167. {
  168. $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
  169. $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
  170. }
  171. $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 254))) : '';
  172. $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 254))) : '';
  173. // referer checks
  174. // The @ before $config['referer_validation'] suppresses notices present while running the updater
  175. $check_referer_path = (@$config['referer_validation'] == REFERER_VALIDATE_PATH);
  176. $referer_valid = true;
  177. // we assume HEAD and TRACE to be foul play and thus only whitelist GET
  178. if (@$config['referer_validation'] && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) !== 'get')
  179. {
  180. $referer_valid = $this->validate_referer($check_referer_path);
  181. }
  182. if (($u_ip === $s_ip) && ($s_browser === $u_browser) && $referer_valid)
  183. {
  184. // Some useful boolean checks... defined here for future easy of use
  185. $session_expired = false;
  186. $session_refresh_time = (int) SESSION_REFRESH;
  187. $autologin_expired = (!empty($config['max_autologin_time']) && ($this->data['session_time'] < ($this->time_now - (86400 * (int) $config['max_autologin_time']) + $session_refresh_time))) ? true : false;
  188. $session_time_expired = ($this->data['session_time'] < ($this->time_now - ((int) $config['session_length'] + $session_refresh_time))) ? true : false;
  189. $session_refresh = ($this->data['session_time'] < ($this->time_now - $session_refresh_time)) ? true : false;
  190. if (!$session_expired)
  191. {
  192. // Check the session length timeframe if autologin is not enabled.
  193. // Else check the autologin length... and also removing those having autologin enabled but no longer allowed site-wide.
  194. if (empty($this->data['session_autologin']))
  195. {
  196. if ($session_time_expired)
  197. {
  198. $session_expired = true;
  199. }
  200. }
  201. elseif (empty($config['allow_autologin']) || $autologin_expired)
  202. {
  203. $session_expired = true;
  204. }
  205. }
  206. // ICY PHOENIX - BEGIN
  207. // This portion of code needs to stay here (after isset($this->data['user_id']) )... otherwise we are potentially going to instantiate some $user->data even if $user->data is still empty
  208. $this->bots_process();
  209. if (isset($this->data['user_id']) && ($this->data['user_id'] != ANONYMOUS) && isset($this->data['user_level']) && ($this->data['user_level'] == JUNIOR_ADMIN))
  210. {
  211. define('IS_JUNIOR_ADMIN', true);
  212. $this->data['user_level'] = (!defined('IN_ADMIN') && !defined('IN_CMS')) ? ADMIN : MOD;
  213. }
  214. // Refresh last visit time for those users having autologin enabled or those users with session time expired (only if config for this has been set)
  215. if (($this->data['user_id'] != ANONYMOUS) && ((!empty($config['session_last_visit_reset']) && $session_time_expired) || (!empty($config['allow_autologin']) && $autologin_expired) || empty($this->data['user_lastvisit'])))
  216. {
  217. $sql = "UPDATE " . USERS_TABLE . "
  218. SET user_lastvisit = " . (int) $this->data['session_time'] . "
  219. WHERE user_id = " . (int) $this->data['user_id'];
  220. $db->sql_query($sql);
  221. }
  222. // ICY PHOENIX - END
  223. if (!$session_expired)
  224. {
  225. // Only update session DB a minute or so after last update or if page changes
  226. // Mighty Gorgon: in Icy Phoenix we give maximum priority to $this->update_session_page, because we don't want the session to be updated for thumbnails or other special features!
  227. if ($this->update_session_page && ($session_refresh || ($this->data['session_page'] != $this->page['page'])) && empty($_REQUEST['explain']))
  228. {
  229. $sql_ary = array();
  230. // ICY PHOENIX - BEGIN
  231. // Update $user->data
  232. $this->data['user_session_time'] = $this->time_now;
  233. $this->data['user_session_page'] = (string) substr($this->page['page'], 0, 254);
  234. $this->data['user_browser'] = (string) substr($this->browser, 0, 254);
  235. $this->data['user_totalpages'] = (int) $this->data['user_totalpages'] + 1;
  236. $this->data['user_totaltime'] = (int) $this->data['user_totaltime'] + $this->time_now - $this->data['session_time'];
  237. // ICY PHOENIX - END
  238. // A little trick to reset session_admin on session re-usage
  239. if (!defined('IN_ADMIN') && !defined('IN_CMS') && $session_time_expired)
  240. {
  241. $sql_ary['session_admin'] = 0;
  242. }
  243. $sql_ary['session_time'] = $this->time_now;
  244. $sql_ary['session_page'] = $this->data['user_session_page'];
  245. $sql_ary['session_browser'] = $this->data['user_browser'];
  246. $sql_ary['session_forum_id'] = $this->page['forum'];
  247. $sql_ary['session_topic_id'] = $this->page['topic'];
  248. $db->sql_return_on_error(true);
  249. $sql = "UPDATE " . SESSIONS_TABLE . " SET " . $db->sql_build_array('UPDATE', $sql_ary) . "
  250. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
  251. $result = $db->sql_query($sql);
  252. // ICY PHOENIX - BEGIN
  253. if ($this->data['user_id'] != ANONYMOUS)
  254. {
  255. $sql_ary = array();
  256. $sql_ary['user_ip'] = $this->ip;
  257. $sql_ary['user_session_time'] = $this->data['user_session_time'];
  258. $sql_ary['user_session_page'] = $this->data['user_session_page'];
  259. $sql_ary['user_browser'] = $this->data['user_browser'];
  260. $sql_ary['user_totalpages'] = $this->data['user_totalpages'];
  261. $sql_ary['user_totaltime'] = $this->data['user_totaltime'];
  262. $sql = "UPDATE " . USERS_TABLE . " SET " . $db->sql_build_array('UPDATE', $sql_ary) . "
  263. WHERE user_id = " . $this->data['user_id'];
  264. $result = $db->sql_query($sql);
  265. }
  266. // ICY PHOENIX - END
  267. $db->sql_return_on_error(false);
  268. }
  269. $this->data['is_registered'] = (empty($this->data['is_bot']) && ($this->data['user_id'] != ANONYMOUS) && !empty($this->data['user_active'])) ? true : false;
  270. $this->data['session_logged_in'] = $this->data['is_registered'];
  271. $this->data['user_lang'] = basename($this->data['user_lang']);
  272. $this->upi2db();
  273. return true;
  274. }
  275. }
  276. else
  277. {
  278. // Added logging temporarily to help debug bugs...
  279. if (defined('DEBUG_EXTRA') && DEBUG_EXTRA && ($this->data['user_id'] != ANONYMOUS))
  280. {
  281. if ($referer_valid)
  282. {
  283. add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser);
  284. }
  285. else
  286. {
  287. add_log('critical', 'LOG_REFERER_INVALID', $this->referer);
  288. }
  289. }
  290. }
  291. }
  292. }
  293. // If we reach here then no (valid) session exists. So we'll create a new one
  294. return $this->session_create();
  295. }
  296. /**
  297. * Create a new session
  298. *
  299. * If upon trying to start a session we discover there is nothing existing we
  300. * jump here. Additionally this method is called directly during login to regenerate
  301. * the session for the specific user. In this method we carry out a number of tasks;
  302. * garbage collection, (search)bot checking, banned user comparison. Basically
  303. * though this method will result in a new session for a specific user.
  304. */
  305. function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true)
  306. {
  307. global $SID, $_SID, $db, $config, $cache;
  308. $this->data = array();
  309. $config['session_gc'] = (int) $config['cron_sessions_interval'];
  310. $config['session_last_gc'] = (int) $config['cron_sessions_last_run'];
  311. // Garbage collection ... remove old sessions updating user information if necessary. It means (potentially) 11 queries but only infrequently
  312. if ($this->time_now > ($config['session_last_gc'] + $config['session_gc']))
  313. {
  314. $this->session_gc();
  315. }
  316. // Do we allow autologin on this site? No? Then override anything that may be requested here
  317. if (!$config['allow_autologin'])
  318. {
  319. $this->cookie_data['k'] = false;
  320. $persist_login = false;
  321. }
  322. $user_logged_in = false;
  323. // If we're presented with an autologin key we'll join against it.
  324. // Else if we've been passed a user_id we'll grab data based on that
  325. if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data))
  326. {
  327. $sql = "SELECT u.*
  328. FROM " . USERS_TABLE . " u, " . SESSIONS_KEYS_TABLE . " k
  329. WHERE u.user_id = " . (int) $this->cookie_data['u'] . "
  330. AND u.user_active = 1
  331. AND k.user_id = u.user_id
  332. AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
  333. $result = $db->sql_query($sql);
  334. $this->data = $db->sql_fetchrow($result);
  335. $db->sql_freeresult($result);
  336. $user_logged_in = true;
  337. }
  338. elseif (($user_id !== false) && !sizeof($this->data))
  339. {
  340. $this->cookie_data['k'] = '';
  341. $this->cookie_data['u'] = $user_id;
  342. $sql = "SELECT *
  343. FROM " . USERS_TABLE . "
  344. WHERE user_id = " . (int) $this->cookie_data['u'] . "
  345. AND user_active = 1";
  346. $result = $db->sql_query($sql);
  347. $this->data = $db->sql_fetchrow($result);
  348. $db->sql_freeresult($result);
  349. $user_logged_in = true;
  350. }
  351. // If no data was returned one or more of the following occurred:
  352. // Key didn't match one in the DB
  353. // User does not exist
  354. // User is inactive
  355. if (!sizeof($this->data) || !is_array($this->data))
  356. {
  357. $this->cookie_data['k'] = '';
  358. $this->cookie_data['u'] = ANONYMOUS;
  359. $sql = "SELECT *
  360. FROM " . USERS_TABLE . "
  361. WHERE user_id = " . (int) $this->cookie_data['u'];
  362. $result = $db->sql_query($sql);
  363. $this->data = $db->sql_fetchrow($result);
  364. $db->sql_freeresult($result);
  365. }
  366. // ICY PHOENIX - BEGIN
  367. $this->bots_process();
  368. // ICY PHOENIX - END
  369. if ($this->data['user_id'] != ANONYMOUS)
  370. {
  371. $this->data['session_last_visit'] = !empty($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : $this->time_now;
  372. }
  373. else
  374. {
  375. // Bot user, if they have a SID in the Request URI we need to get rid of it otherwise they'll index this page with the SID, duplicate content oh my!
  376. if (isset($_GET['sid']) && !empty($this->data['is_bot']))
  377. {
  378. send_status_line(301, 'Moved Permanently');
  379. redirect(build_url(array('sid')));
  380. }
  381. $this->data['session_last_visit'] = $this->time_now;
  382. }
  383. // Force user id to be integer...
  384. $this->data['user_id'] = (int) $this->data['user_id'];
  385. // At this stage we should have a filled data array, defined cookie u and k data.
  386. // data array should contain recent session info if we have a real user and a recent session exists in which case session_id will also be set
  387. // Is user banned? Are they excluded? Won't return on ban, exists within method
  388. if ($this->data['user_level'] != ADMIN)
  389. {
  390. $ban_email = (($this->data['user_id'] != ANONYMOUS) && !empty($this->data['user_email'])) ? $this->data['user_email'] : false;
  391. $this->check_ban($this->data['user_id'], $this->ip, $ban_email);
  392. }
  393. // Mighty Gorgon: add to referers only if the user doesn't have a session... this is why this code is in session_create and not in session_begin
  394. if (empty($config['disable_referers']) && !empty($this->referer))
  395. {
  396. $this->process_referer();
  397. }
  398. $this->data['is_registered'] = (empty($this->data['is_bot']) && ($this->data['user_id'] != ANONYMOUS) && !empty($this->data['user_active'])) ? true : false;
  399. $this->data['session_logged_in'] = $this->data['is_registered'];
  400. // If our friend is a bot, we re-assign a previously assigned session
  401. if ($this->data['is_bot'])
  402. {
  403. // ICY PHOENIX - BEGIN
  404. // We give bots always the same session if it is not yet expired.
  405. $sql_fields = array();
  406. $sql_extra = '';
  407. if (!empty($this->browser))
  408. {
  409. $u_browser = trim(strtolower(substr($this->browser, 0, 254)));
  410. $sql_fields[] = "s.session_browser = '" . $db->sql_escape($u_browser) . "'";
  411. }
  412. if (!empty($this->ip))
  413. {
  414. $u_ip = $this->ip;
  415. $sql_fields[] = "s.session_ip = '" . $db->sql_escape($u_ip) . "'";
  416. }
  417. if (!empty($sql_fields))
  418. {
  419. foreach ($sql_fields as $sql_field)
  420. {
  421. $sql_extra .= (empty($sql_extra) ? " WHERE " : " AND ") . $sql_field;
  422. }
  423. if (!empty($sql_extra))
  424. {
  425. $bot_data = array();
  426. $sql = "SELECT s.* FROM " . SESSIONS_TABLE . " s " . $sql_extra . " AND s.session_time > " . ($this->time_now - ((int) $config['session_length'] + (int) SESSION_REFRESH));
  427. $result = $db->sql_query($sql);
  428. $bot_data = $db->sql_fetchrow($result);
  429. $db->sql_freeresult($result);
  430. if (!empty($bot_data))
  431. {
  432. $this->data = array_merge($this->data, $bot_data);
  433. }
  434. }
  435. }
  436. // ICY PHOENIX - END
  437. if (!empty($this->data['session_id']))
  438. {
  439. $this->session_id = $this->data['session_id'];
  440. // Only update session DB a minute or so after last update or if page changes
  441. if ((($this->time_now - $this->data['session_time']) > SESSION_REFRESH) || ($this->update_session_page && ($this->data['session_page'] != $this->page['page'])))
  442. {
  443. $this->data['session_time'] = $this->time_now;
  444. $this->data['session_last_visit'] = $this->time_now;
  445. $this->data['is_registered'] = false;
  446. $this->data['session_logged_in'] = $this->data['is_registered'];
  447. $this->bots_session_gc(false);
  448. }
  449. // Mighty Gorgon: I'm still not sure if I want to keep 'sid=' in Icy Phoenix as well... maybe better removing it!!!
  450. //$SID = 'sid=';
  451. $SID = '';
  452. $_SID = '';
  453. return true;
  454. }
  455. else
  456. {
  457. $this->bots_session_gc(true);
  458. }
  459. }
  460. $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false;
  461. $set_admin = ($set_admin && $this->data['is_registered']) ? true : false;
  462. // Create or update the session
  463. $sql_ary = array(
  464. 'session_user_id' => (int) $this->data['user_id'],
  465. 'session_logged_in' => ($this->data['session_logged_in']) ? 1 : 0,
  466. 'session_start' => (int) $this->time_now,
  467. 'session_last_visit' => (int) $this->data['session_last_visit'],
  468. 'session_time' => (int) $this->time_now,
  469. 'session_browser' => (string) trim(substr($this->browser, 0, 254)),
  470. 'session_forwarded_for' => (string) $this->forwarded_for,
  471. 'session_ip' => (string) $this->ip,
  472. 'session_autologin' => ($session_autologin) ? 1 : 0,
  473. 'session_admin' => ($set_admin) ? 1 : 0,
  474. 'session_viewonline' => ($viewonline) ? 1 : 0,
  475. );
  476. if ($this->update_session_page)
  477. {
  478. $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 254);
  479. $sql_ary['session_forum_id'] = $this->page['forum'];
  480. $sql_ary['session_topic_id'] = $this->page['topic'];
  481. }
  482. $db->sql_return_on_error(true);
  483. $sql = "DELETE
  484. FROM " . SESSIONS_TABLE . "
  485. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
  486. AND session_user_id = " . ANONYMOUS;
  487. if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows()))
  488. {
  489. // Limit new sessions in 1 minute period (if required)
  490. if (empty($this->data['session_time']) && !empty($config['active_sessions']))
  491. {
  492. //$db->sql_return_on_error(false);
  493. $sessions_limit = (int) $config['active_sessions'];
  494. $sessions_limit = ($sessions_limit < 100) ? 100 : $sessions_limit;
  495. $sql = "SELECT COUNT(session_id) AS sessions
  496. FROM " . SESSIONS_TABLE . "
  497. WHERE session_time >= " . ($this->time_now - SESSION_REFRESH);
  498. $result = $db->sql_query($sql);
  499. $row = $db->sql_fetchrow($result);
  500. $db->sql_freeresult($result);
  501. if ((int) $row['sessions'] > $sessions_limit)
  502. {
  503. send_status_line(503, 'Service Unavailable');
  504. trigger_error('Service Unavailable');
  505. }
  506. }
  507. }
  508. // Since we re-create the session id here, the inserted row must be unique. Therefore, we display potential errors.
  509. // Commented out because it will not allow forums to update correctly
  510. // $db->sql_return_on_error(false);
  511. // Something quite important: session_page always holds the *last* page visited, except for the *first* visit.
  512. // We are not able to simply have an empty session_page btw, therefore we need to detect this special case.
  513. // If the session id is empty, we have a completely new one and will set an "identifier" that we can check later if needed.
  514. if (empty($this->data['session_id']))
  515. {
  516. // This is a temporary variable, only set for the very first visit
  517. $this->data['session_created'] = true;
  518. }
  519. $this->session_id = md5(unique_id());
  520. $this->data['session_id'] = $this->session_id;
  521. $sql_ary['session_id'] = (string) $this->session_id;
  522. $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 254);
  523. $sql_ary['session_browser'] = (string) substr($this->browser, 0, 254);
  524. $sql_ary['session_forum_id'] = $this->page['forum'];
  525. $sql_ary['session_topic_id'] = $this->page['topic'];
  526. $sql = "INSERT INTO " . SESSIONS_TABLE . " " . $db->sql_build_array('INSERT', $sql_ary);
  527. $db->sql_query($sql);
  528. $db->sql_return_on_error(false);
  529. // Regenerate autologin/persistent login key
  530. if ($session_autologin)
  531. {
  532. $this->set_login_key();
  533. }
  534. // refresh data
  535. $SID = 'sid=' . $this->session_id;
  536. $_SID = $this->session_id;
  537. $this->data = array_merge($this->data, $sql_ary);
  538. if (empty($this->data['is_bot']))
  539. {
  540. $this->set_cookie('u', $this->cookie_data['u'], $this->cookie_expire);
  541. $this->set_cookie('k', $this->cookie_data['k'], $this->cookie_expire);
  542. $this->set_cookie('sid', $this->session_id, $this->cookie_expire);
  543. $sql = "SELECT COUNT(session_id) AS sessions
  544. FROM " . SESSIONS_TABLE . "
  545. WHERE session_user_id = " . (int) $this->data['user_id'] . "
  546. AND session_time >= " . (int) ($this->time_now - (max($config['session_length'], $config['form_token_lifetime'])));
  547. $result = $db->sql_query($sql);
  548. $row = $db->sql_fetchrow($result);
  549. $db->sql_freeresult($result);
  550. // ICY PHOENIX - BEGIN
  551. $sql_ary = array();
  552. if ($this->data['user_id'] != ANONYMOUS)
  553. {
  554. $this->data['user_totallogon'] = (int) $this->data['user_totallogon'] + 1;
  555. $sql_ary['user_totallogon'] = $this->data['user_totallogon'];
  556. }
  557. if (((int) $row['sessions'] <= 1) || empty($this->data['user_form_salt']))
  558. {
  559. $this->data['user_form_salt'] = unique_id();
  560. $sql_ary['user_form_salt'] = $this->data['user_form_salt'];
  561. }
  562. if (sizeof($sql_ary))
  563. {
  564. $sql = "UPDATE " . USERS_TABLE . " SET " . $db->sql_build_array('UPDATE', $sql_ary) . "
  565. WHERE user_id = " . $this->data['user_id'];
  566. $result = $db->sql_query($sql);
  567. }
  568. // ICY PHOENIX - END
  569. // Start Advanced IP Tools Pack MOD
  570. if (empty($config['disable_logins']) && !empty($this->data['session_logged_in']))
  571. {
  572. $sql_logins_ary = array(
  573. 'login_userid' => $this->data['user_id'],
  574. 'login_ip' => $this->ip,
  575. 'login_user_agent' => substr($this->browser, 0, 254),
  576. 'login_time' => $this->time_now,
  577. );
  578. $db->sql_return_on_error(true);
  579. $sql = "INSERT INTO " . LOGINS_TABLE . " " . $db->sql_build_insert_update($sql_logins_ary, true);
  580. $db->sql_query($sql);
  581. $db->sql_return_on_error(false);
  582. $max_logins = (int) $config['last_logins_n'];
  583. $limit_sql = (!empty($max_logins) && ($max_logins > 0)) ? (" LIMIT 0, " . $max_logins . " ") : "";
  584. $sql = "SELECT login_id FROM " . LOGINS_TABLE . "
  585. WHERE login_userid = " . $this->data['user_id'] . "
  586. ORDER BY login_id DESC" .
  587. $limit_sql;
  588. $result = $db->sql_query($sql);
  589. $user_logins = $db->sql_numrows($result);
  590. $last_logins = $db->sql_fetchrowset($result);
  591. $db->sql_freeresult($result);
  592. if (!empty($user_logins) && ($user_logins > $max_logins))
  593. {
  594. $logins_to_keep = array();
  595. foreach ($last_logins as $login_row)
  596. {
  597. $logins_to_keep[] = $login_row['login_id'];
  598. }
  599. $db->sql_return_on_error(true);
  600. $sql = "DELETE FROM " . LOGINS_TABLE . "
  601. WHERE login_id NOT IN (" . implode(',', $logins_to_keep) . ")
  602. AND login_userid = " . $this->data['user_id'];
  603. $db->sql_query($sql);
  604. $db->sql_return_on_error(false);
  605. }
  606. }
  607. // End Advanced IP Tools Pack MOD
  608. }
  609. else
  610. {
  611. $this->data['session_time'] = $this->time_now;
  612. $this->data['session_last_visit'] = $this->time_now;
  613. // Mighty Gorgon: I'm still not sure if I want to keep 'sid=' in Icy Phoenix as well... maybe better removing it!!!
  614. //$SID = 'sid=';
  615. $SID = '';
  616. $_SID = '';
  617. }
  618. return true;
  619. }
  620. /**
  621. * Kills a session
  622. *
  623. * This method does what it says on the tin. It will delete a pre-existing session.
  624. * It resets cookie information (destroying any autologin key within that cookie data)
  625. * and update the users information from the relevant session data. It will then
  626. * grab guest user information.
  627. */
  628. function session_kill($new_session = true)
  629. {
  630. global $SID, $_SID, $db, $config;
  631. $sql = "DELETE FROM " . SESSIONS_TABLE . "
  632. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
  633. AND session_user_id = " . (int) $this->data['user_id'];
  634. $db->sql_query($sql);
  635. if ($this->data['user_id'] != ANONYMOUS)
  636. {
  637. // Delete existing session, update last visit info first!
  638. if (!isset($this->data['session_time']))
  639. {
  640. $this->data['session_time'] = time();
  641. }
  642. $sql = "UPDATE " . USERS_TABLE . "
  643. SET user_lastvisit = " . (int) $this->data['session_time'] . ", user_private_chat_alert = ''
  644. WHERE user_id = " . (int) $this->data['user_id'];
  645. $db->sql_query($sql);
  646. if ($this->cookie_data['k'])
  647. {
  648. $sql = "DELETE FROM " . SESSIONS_KEYS_TABLE . "
  649. WHERE user_id = " . (int) $this->data['user_id'] . "
  650. AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
  651. $db->sql_query($sql);
  652. }
  653. // Reset the data array
  654. $this->data = array();
  655. $sql = "SELECT *
  656. FROM " . USERS_TABLE . "
  657. WHERE user_id = " . ANONYMOUS;
  658. $result = $db->sql_query($sql);
  659. $this->data = $db->sql_fetchrow($result);
  660. $db->sql_freeresult($result);
  661. }
  662. $cookie_expire = $this->time_now - 31536000;
  663. $this->set_cookie('u', '', $cookie_expire);
  664. $this->set_cookie('k', '', $cookie_expire);
  665. $this->set_cookie('sid', '', $cookie_expire);
  666. unset($cookie_expire);
  667. // Mighty Gorgon: I'm still not sure if I want to keep 'sid=' in Icy Phoenix as well... maybe better removing it!!!
  668. //$SID = 'sid=';
  669. $SID = '';
  670. $_SID = '';
  671. $this->session_id = '';
  672. // To make sure a valid session is created we create one for the anonymous user
  673. if ($new_session)
  674. {
  675. $this->session_create(ANONYMOUS);
  676. }
  677. return true;
  678. }
  679. /**
  680. * Session garbage collection
  681. *
  682. * This looks a lot more complex than it really is. Effectively we are
  683. * deleting any sessions older than an admin definable limit. Due to the
  684. * way in which we maintain session data we have to ensure we update user
  685. * data before those sessions are destroyed. In addition this method
  686. * removes autologin key information that is older than an admin defined
  687. * limit.
  688. */
  689. function session_gc()
  690. {
  691. global $db, $cache, $config;
  692. $batch_size = 10;
  693. if (!$this->time_now)
  694. {
  695. $this->time_now = time();
  696. }
  697. // Set here the desired time you would like to keep sessions...
  698. $session_remove_limit = 86400 * 2;
  699. $session_length = (int) $config['session_length'];
  700. // Remove old keys for users not logging in so frequently... 30 days should be fine!!!
  701. $max_autologin_time = !empty($config['max_autologin_time']) ? $config['max_autologin_time'] : 30;
  702. $sql = "DELETE FROM " . SESSIONS_KEYS_TABLE . "
  703. WHERE last_login < " . ($this->time_now - (86400 * (int) $max_autologin_time));
  704. $db->sql_query($sql);
  705. // Remove all sessions which are X days old from AJAX Chat table
  706. $sql = "DELETE FROM " . AJAX_SHOUTBOX_SESSIONS_TABLE . "
  707. WHERE session_time < " . (int) ($this->time_now - $session_remove_limit);
  708. $db->sql_query($sql);
  709. // Remove all sessions which are X days old from search table
  710. $sql = "DELETE FROM " . SEARCH_TABLE . "
  711. WHERE search_time < " . (int) ($this->time_now - $session_remove_limit);
  712. $db->sql_query($sql);
  713. // Delete Guest sessions which are at least X days old from sessions table (at least one day is needed for statistics)
  714. $sql = "DELETE FROM " . SESSIONS_TABLE . "
  715. WHERE session_user_id = " . ANONYMOUS . "
  716. AND session_time < " . (int) ($this->time_now - $session_length - $session_remove_limit);
  717. $db->sql_query($sql);
  718. // Get expired sessions, only most recent for each user
  719. $sql = "SELECT session_user_id, session_page, MAX(session_time) AS recent_time
  720. FROM " . SESSIONS_TABLE . "
  721. WHERE session_time < " . (int) ($this->time_now - $session_length) . "
  722. GROUP BY session_user_id, session_page";
  723. $result = $db->sql_query_limit($sql, $batch_size);
  724. $del_user_id = array();
  725. $del_sessions = 0;
  726. while ($row = $db->sql_fetchrow($result))
  727. {
  728. $sql = "UPDATE " . USERS_TABLE . "
  729. SET user_lastvisit = " . (int) $row['recent_time'] . ", user_session_page = '" . $db->sql_escape($row['session_page']) . "'
  730. WHERE user_id = " . (int) $row['session_user_id'];
  731. $db->sql_query($sql);
  732. $del_user_id[] = (int) $row['session_user_id'];
  733. $del_sessions++;
  734. }
  735. $db->sql_freeresult($result);
  736. if (sizeof($del_user_id))
  737. {
  738. // Delete expired sessions from more than 2 days (at least one day is needed for statistics)
  739. $sql = "DELETE FROM " . SESSIONS_TABLE . "
  740. WHERE " . $db->sql_in_set('session_user_id', $del_user_id) . "
  741. AND session_time < " . (int) ($this->time_now - $session_length - $session_remove_limit);
  742. $db->sql_query($sql);
  743. }
  744. if ($del_sessions < $batch_size)
  745. {
  746. // Less than 10 users, update gc timer ... else we want gc called again to delete other sessions
  747. set_config('session_last_gc', $this->time_now, true);
  748. set_config('cron_sessions_last_run', $this->time_now, true);
  749. if ($config['max_autologin_time'])
  750. {
  751. $sql = "DELETE FROM " . SESSIONS_KEYS_TABLE . "
  752. WHERE last_login < " . (time() - (86400 * (int) $config['max_autologin_time']));
  753. $db->sql_query($sql);
  754. }
  755. // only called from CRON; should be a safe workaround until the infrastructure gets going
  756. /*
  757. if (!class_exists('phpbb_captcha_factory'))
  758. {
  759. include(IP_ROOT_PATH . 'includes/captcha/captcha_factory.' . PHP_EXT);
  760. }
  761. phpbb_captcha_factory::garbage_collect($config['captcha_plugin']);
  762. */
  763. }
  764. return true;
  765. }
  766. /**
  767. * Bots session garbage collection
  768. *
  769. * This is needed to avoid bots filling up the whole sessions table due to SID removal... this is needed because in Icy Phoenix bots don't have USER_ID but are guests!
  770. */
  771. function bots_session_gc($clear_all = false)
  772. {
  773. global $db, $cache, $config;
  774. if (!$this->time_now)
  775. {
  776. $this->time_now = time();
  777. }
  778. $sql_extra = empty($clear_all) ? (" AND session_id <> '" . $db->sql_escape($this->session_id) . "' ") : '';
  779. if (!empty($this->browser))
  780. {
  781. $u_browser = trim(strtolower(substr($this->browser, 0, 254)));
  782. $sql = "DELETE FROM " . SESSIONS_TABLE . "
  783. WHERE session_browser = '" . $db->sql_escape($u_browser) . "'"
  784. . $sql_extra . "
  785. AND session_user_id = " . ANONYMOUS . "
  786. AND session_time < " . ($this->time_now - ONLINE_REFRESH);
  787. $db->sql_query($sql);
  788. }
  789. if (!empty($this->ip))
  790. {
  791. $sql = "DELETE FROM " . SESSIONS_TABLE . "
  792. WHERE session_ip = '" . $db->sql_escape($this->ip) . "'"
  793. . $sql_extra . "
  794. AND session_user_id = " . ANONYMOUS . "
  795. AND session_time < " . ($this->time_now - ONLINE_REFRESH);
  796. $db->sql_query($sql);
  797. }
  798. }
  799. /**
  800. * Confirm table garbage collection
  801. */
  802. function confirm_gc()
  803. {
  804. global $db, $cache, $config;
  805. // Clean some old sessions first!
  806. $this->session_gc();
  807. // We need to limit this SQL or we may have issue when sessions table has many records
  808. $limit = 2000;
  809. // We also query only those sessions in the last two hours... if a user didn't use its code, maybe he didn't need anymore... ;-)
  810. $sql = "SELECT session_id FROM " . SESSIONS_TABLE . " WHERE session_time > " . (int) (time() - 7200) . " ORDER BY session_time DESC LIMIT " . (int) $limit;
  811. $result = $db->sql_query($sql);
  812. $sessions_ids = $db->sql_fetchrowset($result);
  813. $db->sql_freeresult($result);
  814. if (!empty($sessions_ids))
  815. {
  816. $confirm_sql = '';
  817. foreach ($sessions_ids as $session_id)
  818. {
  819. $confirm_sql .= (!empty($confirm_sql) ? ', ' : '') . "'" . $session_id['session_id'] . "'";
  820. }
  821. $sql = "DELETE FROM " . CONFIRM_TABLE . "
  822. WHERE session_id NOT IN (" . $confirm_sql . ")";
  823. $db->sql_query($sql);
  824. }
  825. return true;
  826. }
  827. /**
  828. * Sets a cookie
  829. *
  830. * Sets a cookie of the given name with the specified data for the given length of time. If no time is specified, a session cookie will be set.
  831. *
  832. * @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then.
  833. * @param string $cookiedata The data to hold within the cookie
  834. * @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set.
  835. */
  836. function set_cookie($name, $cookiedata, $cookietime)
  837. {
  838. global $config;
  839. // Old setcookie version...
  840. //setcookie($config['cookie_name'] . '_' . $name, $cookiedata, $cookietime, $config['cookie_path'], $config['cookie_domain'], $config['cookie_secure']);
  841. $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
  842. $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
  843. $domain = (!$config['cookie_domain'] || ($config['cookie_domain'] == 'localhost') || ($config['cookie_domain'] == '127.0.0.1')) ? '' : '; domain=' . $config['cookie_domain'];
  844. header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
  845. }
  846. /**
  847. * Check for banned user
  848. *
  849. * Checks whether the supplied user is banned by id, ip or email. If no parameters
  850. * are passed to the method pre-existing session data is used. If $return is false
  851. * this routine does not return on finding a banned user, it outputs a relevant
  852. * message and stops execution.
  853. *
  854. * @param string|array $user_ips Can contain a string with one IP or an array of multiple IPs
  855. */
  856. function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
  857. {
  858. global $config, $cache, $db, $lang;
  859. if (defined('IN_CHECK_BAN'))
  860. {
  861. return;
  862. }
  863. $banned = false;
  864. $cache_ttl = 0;
  865. $where_sql = array();
  866. $sql = "SELECT *
  867. FROM " . BANLIST_TABLE . "
  868. WHERE ";
  869. // Determine which entries to check, only return those
  870. if ($user_email === false)
  871. {
  872. $where_sql[] = "(ban_email = '')";
  873. }
  874. if ($user_ips === false)
  875. {
  876. $where_sql[] = "(ban_ip = '')";
  877. }
  878. if ($user_id === false)
  879. {
  880. $where_sql[] = "(ban_userid = 0)";
  881. }
  882. else
  883. {
  884. $cache_ttl = ($user_id == ANONYMOUS) ? 86400 : 0;
  885. $_sql = "(ban_userid = " . $user_id;
  886. if ($user_email !== false)
  887. {
  888. $_sql .= " OR ban_email <> ''";
  889. }
  890. if ($user_ips !== false)
  891. {
  892. $_sql .= " OR ban_ip <> ''";
  893. }
  894. $_sql .= ")";
  895. $where_sql[] = $_sql;
  896. }
  897. $sql .= (sizeof($where_sql)) ? implode(" AND ", $where_sql) : "";
  898. $result = ((defined('CACHE_BAN_INFO') && CACHE_BAN_INFO) || !empty($cache_ttl)) ? $db->sql_query($sql, $cache_ttl, 'ban_', USERS_CACHE_FOLDER) : $db->sql_query($sql);
  899. $ban_triggered_by = 'user';
  900. while ($row = $db->sql_fetchrow($result))
  901. {
  902. if (($row['ban_userid'] == ANONYMOUS) && ($row['ban_ip'] == '') && ($row['ban_email'] == null))
  903. {
  904. $sql = "DELETE FROM " . BANLIST_TABLE . " WHERE ban_userid = '" . ANONYMOUS . "'";
  905. $db->sql_query($sql);
  906. $db->clear_cache('ban_', USERS_CACHE_FOLDER);
  907. continue;
  908. }
  909. if (!empty($row['ban_end']) && ($row['ban_end'] <= time()))
  910. {
  911. $sql = "DELETE FROM " . BANLIST_TABLE . " WHERE ban_id = '" . $row['ban_id'] . "'";
  912. $db->sql_query($sql);
  913. $db->clear_cache('ban_', USERS_CACHE_FOLDER);
  914. continue;
  915. }
  916. $ip_banned = false;
  917. if (!empty($row['ban_ip']))
  918. {
  919. if (!is_array($user_ips))
  920. {
  921. $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips);
  922. }
  923. else
  924. {
  925. foreach ($user_ips as $user_ip)
  926. {
  927. if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip))
  928. {
  929. $ip_banned = true;
  930. break;
  931. }
  932. }
  933. }
  934. }
  935. if ((!empty($row['ban_userid']) && (intval($row['ban_userid']) == $user_id)) || $ip_banned || (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email)))
  936. {
  937. $banned = true;
  938. $ban_row = $row;
  939. if (!empty($row['ban_userid']) && (intval($row['ban_userid']) == $user_id))
  940. {
  941. $ban_triggered_by = 'user';
  942. }
  943. elseif ($ip_banned)
  944. {
  945. $ban_triggered_by = 'ip';
  946. }
  947. else
  948. {
  949. $ban_triggered_by = 'email';
  950. }
  951. break;
  952. }
  953. }
  954. $db->sql_freeresult($result);
  955. if ($banned && !$return)
  956. {
  957. global $template;
  958. // The false here is needed, else the user is able to circumvent the ban.
  959. $this->session_kill(false);
  960. // We need to make sure we have at least the basic lang files included...
  961. if (empty($lang))
  962. {
  963. setup_basic_lang();
  964. }
  965. // A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page
  966. if (defined('IN_CRON'))
  967. {
  968. garbage_collection();
  969. exit_handler();
  970. exit;
  971. }
  972. if (($ban_info['ban_pub_reason_mode'] == '0') || !isset($ban_info['ban_pub_reason_mode']))
  973. {
  974. $reason = $lang['You_been_banned'];
  975. }
  976. elseif ($ban_info['ban_pub_reason_mode'] == '1')
  977. {
  978. $reason = str_replace("\n", '<br />', $ban_info['ban_priv_reason']);
  979. }
  980. elseif ($ban_info['ban_pub_reason_mode'] == '2')
  981. {
  982. $reason = str_replace("\n", '<br />', $ban_info['ban_pub_reason']);
  983. }
  984. $reason = empty($reason) ? $lang['You_been_banned'] : $reason;
  985. message_die(CRITICAL_MESSAGE, $reason);
  986. }
  987. return ($banned && !empty($reason)) ? $reason : $banned;
  988. }
  989. /**
  990. * Check if ip is blacklisted
  991. * This should be called only where absolutly necessary
  992. *
  993. * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups)
  994. *
  995. * @author satmd (from the php manual)
  996. * @param string $mode register/post - spamcop for example is ommitted for posting
  997. * @return false if ip is not blacklisted, else an array([checked server], [lookup])
  998. */
  999. function check_dnsbl($mode, $ip = false)
  1000. {
  1001. global $config;
  1002. if ($ip === false)
  1003. {
  1004. $ip = $this->ip;
  1005. }
  1006. $dnsbl_check = array(
  1007. 'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=',
  1008. );
  1009. if ($mode == 'register')
  1010. {
  1011. $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?';
  1012. }
  1013. if ($ip)
  1014. {
  1015. $quads = explode('.', $ip);
  1016. $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0];
  1017. // Need to be listed on all servers...
  1018. $listed = true;
  1019. $info = array();
  1020. foreach ($dnsbl_check as $dnsbl => $lookup)
  1021. {
  1022. if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true)
  1023. {
  1024. $info = array($dnsbl, $lookup . $ip);
  1025. }
  1026. else
  1027. {
  1028. $listed = false;
  1029. }
  1030. }
  1031. if ($listed)
  1032. {
  1033. return $info;
  1034. }
  1035. }
  1036. return false;
  1037. }
  1038. /**
  1039. * Set/Update a persistent login key
  1040. *
  1041. * This method creates or updates a persistent session key. When a user makes
  1042. * use of persistent (formerly auto-) logins a key is generated and stored in the
  1043. * DB. When they revisit with the same key it's automatically updated in both the
  1044. * DB and cookie. Multiple keys may exist for each user representing different
  1045. * browsers or locations. As with _any_ non-secure-socket no passphrase login this
  1046. * remains vulnerable to exploit.
  1047. */
  1048. function set_login_key($user_id = false, $key = false, $user_ip = false)
  1049. {
  1050. global $config, $db;
  1051. $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
  1052. $user_ip = ($user_ip === false) ? $this->ip : $user_ip;
  1053. $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key;
  1054. $key_id = unique_id(hexdec(substr($this->session_id, 0, 8)));
  1055. $sql_ary = array(
  1056. 'key_id' => (string) md5($key_id),
  1057. 'last_ip' => (string) $this->ip,
  1058. 'last_login' => (int) time()
  1059. );
  1060. if (!$key)
  1061. {
  1062. $sql_ary += array(
  1063. 'user_id' => (int) $user_id
  1064. );
  1065. }
  1066. if ($key)
  1067. {
  1068. $sql = "UPDATE " . SESSIONS_KEYS_TABLE . "
  1069. SET " . $db->sql_build_array('UPDATE', $sql_ary) . "
  1070. WHERE user_id = " . (int) $user_id . "
  1071. AND key_id = '" . $db->sql_escape(md5($key)) . "'";
  1072. }
  1073. else
  1074. {
  1075. $sql = "INSERT INTO " . SESSIONS_KEYS_TABLE . " " . $db->sql_build_array('INSERT', $sql_ary);
  1076. }
  1077. $db->sql_query($sql);
  1078. $this->cookie_data['k'] = $key_id;
  1079. return false;
  1080. }
  1081. /**
  1082. * Reset all login keys for the specified user
  1083. *
  1084. * This method removes all current login keys for a specified (or the current)
  1085. * user. It will be called on password change to render old keys unusable
  1086. */
  1087. function reset_login_keys($user_id = false)
  1088. {
  1089. global $config, $db;
  1090. $user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id;
  1091. $sql = "DELETE FROM " . SESSIONS_KEYS_TABLE . "
  1092. WHERE user_id = " . (int) $user_id;
  1093. $db->sql_query($sql);
  1094. // If the user is logged in, update last visit info first before deleting sessions
  1095. $sql = "SELECT session_time, session_page
  1096. FROM " . SESSIONS_TABLE . "
  1097. WHERE session_user_id = " . (int) $user_id . "
  1098. ORDER BY session_time DESC";
  1099. $result = $db->sql_query_limit($sql, 1);
  1100. $row = $db->sql_fetchrow($result);
  1101. $db->sql_freeresult($result);
  1102. if ($row)
  1103. {
  1104. $sql = "UPDATE " . USERS_TABLE . "
  1105. SET user_lastvisit = " . (int) $row['session_time'] . ", user_session_page = '" . $db->sql_escape($row['session_page']) . "'
  1106. WHERE user_id = " . (int) $user_id;
  1107. $db->sql_query($sql);
  1108. }
  1109. // Let's also clear any current sessions for the specified user_id
  1110. // If it's the current user then we'll leave this session intact
  1111. $sql_where = 'session_user_id = ' . (int) $user_id;
  1112. $sql_where .= ($user_id === (int) $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : '';
  1113. $sql = "DELETE FROM " . SESSIONS_TABLE . "
  1114. WHERE $sql_where";
  1115. $db->sql_query($sql);
  1116. // We're changing the password of the current user and they have a key
  1117. // Lets regenerate it to be safe
  1118. if ($user_id === (int) $this->data['user_id'] && $this->cookie_data['k'])
  1119. {
  1120. $this->set_login_key($user_id);
  1121. }
  1122. }
  1123. /**
  1124. * Check if the request originated from the same page.
  1125. * @param bool $check_script_path If true, the path will be checked as well
  1126. */
  1127. function validate_referer($check_script_path = false)
  1128. {
  1129. global $config;
  1130. // no referer - nothing to validate, user's fault for turning it off (we only check on POST; so meta can't be the reason)
  1131. if (empty($this->referer) || empty($this->host))
  1132. {
  1133. return true;
  1134. }
  1135. $host = htmlspecialchars($this->host);
  1136. $ref = substr($this->referer, strpos($this->referer, '://') + 3);
  1137. if (!(stripos($ref, $host) === 0) && (!$config['force_server_vars'] || !(stripos($ref, $config['server_name']) === 0)))
  1138. {
  1139. return false;
  1140. }
  1141. elseif ($check_script_path && (rtrim($this->page['root_script_path'], '/') !== ''))
  1142. {
  1143. $ref = substr($ref, strlen($host));
  1144. $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT');
  1145. if (($server_port !== 80) && ($server_port !== 443) && (stripos($ref, ":$server_port") === 0))
  1146. {
  1147. $ref = substr($ref, strlen(":$server_port"));
  1148. }
  1149. if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0))
  1150. {
  1151. return false;
  1152. }
  1153. }
  1154. return true;
  1155. }
  1156. function unset_admin()
  1157. {
  1158. global $db;
  1159. $sql = "UPDATE " . SESSIONS_TABLE . "
  1160. SET session_admin = 0
  1161. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
  1162. $db->sql_query($sql);
  1163. }
  1164. /**
  1165. * Bots check...
  1166. */
  1167. function bots_process()
  1168. {
  1169. global $config;
  1170. if (!empty($this->data))
  1171. {
  1172. $this->data['is_bot'] = false;
  1173. $this->data['bot_id'] = false;
  1174. if ($this->data['user_id'] == ANONYMOUS)
  1175. {
  1176. $bot_name_tmp = bots_parse($this->ip, $config['bots_color'], $this->browser, true);
  1177. $this->data['bot_id'] = $bot_name_tmp['name'];
  1178. if ($this->data['bot_id'] !== false)
  1179. {
  1180. $this->data['is_bot'] = true;
  1181. bots_table_update($bot_name_tmp['id']);
  1182. }
  1183. }
  1184. }
  1185. }
  1186. /**
  1187. * Process referers
  1188. */
  1189. function process_referer()
  1190. {
  1191. global $db, $cache, $config;
  1192. if (!empty($this->referer))
  1193. {
  1194. $this_page = $this->page;
  1195. $this_page_url = preg_replace('/(\?)?(&amp;|&)?sid=[a-z0-9]+/', '', $this_page['page_full']);
  1196. $ref_url = $this->referer;
  1197. $ref_url_array = parse_url($ref_url);
  1198. $ref_host = $ref_url_array['host'];
  1199. $ref_process = true;
  1200. if (strpos(strtolower($ref_url), strtolower($this->host . $config['script_path'])) !== false)
  1201. {
  1202. $ref_process = false;
  1203. }
  1204. if (strpos(strtolower($ref_host), str_replace('/', '', strtolower($config['server_name']))) !== false)
  1205. {
  1206. $ref_process = false;
  1207. }
  1208. if (!empty($ref_process))
  1209. {
  1210. include(IP_ROOT_PATH . 'includes/blacklist.' . PHP_EXT);
  1211. if (!empty($blacklist['host']))
  1212. {
  1213. foreach ($blacklist['host'] as $blacklist_entry)
  1214. {
  1215. if (strpos(strtolower($ref_host), strtolower($blacklist_entry)) !== false)
  1216. {
  1217. $ref_process = false;
  1218. break;
  1219. }
  1220. }
  1221. }
  1222. if (!empty($ref_process))
  1223. {
  1224. $sql_where_extra = !empty($this_page_url) ? (" AND t_url = '" . $db->sql_escape($this_page_url) . "' ") : "";
  1225. $sql = "SELECT url FROM " . REFERERS_TABLE . " WHERE url = '" . $db->sql_escape($ref_url) . "'" . $sql_where_extra . " LIMIT 1";
  1226. $result = $db->sql_query($sql);
  1227. $row = $db->sql_fetchrow($result);
  1228. if (empty($row))
  1229. {
  1230. $ref_insert_array = array(
  1231. 'host' => $ref_host,
  1232. 'url' => $ref_url,
  1233. 't_url' => $this_page_url,
  1234. 'ip' => $this->ip,
  1235. 'hits' => 1,
  1236. 'firstvisit' => time(),
  1237. 'lastvisit' => time(),
  1238. );
  1239. $sql = "INSERT INTO " . REFERERS_TABLE . " " . $db->sql_build_insert_update($ref_insert_array, true);
  1240. $result = $db->sql_query($sql);
  1241. }
  1242. else
  1243. {
  1244. $sql = "UPDATE " . REFERERS_TABLE . "
  1245. SET hits = hits + 1, lastvisit = " . time() . ", ip = '" . $db->sql_escape($user_ip) . "'
  1246. WHERE url = '" . $db->sql_escape($ref_url) . "'" . $sql_where_extra;
  1247. $result = $db->sql_query($sql);
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. // UPI2DB - BEGIN
  1254. /**
  1255. * UPI2DB
  1256. */
  1257. function upi2db()
  1258. {
  1259. global $config;
  1260. $this->data['upi2db_access'] = false;
  1261. if (!$config['board_disable'] && $this->data['session_logged_in'] && $config['upi2db_on'])
  1262. {
  1263. $this->data['upi2db_access'] = check_upi2db_on($this->data);
  1264. if ($this->data['upi2db_access'] != false)
  1265. {
  1266. $this->data['always_read'] = select_always_read($this->data);
  1267. $this->data['auth_forum_id'] = auth_forum_read($this->data);
  1268. sync_database($this->data);
  1269. }
  1270. }
  1271. }
  1272. // UPI2DB - END
  1273. }
  1274. /**
  1275. * Base user class
  1276. *
  1277. * This is the overarching class which contains (through session extend)
  1278. * all methods utilised for user functionality during a session.
  1279. *
  1280. * @package phpBB3
  1281. */
  1282. class user extends session
  1283. {
  1284. var $lang = array();
  1285. var $help = array();
  1286. var $theme = array();
  1287. var $date_format;
  1288. var $timezone;
  1289. var $dst;
  1290. var $lang_name = false;
  1291. var $lang_id = false;
  1292. var $lang_path;
  1293. var $img_lang;
  1294. var $i

Large files files are truncated, but you can click here to view the full file