Advertisement
Guest User

Untitled

a guest
Feb 13th, 2012
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 78.25 KB | None | 0 0
  1. <?php
  2. /**
  3. *
  4. * @package phpBB3
  5. * @version $Id$
  6. * @copyright (c) 2005 phpBB Group
  7. * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8. *
  9. */
  10.  
  11. /**
  12. * @ignore
  13. */
  14. if (!defined('IN_PHPBB'))
  15. {
  16. exit;
  17. }
  18.  
  19. /**
  20. * Session class
  21. * @package phpBB3
  22. */
  23. class session
  24. {
  25. var $cookie_data = array();
  26. var $page = array();
  27. var $data = array();
  28. var $browser = '';
  29. var $forwarded_for = '';
  30. var $host = '';
  31. var $session_id = '';
  32. var $ip = '';
  33. var $load = 0;
  34. var $time_now = 0;
  35. var $update_session_page = true;
  36.  
  37. /**
  38. * Extract current session page
  39. *
  40. * @param string $root_path current root path (phpbb_root_path)
  41. */
  42. function extract_current_page($root_path)
  43. {
  44. $page_array = array();
  45.  
  46. // First of all, get the request uri...
  47. $script_name = (!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : getenv('PHP_SELF');
  48. $args = (!empty($_SERVER['QUERY_STRING'])) ? explode('&', $_SERVER['QUERY_STRING']) : explode('&', getenv('QUERY_STRING'));
  49.  
  50. // If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support...
  51. if (!$script_name)
  52. {
  53. $script_name = (!empty($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : getenv('REQUEST_URI');
  54. $script_name = (($pos = strpos($script_name, '?')) !== false) ? substr($script_name, 0, $pos) : $script_name;
  55. $page_array['failover'] = 1;
  56. }
  57.  
  58. // Replace backslashes and doubled slashes (could happen on some proxy setups)
  59. $script_name = str_replace(array('\\', '//'), '/', $script_name);
  60.  
  61. // Now, remove the sid and let us get a clean query string...
  62. $use_args = array();
  63.  
  64. // Since some browser do not encode correctly we need to do this with some "special" characters...
  65. // " -> %22, ' => %27, < -> %3C, > -> %3E
  66. $find = array('"', "'", '<', '>');
  67. $replace = array('%22', '%27', '%3C', '%3E');
  68.  
  69. foreach ($args as $key => $argument)
  70. {
  71. if (strpos($argument, 'sid=') === 0)
  72. {
  73. continue;
  74. }
  75.  
  76. $use_args[] = str_replace($find, $replace, $argument);
  77. }
  78. unset($args);
  79.  
  80. // The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2
  81.  
  82. // The current query string
  83. $query_string = trim(implode('&', $use_args));
  84.  
  85. // basenamed page name (for example: index.php)
  86. $page_name = (substr($script_name, -1, 1) == '/') ? '' : basename($script_name);
  87. $page_name = urlencode(htmlspecialchars($page_name));
  88.  
  89. // current directory within the phpBB root (for example: adm)
  90. $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path)));
  91. $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./')));
  92. $intersection = array_intersect_assoc($root_dirs, $page_dirs);
  93.  
  94. $root_dirs = array_diff_assoc($root_dirs, $intersection);
  95. $page_dirs = array_diff_assoc($page_dirs, $intersection);
  96.  
  97. $page_dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
  98.  
  99. if ($page_dir && substr($page_dir, -1, 1) == '/')
  100. {
  101. $page_dir = substr($page_dir, 0, -1);
  102. }
  103.  
  104. // Current page from phpBB root (for example: adm/index.php?i=10&b=2)
  105. $page = (($page_dir) ? $page_dir . '/' : '') . $page_name . (($query_string) ? "?$query_string" : '');
  106.  
  107. // The script path from the webroot to the current directory (for example: /phpBB3/adm/) : always prefixed with / and ends in /
  108. $script_path = trim(str_replace('\\', '/', dirname($script_name)));
  109.  
  110. // The script path from the webroot to the phpBB root (for example: /phpBB3/)
  111. $script_dirs = explode('/', $script_path);
  112. array_splice($script_dirs, -sizeof($page_dirs));
  113. $root_script_path = implode('/', $script_dirs) . (sizeof($root_dirs) ? '/' . implode('/', $root_dirs) : '');
  114.  
  115. // We are on the base level (phpBB root == webroot), lets adjust the variables a bit...
  116. if (!$root_script_path)
  117. {
  118. $root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path;
  119. }
  120.  
  121. $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/';
  122. $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/';
  123.  
  124. $page_array += array(
  125. 'page_name' => $page_name,
  126. 'page_dir' => $page_dir,
  127.  
  128. 'query_string' => $query_string,
  129. 'script_path' => str_replace(' ', '%20', htmlspecialchars($script_path)),
  130. 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)),
  131.  
  132. 'page' => $page,
  133. 'forum' => (isset($_REQUEST['f']) && $_REQUEST['f'] > 0) ? (int) $_REQUEST['f'] : 0,
  134. );
  135.  
  136. return $page_array;
  137. }
  138.  
  139. /**
  140. * Get valid hostname/port. HTTP_HOST is used, SERVER_NAME if HTTP_HOST not present.
  141. */
  142. function extract_current_hostname()
  143. {
  144. global $config;
  145.  
  146. // Get hostname
  147. $host = (!empty($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME'));
  148.  
  149. // Should be a string and lowered
  150. $host = (string) strtolower($host);
  151.  
  152. // If host is equal the cookie domain or the server name (if config is set), then we assume it is valid
  153. if ((isset($config['cookie_domain']) && $host === $config['cookie_domain']) || (isset($config['server_name']) && $host === $config['server_name']))
  154. {
  155. return $host;
  156. }
  157.  
  158. // Is the host actually a IP? If so, we use the IP... (IPv4)
  159. if (long2ip(ip2long($host)) === $host)
  160. {
  161. return $host;
  162. }
  163.  
  164. // Now return the hostname (this also removes any port definition). The http:// is prepended to construct a valid URL, hosts never have a scheme assigned
  165. $host = @parse_url('http://' . $host);
  166. $host = (!empty($host['host'])) ? $host['host'] : '';
  167.  
  168. // Remove any portions not removed by parse_url (#)
  169. $host = str_replace('#', '', $host);
  170.  
  171. // If, by any means, the host is now empty, we will use a "best approach" way to guess one
  172. if (empty($host))
  173. {
  174. if (!empty($config['server_name']))
  175. {
  176. $host = $config['server_name'];
  177. }
  178. else if (!empty($config['cookie_domain']))
  179. {
  180. $host = (strpos($config['cookie_domain'], '.') === 0) ? substr($config['cookie_domain'], 1) : $config['cookie_domain'];
  181. }
  182. else
  183. {
  184. // Set to OS hostname or localhost
  185. $host = (function_exists('php_uname')) ? php_uname('n') : 'localhost';
  186. }
  187. }
  188.  
  189. // It may be still no valid host, but for sure only a hostname (we may further expand on the cookie domain... if set)
  190. return $host;
  191. }
  192.  
  193. /**
  194. * Start session management
  195. *
  196. * This is where all session activity begins. We gather various pieces of
  197. * information from the client and server. We test to see if a session already
  198. * exists. If it does, fine and dandy. If it doesn't we'll go on to create a
  199. * new one ... pretty logical heh? We also examine the system load (if we're
  200. * running on a system which makes such information readily available) and
  201. * halt if it's above an admin definable limit.
  202. *
  203. * @param bool $update_session_page if true the session page gets updated.
  204. * This can be set to circumvent certain scripts to update the users last visited page.
  205. */
  206. function session_begin($update_session_page = true)
  207. {
  208. global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path;
  209.  
  210. // Give us some basic information
  211. $this->time_now = time();
  212. $this->cookie_data = array('u' => 0, 'k' => '');
  213. $this->update_session_page = $update_session_page;
  214. $this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : '';
  215. $this->referer = (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : '';
  216. $this->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? htmlspecialchars((string) $_SERVER['HTTP_X_FORWARDED_FOR']) : '';
  217.  
  218. $this->host = $this->extract_current_hostname();
  219. $this->page = $this->extract_current_page($phpbb_root_path);
  220.  
  221. // if the forwarded for header shall be checked we have to validate its contents
  222. if ($config['forwarded_for_check'])
  223. {
  224. $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for));
  225.  
  226. // split the list of IPs
  227. $ips = explode(' ', $this->forwarded_for);
  228. foreach ($ips as $ip)
  229. {
  230. // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly
  231. if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip))
  232. {
  233. // contains invalid data, don't use the forwarded for header
  234. $this->forwarded_for = '';
  235. break;
  236. }
  237. }
  238. }
  239. else
  240. {
  241. $this->forwarded_for = '';
  242. }
  243.  
  244. if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u']))
  245. {
  246. $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
  247. $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
  248. $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true);
  249.  
  250. $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';
  251. $_SID = (defined('NEED_SID')) ? $this->session_id : '';
  252.  
  253. if (empty($this->session_id))
  254. {
  255. $this->session_id = $_SID = request_var('sid', '');
  256. $SID = '?sid=' . $this->session_id;
  257. $this->cookie_data = array('u' => 0, 'k' => '');
  258. }
  259. }
  260. else
  261. {
  262. $this->session_id = $_SID = request_var('sid', '');
  263. $SID = '?sid=' . $this->session_id;
  264. }
  265.  
  266. $_EXTRA_URL = array();
  267.  
  268. // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests
  269. // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip.
  270. $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? (string) $_SERVER['REMOTE_ADDR'] : '';
  271. $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip));
  272.  
  273. // split the list of IPs
  274. $ips = explode(' ', trim($this->ip));
  275.  
  276. // Default IP if REMOTE_ADDR is invalid
  277. $this->ip = '127.0.0.1';
  278.  
  279. foreach ($ips as $ip)
  280. {
  281. if (preg_match(get_preg_expression('ipv4'), $ip))
  282. {
  283. $this->ip = $ip;
  284. }
  285. else if (preg_match(get_preg_expression('ipv6'), $ip))
  286. {
  287. // Quick check for IPv4-mapped address in IPv6
  288. if (stripos($ip, '::ffff:') === 0)
  289. {
  290. $ipv4 = substr($ip, 7);
  291.  
  292. if (preg_match(get_preg_expression('ipv4'), $ipv4))
  293. {
  294. $ip = $ipv4;
  295. }
  296. }
  297.  
  298. $this->ip = $ip;
  299. }
  300. else
  301. {
  302. // We want to use the last valid address in the chain
  303. // Leave foreach loop when address is invalid
  304. break;
  305. }
  306. }
  307.  
  308. $this->load = false;
  309.  
  310. // Load limit check (if applicable)
  311. if ($config['limit_load'] || $config['limit_search_load'])
  312. {
  313. if ((function_exists('sys_getloadavg') && $load = sys_getloadavg()) || ($load = explode(' ', @file_get_contents('/proc/loadavg'))))
  314. {
  315. $this->load = array_slice($load, 0, 1);
  316. $this->load = floatval($this->load[0]);
  317. }
  318. else
  319. {
  320. set_config('limit_load', '0');
  321. set_config('limit_search_load', '0');
  322. }
  323. }
  324.  
  325. // Is session_id is set or session_id is set and matches the url param if required
  326. if (!empty($this->session_id) && (!defined('NEED_SID') || (isset($_GET['sid']) && $this->session_id === $_GET['sid'])))
  327. {
  328. $sql = 'SELECT u.*, s.*
  329. FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u
  330. WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "'
  331. AND u.user_id = s.session_user_id";
  332. $result = $db->sql_query($sql);
  333. $this->data = $db->sql_fetchrow($result);
  334. $db->sql_freeresult($result);
  335.  
  336. // Did the session exist in the DB?
  337. if (isset($this->data['user_id']))
  338. {
  339. // Validate IP length according to admin ... enforces an IP
  340. // check on bots if admin requires this
  341. // $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check'];
  342.  
  343. if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
  344. {
  345. $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
  346. $u_ip = short_ipv6($this->ip, $config['ip_check']);
  347. }
  348. else
  349. {
  350. $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
  351. $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
  352. }
  353.  
  354. $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : '';
  355. $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : '';
  356.  
  357. $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
  358. $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';
  359.  
  360. // referer checks
  361. // The @ before $config['referer_validation'] suppresses notices present while running the updater
  362. $check_referer_path = (@$config['referer_validation'] == REFERER_VALIDATE_PATH);
  363. $referer_valid = true;
  364.  
  365. // we assume HEAD and TRACE to be foul play and thus only whitelist GET
  366. if (@$config['referer_validation'] && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) !== 'get')
  367. {
  368. $referer_valid = $this->validate_referer($check_referer_path);
  369. }
  370.  
  371. if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for && $referer_valid)
  372. {
  373. $session_expired = false;
  374.  
  375. // Check whether the session is still valid if we have one
  376. $method = basename(trim($config['auth_method']));
  377. include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
  378.  
  379. $method = 'validate_session_' . $method;
  380. if (function_exists($method))
  381. {
  382. if (!$method($this->data))
  383. {
  384. $session_expired = true;
  385. }
  386. }
  387.  
  388. if (!$session_expired)
  389. {
  390. // Check the session length timeframe if autologin is not enabled.
  391. // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide.
  392. if (!$this->data['session_autologin'])
  393. {
  394. if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60))
  395. {
  396. $session_expired = true;
  397. }
  398. }
  399. else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60))
  400. {
  401. $session_expired = true;
  402. }
  403. }
  404.  
  405. if (!$session_expired)
  406. {
  407. // Only update session DB a minute or so after last update or if page changes
  408. if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
  409. {
  410. $sql_ary = array('session_time' => $this->time_now);
  411.  
  412. if ($this->update_session_page)
  413. {
  414. $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
  415. $sql_ary['session_forum_id'] = $this->page['forum'];
  416. }
  417.  
  418. $db->sql_return_on_error(true);
  419.  
  420. $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
  421. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
  422. $result = $db->sql_query($sql);
  423.  
  424. $db->sql_return_on_error(false);
  425.  
  426. // If the database is not yet updated, there will be an error due to the session_forum_id
  427. // @todo REMOVE for 3.0.2
  428. if ($result === false)
  429. {
  430. unset($sql_ary['session_forum_id']);
  431.  
  432. $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
  433. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
  434. $db->sql_query($sql);
  435. }
  436.  
  437. if ($this->data['user_id'] != ANONYMOUS && !empty($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts'])
  438. {
  439. $this->leave_newly_registered();
  440. }
  441. }
  442.  
  443. $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
  444. $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false;
  445. $this->data['user_lang'] = basename($this->data['user_lang']);
  446.  
  447. return true;
  448. }
  449. }
  450. else
  451. {
  452. // Added logging temporarly to help debug bugs...
  453. if (defined('DEBUG_EXTRA') && $this->data['user_id'] != ANONYMOUS)
  454. {
  455. if ($referer_valid)
  456. {
  457. add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for));
  458. }
  459. else
  460. {
  461. add_log('critical', 'LOG_REFERER_INVALID', $this->referer);
  462. }
  463. }
  464. }
  465. }
  466. }
  467.  
  468. // If we reach here then no (valid) session exists. So we'll create a new one
  469. return $this->session_create();
  470. }
  471.  
  472. /**
  473. * Create a new session
  474. *
  475. * If upon trying to start a session we discover there is nothing existing we
  476. * jump here. Additionally this method is called directly during login to regenerate
  477. * the session for the specific user. In this method we carry out a number of tasks;
  478. * garbage collection, (search)bot checking, banned user comparison. Basically
  479. * though this method will result in a new session for a specific user.
  480. */
  481. function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true)
  482. {
  483. global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx;
  484.  
  485. $this->data = array();
  486.  
  487. /* Garbage collection ... remove old sessions updating user information
  488. // if necessary. It means (potentially) 11 queries but only infrequently
  489. if ($this->time_now > $config['session_last_gc'] + $config['session_gc'])
  490. {
  491. $this->session_gc();
  492. }*/
  493.  
  494. // Do we allow autologin on this board? No? Then override anything
  495. // that may be requested here
  496. if (!$config['allow_autologin'])
  497. {
  498. $this->cookie_data['k'] = $persist_login = false;
  499. }
  500.  
  501. /**
  502. * Here we do a bot check, oh er saucy! No, not that kind of bot
  503. * check. We loop through the list of bots defined by the admin and
  504. * see if we have any useragent and/or IP matches. If we do, this is a
  505. * bot, act accordingly
  506. */
  507. $bot = false;
  508. $active_bots = $cache->obtain_bots();
  509.  
  510. foreach ($active_bots as $row)
  511. {
  512. if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser))
  513. {
  514. $bot = $row['user_id'];
  515. }
  516.  
  517. // If ip is supplied, we will make sure the ip is matching too...
  518. if ($row['bot_ip'] && ($bot || !$row['bot_agent']))
  519. {
  520. // Set bot to false, then we only have to set it to true if it is matching
  521. $bot = false;
  522.  
  523. foreach (explode(',', $row['bot_ip']) as $bot_ip)
  524. {
  525. $bot_ip = trim($bot_ip);
  526.  
  527. if (!$bot_ip)
  528. {
  529. continue;
  530. }
  531.  
  532. if (strpos($this->ip, $bot_ip) === 0)
  533. {
  534. $bot = (int) $row['user_id'];
  535. break;
  536. }
  537. }
  538. }
  539.  
  540. if ($bot)
  541. {
  542. break;
  543. }
  544. }
  545.  
  546. $method = basename(trim($config['auth_method']));
  547. include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
  548.  
  549. $method = 'autologin_' . $method;
  550. if (function_exists($method))
  551. {
  552. $this->data = $method();
  553.  
  554. if (sizeof($this->data))
  555. {
  556. $this->cookie_data['k'] = '';
  557. $this->cookie_data['u'] = $this->data['user_id'];
  558. }
  559. }
  560.  
  561. // If we're presented with an autologin key we'll join against it.
  562. // Else if we've been passed a user_id we'll grab data based on that
  563. if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data))
  564. {
  565. $sql = 'SELECT u.*
  566. FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k
  567. WHERE u.user_id = ' . (int) $this->cookie_data['u'] . '
  568. AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ")
  569. AND k.user_id = u.user_id
  570. AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
  571. $result = $db->sql_query($sql);
  572. $this->data = $db->sql_fetchrow($result);
  573. $db->sql_freeresult($result);
  574. $bot = false;
  575. }
  576. else if ($user_id !== false && !sizeof($this->data))
  577. {
  578. $this->cookie_data['k'] = '';
  579. $this->cookie_data['u'] = $user_id;
  580.  
  581. $sql = 'SELECT *
  582. FROM ' . USERS_TABLE . '
  583. WHERE user_id = ' . (int) $this->cookie_data['u'] . '
  584. AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
  585. $result = $db->sql_query($sql);
  586. $this->data = $db->sql_fetchrow($result);
  587. $db->sql_freeresult($result);
  588. $bot = false;
  589. }
  590.  
  591. // Bot user, if they have a SID in the Request URI we need to get rid of it
  592. // otherwise they'll index this page with the SID, duplicate content oh my!
  593. if ($bot && isset($_GET['sid']))
  594. {
  595. send_status_line(301, 'Moved Permanently');
  596. redirect(build_url(array('sid')));
  597. }
  598.  
  599. // If no data was returned one or more of the following occurred:
  600. // Key didn't match one in the DB
  601. // User does not exist
  602. // User is inactive
  603. // User is bot
  604. if (!sizeof($this->data) || !is_array($this->data))
  605. {
  606. $this->cookie_data['k'] = '';
  607. $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS;
  608.  
  609. if (!$bot)
  610. {
  611. $sql = 'SELECT *
  612. FROM ' . USERS_TABLE . '
  613. WHERE user_id = ' . (int) $this->cookie_data['u'];
  614. }
  615. else
  616. {
  617. // We give bots always the same session if it is not yet expired.
  618. $sql = 'SELECT u.*, s.*
  619. FROM ' . USERS_TABLE . ' u
  620. LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id)
  621. WHERE u.user_id = ' . (int) $bot;
  622. }
  623.  
  624. $result = $db->sql_query($sql);
  625. $this->data = $db->sql_fetchrow($result);
  626. $db->sql_freeresult($result);
  627. }
  628.  
  629. if ($this->data['user_id'] != ANONYMOUS && !$bot)
  630. {
  631. $this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time());
  632. }
  633. else
  634. {
  635. $this->data['session_last_visit'] = $this->time_now;
  636. }
  637.  
  638. // Force user id to be integer...
  639. $this->data['user_id'] = (int) $this->data['user_id'];
  640.  
  641. // At this stage we should have a filled data array, defined cookie u and k data.
  642. // data array should contain recent session info if we're a real user and a recent
  643. // session exists in which case session_id will also be set
  644.  
  645. // Is user banned? Are they excluded? Won't return on ban, exists within method
  646. if ($this->data['user_type'] != USER_FOUNDER)
  647. {
  648. if (!$config['forwarded_for_check'])
  649. {
  650. $this->check_ban($this->data['user_id'], $this->ip);
  651. }
  652. else
  653. {
  654. $ips = explode(' ', $this->forwarded_for);
  655. $ips[] = $this->ip;
  656. $this->check_ban($this->data['user_id'], $ips);
  657. }
  658. }
  659.  
  660. $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
  661. $this->data['is_bot'] = ($bot) ? true : false;
  662.  
  663. // If our friend is a bot, we re-assign a previously assigned session
  664. if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id'])
  665. {
  666. // Only assign the current session if the ip, browser and forwarded_for match...
  667. if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
  668. {
  669. $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
  670. $u_ip = short_ipv6($this->ip, $config['ip_check']);
  671. }
  672. else
  673. {
  674. $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
  675. $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
  676. }
  677.  
  678. $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : '';
  679. $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : '';
  680.  
  681. $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
  682. $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';
  683.  
  684. if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for)
  685. {
  686. $this->session_id = $this->data['session_id'];
  687.  
  688. // Only update session DB a minute or so after last update or if page changes
  689. if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
  690. {
  691. $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
  692.  
  693. $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0);
  694.  
  695. if ($this->update_session_page)
  696. {
  697. $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
  698. $sql_ary['session_forum_id'] = $this->page['forum'];
  699. }
  700.  
  701. $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . "
  702. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'";
  703. $db->sql_query($sql);
  704.  
  705. // Update the last visit time
  706. $sql = 'UPDATE ' . USERS_TABLE . '
  707. SET user_lastvisit = ' . (int) $this->data['session_time'] . '
  708. WHERE user_id = ' . (int) $this->data['user_id'];
  709. $db->sql_query($sql);
  710. }
  711.  
  712. $SID = '?sid=';
  713. $_SID = '';
  714. return true;
  715. }
  716. else
  717. {
  718. // If the ip and browser does not match make sure we only have one bot assigned to one session
  719. $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']);
  720. }
  721. }
  722.  
  723. $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false;
  724. $set_admin = ($set_admin && $this->data['is_registered']) ? true : false;
  725.  
  726. // Create or update the session
  727. $sql_ary = array(
  728. 'session_user_id' => (int) $this->data['user_id'],
  729. 'session_start' => (int) $this->time_now,
  730. 'session_last_visit' => (int) $this->data['session_last_visit'],
  731. 'session_time' => (int) $this->time_now,
  732. 'session_browser' => (string) trim(substr($this->browser, 0, 149)),
  733. 'session_forwarded_for' => (string) $this->forwarded_for,
  734. 'session_ip' => (string) $this->ip,
  735. 'session_autologin' => ($session_autologin) ? 1 : 0,
  736. 'session_admin' => ($set_admin) ? 1 : 0,
  737. 'session_viewonline' => ($viewonline) ? 1 : 0,
  738. );
  739.  
  740. if ($this->update_session_page)
  741. {
  742. $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
  743. $sql_ary['session_forum_id'] = $this->page['forum'];
  744. }
  745.  
  746. $db->sql_return_on_error(true);
  747.  
  748. $sql = 'DELETE
  749. FROM ' . SESSIONS_TABLE . '
  750. WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\'
  751. AND session_user_id = ' . ANONYMOUS;
  752.  
  753. if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows()))
  754. {
  755. // Limit new sessions in 1 minute period (if required)
  756. if (empty($this->data['session_time']) && $config['active_sessions'])
  757. {
  758. // $db->sql_return_on_error(false);
  759.  
  760. $sql = 'SELECT COUNT(session_id) AS sessions
  761. FROM ' . SESSIONS_TABLE . '
  762. WHERE session_time >= ' . ($this->time_now - 60);
  763. $result = $db->sql_query($sql);
  764. $row = $db->sql_fetchrow($result);
  765. $db->sql_freeresult($result);
  766.  
  767. if ((int) $row['sessions'] > (int) $config['active_sessions'])
  768. {
  769. send_status_line(503, 'Service Unavailable');
  770. trigger_error('BOARD_UNAVAILABLE');
  771. }
  772. }
  773. }
  774.  
  775. // Since we re-create the session id here, the inserted row must be unique. Therefore, we display potential errors.
  776. // Commented out because it will not allow forums to update correctly
  777. // $db->sql_return_on_error(false);
  778.  
  779. // Something quite important: session_page always holds the *last* page visited, except for the *first* visit.
  780. // We are not able to simply have an empty session_page btw, therefore we need to tell phpBB how to detect this special case.
  781. // If the session id is empty, we have a completely new one and will set an "identifier" here. This identifier is able to be checked later.
  782. if (empty($this->data['session_id']))
  783. {
  784. // This is a temporary variable, only set for the very first visit
  785. $this->data['session_created'] = true;
  786. }
  787.  
  788. $this->session_id = $this->data['session_id'] = md5(unique_id());
  789.  
  790. $sql_ary['session_id'] = (string) $this->session_id;
  791. $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
  792. $sql_ary['session_forum_id'] = $this->page['forum'];
  793.  
  794. $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
  795. $db->sql_query($sql);
  796.  
  797. $db->sql_return_on_error(false);
  798.  
  799. // Regenerate autologin/persistent login key
  800. if ($session_autologin)
  801. {
  802. $this->set_login_key();
  803. }
  804.  
  805. // refresh data
  806. $SID = '?sid=' . $this->session_id;
  807. $_SID = $this->session_id;
  808. $this->data = array_merge($this->data, $sql_ary);
  809.  
  810. if (!$bot)
  811. {
  812. $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000);
  813.  
  814. $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire);
  815. $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire);
  816. $this->set_cookie('sid', $this->session_id, $cookie_expire);
  817.  
  818. unset($cookie_expire);
  819.  
  820. $sql = 'SELECT COUNT(session_id) AS sessions
  821. FROM ' . SESSIONS_TABLE . '
  822. WHERE session_user_id = ' . (int) $this->data['user_id'] . '
  823. AND session_time >= ' . (int) ($this->time_now - (max($config['session_length'], $config['form_token_lifetime'])));
  824. $result = $db->sql_query($sql);
  825. $row = $db->sql_fetchrow($result);
  826. $db->sql_freeresult($result);
  827.  
  828. if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt']))
  829. {
  830. $this->data['user_form_salt'] = unique_id();
  831. // Update the form key
  832. $sql = 'UPDATE ' . USERS_TABLE . '
  833. SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\'
  834. WHERE user_id = ' . (int) $this->data['user_id'];
  835. $db->sql_query($sql);
  836. }
  837. }
  838. else
  839. {
  840. $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
  841.  
  842. // Update the last visit time
  843. $sql = 'UPDATE ' . USERS_TABLE . '
  844. SET user_lastvisit = ' . (int) $this->data['session_time'] . '
  845. WHERE user_id = ' . (int) $this->data['user_id'];
  846. $db->sql_query($sql);
  847.  
  848. $SID = '?sid=';
  849. $_SID = '';
  850. }
  851.  
  852. return true;
  853. }
  854.  
  855. /**
  856. * Kills a session
  857. *
  858. * This method does what it says on the tin. It will delete a pre-existing session.
  859. * It resets cookie information (destroying any autologin key within that cookie data)
  860. * and update the users information from the relevant session data. It will then
  861. * grab guest user information.
  862. */
  863. function session_kill($new_session = true)
  864. {
  865. global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx;
  866.  
  867. $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
  868. WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
  869. AND session_user_id = " . (int) $this->data['user_id'];
  870. $db->sql_query($sql);
  871.  
  872. // Allow connecting logout with external auth method logout
  873. $method = basename(trim($config['auth_method']));
  874. include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
  875.  
  876. $method = 'logout_' . $method;
  877. if (function_exists($method))
  878. {
  879. $method($this->data, $new_session);
  880. }
  881.  
  882. if ($this->data['user_id'] != ANONYMOUS)
  883. {
  884. // Delete existing session, update last visit info first!
  885. if (!isset($this->data['session_time']))
  886. {
  887. $this->data['session_time'] = time();
  888. }
  889.  
  890. $sql = 'UPDATE ' . USERS_TABLE . '
  891. SET user_lastvisit = ' . (int) $this->data['session_time'] . '
  892. WHERE user_id = ' . (int) $this->data['user_id'];
  893. $db->sql_query($sql);
  894.  
  895. if ($this->cookie_data['k'])
  896. {
  897. $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
  898. WHERE user_id = ' . (int) $this->data['user_id'] . "
  899. AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
  900. $db->sql_query($sql);
  901. }
  902.  
  903. // Reset the data array
  904. $this->data = array();
  905.  
  906. $sql = 'SELECT *
  907. FROM ' . USERS_TABLE . '
  908. WHERE user_id = ' . ANONYMOUS;
  909. $result = $db->sql_query($sql);
  910. $this->data = $db->sql_fetchrow($result);
  911. $db->sql_freeresult($result);
  912. }
  913.  
  914. $cookie_expire = $this->time_now - 31536000;
  915. $this->set_cookie('u', '', $cookie_expire);
  916. $this->set_cookie('k', '', $cookie_expire);
  917. $this->set_cookie('sid', '', $cookie_expire);
  918. unset($cookie_expire);
  919.  
  920. $SID = '?sid=';
  921. $this->session_id = $_SID = '';
  922.  
  923. // To make sure a valid session is created we create one for the anonymous user
  924. if ($new_session)
  925. {
  926. $this->session_create(ANONYMOUS);
  927. }
  928.  
  929. return true;
  930. }
  931.  
  932. /**
  933. * Session garbage collection
  934. *
  935. * This looks a lot more complex than it really is. Effectively we are
  936. * deleting any sessions older than an admin definable limit. Due to the
  937. * way in which we maintain session data we have to ensure we update user
  938. * data before those sessions are destroyed. In addition this method
  939. * removes autologin key information that is older than an admin defined
  940. * limit.
  941. */
  942. function session_gc()
  943. {
  944. global $db, $config, $phpbb_root_path, $phpEx;
  945.  
  946. $batch_size = 10;
  947.  
  948. if (!$this->time_now)
  949. {
  950. $this->time_now = time();
  951. }
  952.  
  953. // Firstly, delete guest sessions
  954. $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
  955. WHERE session_user_id = ' . ANONYMOUS . '
  956. AND session_time < ' . (int) ($this->time_now - $config['session_length']);
  957. $db->sql_query($sql);
  958.  
  959. // Get expired sessions, only most recent for each user
  960. $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time
  961. FROM ' . SESSIONS_TABLE . '
  962. WHERE session_time < ' . ($this->time_now - $config['session_length']) . '
  963. GROUP BY session_user_id, session_page';
  964. $result = $db->sql_query_limit($sql, $batch_size);
  965.  
  966. $del_user_id = array();
  967. $del_sessions = 0;
  968.  
  969. while ($row = $db->sql_fetchrow($result))
  970. {
  971. $sql = 'UPDATE ' . USERS_TABLE . '
  972. SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "'
  973. WHERE user_id = " . (int) $row['session_user_id'];
  974. $db->sql_query($sql);
  975.  
  976. $del_user_id[] = (int) $row['session_user_id'];
  977. $del_sessions++;
  978. }
  979. $db->sql_freeresult($result);
  980.  
  981. if (sizeof($del_user_id))
  982. {
  983. // Delete expired sessions
  984. $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
  985. WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . '
  986. AND session_time < ' . ($this->time_now - $config['session_length']);
  987. $db->sql_query($sql);
  988. }
  989.  
  990. if ($del_sessions < $batch_size)
  991. {
  992. // Less than 10 users, update gc timer ... else we want gc
  993. // called again to delete other sessions
  994. set_config('session_last_gc', $this->time_now, true);
  995.  
  996. if ($config['max_autologin_time'])
  997. {
  998. $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
  999. WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time']));
  1000. $db->sql_query($sql);
  1001. }
  1002.  
  1003. // only called from CRON; should be a safe workaround until the infrastructure gets going
  1004. if (!class_exists('phpbb_captcha_factory'))
  1005. {
  1006. include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx);
  1007. }
  1008. phpbb_captcha_factory::garbage_collect($config['captcha_plugin']);
  1009.  
  1010. $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
  1011. WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']);
  1012. $db->sql_query($sql);
  1013. }
  1014.  
  1015. return;
  1016. }
  1017.  
  1018. /**
  1019. * Sets a cookie
  1020. *
  1021. * 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.
  1022. *
  1023. * @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then.
  1024. * @param string $cookiedata The data to hold within the cookie
  1025. * @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set.
  1026. */
  1027. function set_cookie($name, $cookiedata, $cookietime)
  1028. {
  1029. global $config;
  1030.  
  1031. $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
  1032. $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
  1033. $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
  1034.  
  1035. header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
  1036. }
  1037.  
  1038. /**
  1039. * Check for banned user
  1040. *
  1041. * Checks whether the supplied user is banned by id, ip or email. If no parameters
  1042. * are passed to the method pre-existing session data is used. If $return is false
  1043. * this routine does not return on finding a banned user, it outputs a relevant
  1044. * message and stops execution.
  1045. *
  1046. * @param string|array $user_ips Can contain a string with one IP or an array of multiple IPs
  1047. */
  1048. function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
  1049. {
  1050. global $config, $db;
  1051.  
  1052. if (defined('IN_CHECK_BAN'))
  1053. {
  1054. return;
  1055. }
  1056.  
  1057. $banned = false;
  1058. $cache_ttl = 3600;
  1059. $where_sql = array();
  1060.  
  1061. $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end
  1062. FROM ' . BANLIST_TABLE . '
  1063. WHERE ';
  1064.  
  1065. // Determine which entries to check, only return those
  1066. if ($user_email === false)
  1067. {
  1068. $where_sql[] = "ban_email = ''";
  1069. }
  1070.  
  1071. if ($user_ips === false)
  1072. {
  1073. $where_sql[] = "(ban_ip = '' OR ban_exclude = 1)";
  1074. }
  1075.  
  1076. if ($user_id === false)
  1077. {
  1078. $where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)';
  1079. }
  1080. else
  1081. {
  1082. $cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0;
  1083. $_sql = '(ban_userid = ' . $user_id;
  1084.  
  1085. if ($user_email !== false)
  1086. {
  1087. $_sql .= " OR ban_email <> ''";
  1088. }
  1089.  
  1090. if ($user_ips !== false)
  1091. {
  1092. $_sql .= " OR ban_ip <> ''";
  1093. }
  1094.  
  1095. $_sql .= ')';
  1096.  
  1097. $where_sql[] = $_sql;
  1098. }
  1099.  
  1100. $sql .= (sizeof($where_sql)) ? implode(' AND ', $where_sql) : '';
  1101. $result = $db->sql_query($sql, $cache_ttl);
  1102.  
  1103. $ban_triggered_by = 'user';
  1104. while ($row = $db->sql_fetchrow($result))
  1105. {
  1106. if ($row['ban_end'] && $row['ban_end'] < time())
  1107. {
  1108. continue;
  1109. }
  1110.  
  1111. $ip_banned = false;
  1112. if (!empty($row['ban_ip']))
  1113. {
  1114. if (!is_array($user_ips))
  1115. {
  1116. $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips);
  1117. }
  1118. else
  1119. {
  1120. foreach ($user_ips as $user_ip)
  1121. {
  1122. if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip))
  1123. {
  1124. $ip_banned = true;
  1125. break;
  1126. }
  1127. }
  1128. }
  1129. }
  1130.  
  1131. if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) ||
  1132. $ip_banned ||
  1133. (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email)))
  1134. {
  1135. if (!empty($row['ban_exclude']))
  1136. {
  1137. $banned = false;
  1138. break;
  1139. }
  1140. else
  1141. {
  1142. $banned = true;
  1143. $ban_row = $row;
  1144.  
  1145. if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id)
  1146. {
  1147. $ban_triggered_by = 'user';
  1148. }
  1149. else if ($ip_banned)
  1150. {
  1151. $ban_triggered_by = 'ip';
  1152. }
  1153. else
  1154. {
  1155. $ban_triggered_by = 'email';
  1156. }
  1157.  
  1158. // Don't break. Check if there is an exclude rule for this user
  1159. }
  1160. }
  1161. }
  1162. $db->sql_freeresult($result);
  1163.  
  1164. if ($banned && !$return)
  1165. {
  1166. global $template;
  1167.  
  1168. // If the session is empty we need to create a valid one...
  1169. if (empty($this->session_id))
  1170. {
  1171. // This seems to be no longer needed? - #14971
  1172. // $this->session_create(ANONYMOUS);
  1173. }
  1174.  
  1175. // Initiate environment ... since it won't be set at this stage
  1176. $this->setup();
  1177.  
  1178. // Logout the user, banned users are unable to use the normal 'logout' link
  1179. if ($this->data['user_id'] != ANONYMOUS)
  1180. {
  1181. $this->session_kill();
  1182. }
  1183.  
  1184. // We show a login box here to allow founders accessing the board if banned by IP
  1185. if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS)
  1186. {
  1187. global $phpEx;
  1188.  
  1189. $this->setup('ucp');
  1190. $this->data['is_registered'] = $this->data['is_bot'] = false;
  1191.  
  1192. // Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again.
  1193. define('IN_CHECK_BAN', 1);
  1194.  
  1195. login_box("index.$phpEx");
  1196.  
  1197. // The false here is needed, else the user is able to circumvent the ban.
  1198. $this->session_kill(false);
  1199. }
  1200.  
  1201. // Ok, we catch the case of an empty session id for the anonymous user...
  1202. // This can happen if the user is logging in, banned by username and the login_box() being called "again".
  1203. if (empty($this->session_id) && defined('IN_CHECK_BAN'))
  1204. {
  1205. $this->session_create(ANONYMOUS);
  1206. }
  1207.  
  1208.  
  1209. // Determine which message to output
  1210. $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : '';
  1211. $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
  1212.  
  1213. $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>');
  1214. $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : '';
  1215. $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>';
  1216.  
  1217. // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again
  1218. $this->session_kill(false);
  1219.  
  1220. // A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page
  1221. if (defined('IN_CRON'))
  1222. {
  1223. garbage_collection();
  1224. exit_handler();
  1225. exit;
  1226. }
  1227.  
  1228. trigger_error($message);
  1229. }
  1230.  
  1231. return ($banned && $ban_row['ban_give_reason']) ? $ban_row['ban_give_reason'] : $banned;
  1232. }
  1233.  
  1234. /**
  1235. * Check if ip is blacklisted
  1236. * This should be called only where absolutly necessary
  1237. *
  1238. * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups)
  1239. *
  1240. * @author satmd (from the php manual)
  1241. * @param string $mode register/post - spamcop for example is ommitted for posting
  1242. * @return false if ip is not blacklisted, else an array([checked server], [lookup])
  1243. */
  1244. function check_dnsbl($mode, $ip = false)
  1245. {
  1246. if ($ip === false)
  1247. {
  1248. $ip = $this->ip;
  1249. }
  1250.  
  1251. // Neither Spamhaus nor Spamcop supports IPv6 addresses.
  1252. if (strpos($ip, ':') !== false)
  1253. {
  1254. return false;
  1255. }
  1256.  
  1257. $dnsbl_check = array(
  1258. 'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=',
  1259. );
  1260.  
  1261. if ($mode == 'register')
  1262. {
  1263. $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?';
  1264. }
  1265.  
  1266. if ($ip)
  1267. {
  1268. $quads = explode('.', $ip);
  1269. $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0];
  1270.  
  1271. // Need to be listed on all servers...
  1272. $listed = true;
  1273. $info = array();
  1274.  
  1275. foreach ($dnsbl_check as $dnsbl => $lookup)
  1276. {
  1277. if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true)
  1278. {
  1279. $info = array($dnsbl, $lookup . $ip);
  1280. }
  1281. else
  1282. {
  1283. $listed = false;
  1284. }
  1285. }
  1286.  
  1287. if ($listed)
  1288. {
  1289. return $info;
  1290. }
  1291. }
  1292.  
  1293. return false;
  1294. }
  1295.  
  1296. /**
  1297. * Check if URI is blacklisted
  1298. * This should be called only where absolutly necessary, for example on the submitted website field
  1299. * This function is not in use at the moment and is only included for testing purposes, it may not work at all!
  1300. * This means it is untested at the moment and therefore commented out
  1301. *
  1302. * @param string $uri URI to check
  1303. * @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists
  1304. function check_uribl($uri)
  1305. {
  1306. // Normally parse_url() is not intended to parse uris
  1307. // We need to get the top-level domain name anyway... change.
  1308. $uri = parse_url($uri);
  1309.  
  1310. if ($uri === false || empty($uri['host']))
  1311. {
  1312. return false;
  1313. }
  1314.  
  1315. $uri = trim($uri['host']);
  1316.  
  1317. if ($uri)
  1318. {
  1319. // One problem here... the return parameter for the "windows" method is different from what
  1320. // we expect... this may render this check useless...
  1321. if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true)
  1322. {
  1323. return true;
  1324. }
  1325. }
  1326.  
  1327. return false;
  1328. }
  1329. */
  1330.  
  1331. /**
  1332. * Set/Update a persistent login key
  1333. *
  1334. * This method creates or updates a persistent session key. When a user makes
  1335. * use of persistent (formerly auto-) logins a key is generated and stored in the
  1336. * DB. When they revisit with the same key it's automatically updated in both the
  1337. * DB and cookie. Multiple keys may exist for each user representing different
  1338. * browsers or locations. As with _any_ non-secure-socket no passphrase login this
  1339. * remains vulnerable to exploit.
  1340. */
  1341. function set_login_key($user_id = false, $key = false, $user_ip = false)
  1342. {
  1343. global $config, $db;
  1344.  
  1345. $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
  1346. $user_ip = ($user_ip === false) ? $this->ip : $user_ip;
  1347. $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key;
  1348.  
  1349. $key_id = unique_id(hexdec(substr($this->session_id, 0, 8)));
  1350.  
  1351. $sql_ary = array(
  1352. 'key_id' => (string) md5($key_id),
  1353. 'last_ip' => (string) $this->ip,
  1354. 'last_login' => (int) time()
  1355. );
  1356.  
  1357. if (!$key)
  1358. {
  1359. $sql_ary += array(
  1360. 'user_id' => (int) $user_id
  1361. );
  1362. }
  1363.  
  1364. if ($key)
  1365. {
  1366. $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . '
  1367. SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
  1368. WHERE user_id = ' . (int) $user_id . "
  1369. AND key_id = '" . $db->sql_escape(md5($key)) . "'";
  1370. }
  1371. else
  1372. {
  1373. $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
  1374. }
  1375. $db->sql_query($sql);
  1376.  
  1377. $this->cookie_data['k'] = $key_id;
  1378.  
  1379. return false;
  1380. }
  1381.  
  1382. /**
  1383. * Reset all login keys for the specified user
  1384. *
  1385. * This method removes all current login keys for a specified (or the current)
  1386. * user. It will be called on password change to render old keys unusable
  1387. */
  1388. function reset_login_keys($user_id = false)
  1389. {
  1390. global $config, $db;
  1391.  
  1392. $user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id;
  1393.  
  1394. $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
  1395. WHERE user_id = ' . (int) $user_id;
  1396. $db->sql_query($sql);
  1397.  
  1398. // If the user is logged in, update last visit info first before deleting sessions
  1399. $sql = 'SELECT session_time, session_page
  1400. FROM ' . SESSIONS_TABLE . '
  1401. WHERE session_user_id = ' . (int) $user_id . '
  1402. ORDER BY session_time DESC';
  1403. $result = $db->sql_query_limit($sql, 1);
  1404. $row = $db->sql_fetchrow($result);
  1405. $db->sql_freeresult($result);
  1406.  
  1407. if ($row)
  1408. {
  1409. $sql = 'UPDATE ' . USERS_TABLE . '
  1410. SET user_lastvisit = ' . (int) $row['session_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "'
  1411. WHERE user_id = " . (int) $user_id;
  1412. $db->sql_query($sql);
  1413. }
  1414.  
  1415. // Let's also clear any current sessions for the specified user_id
  1416. // If it's the current user then we'll leave this session intact
  1417. $sql_where = 'session_user_id = ' . (int) $user_id;
  1418. $sql_where .= ($user_id === (int) $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : '';
  1419.  
  1420. $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
  1421. WHERE $sql_where";
  1422. $db->sql_query($sql);
  1423.  
  1424. // We're changing the password of the current user and they have a key
  1425. // Lets regenerate it to be safe
  1426. if ($user_id === (int) $this->data['user_id'] && $this->cookie_data['k'])
  1427. {
  1428. $this->set_login_key($user_id);
  1429. }
  1430. }
  1431.  
  1432.  
  1433. /**
  1434. * Check if the request originated from the same page.
  1435. * @param bool $check_script_path If true, the path will be checked as well
  1436. */
  1437. function validate_referer($check_script_path = false)
  1438. {
  1439. global $config;
  1440.  
  1441. // no referer - nothing to validate, user's fault for turning it off (we only check on POST; so meta can't be the reason)
  1442. if (empty($this->referer) || empty($this->host))
  1443. {
  1444. return true;
  1445. }
  1446.  
  1447. $host = htmlspecialchars($this->host);
  1448. $ref = substr($this->referer, strpos($this->referer, '://') + 3);
  1449.  
  1450. if (!(stripos($ref, $host) === 0) && (!$config['force_server_vars'] || !(stripos($ref, $config['server_name']) === 0)))
  1451. {
  1452. return false;
  1453. }
  1454. else if ($check_script_path && rtrim($this->page['root_script_path'], '/') !== '')
  1455. {
  1456. $ref = substr($ref, strlen($host));
  1457. $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT');
  1458.  
  1459. if ($server_port !== 80 && $server_port !== 443 && stripos($ref, ":$server_port") === 0)
  1460. {
  1461. $ref = substr($ref, strlen(":$server_port"));
  1462. }
  1463.  
  1464. if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0))
  1465. {
  1466. return false;
  1467. }
  1468. }
  1469.  
  1470. return true;
  1471. }
  1472.  
  1473.  
  1474. function unset_admin()
  1475. {
  1476. global $db;
  1477. $sql = 'UPDATE ' . SESSIONS_TABLE . '
  1478. SET session_admin = 0
  1479. WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\'';
  1480. $db->sql_query($sql);
  1481. }
  1482. }
  1483.  
  1484.  
  1485. /**
  1486. * Base user class
  1487. *
  1488. * This is the overarching class which contains (through session extend)
  1489. * all methods utilised for user functionality during a session.
  1490. *
  1491. * @package phpBB3
  1492. */
  1493. class user extends session
  1494. {
  1495. var $lang = array();
  1496. var $help = array();
  1497. var $theme = array();
  1498. var $date_format;
  1499. var $timezone;
  1500. var $dst;
  1501.  
  1502. var $lang_name = false;
  1503. var $lang_id = false;
  1504. var $lang_path;
  1505. var $img_lang;
  1506. var $img_array = array();
  1507.  
  1508. // Able to add new options (up to id 31)
  1509. var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10, 'sig_bbcode' => 15, 'sig_smilies' => 16, 'sig_links' => 17);
  1510. var $keyvalues = array();
  1511.  
  1512. /**
  1513. * Constructor to set the lang path
  1514. */
  1515. function user()
  1516. {
  1517. global $phpbb_root_path;
  1518.  
  1519. $this->lang_path = $phpbb_root_path . 'language/';
  1520. }
  1521.  
  1522. /**
  1523. * Function to set custom language path (able to use directory outside of phpBB)
  1524. *
  1525. * @param string $lang_path New language path used.
  1526. * @access public
  1527. */
  1528. function set_custom_lang_path($lang_path)
  1529. {
  1530. $this->lang_path = $lang_path;
  1531.  
  1532. if (substr($this->lang_path, -1) != '/')
  1533. {
  1534. $this->lang_path .= '/';
  1535. }
  1536. }
  1537.  
  1538. /**
  1539. * Setup basic user-specific items (style, language, ...)
  1540. */
  1541. function setup($lang_set = false, $style = false)
  1542. {
  1543. global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
  1544.  
  1545. if ($this->data['user_id'] != ANONYMOUS)
  1546. {
  1547. $this->lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
  1548.  
  1549. $this->date_format = $this->data['user_dateformat'];
  1550. $this->timezone = $this->data['user_timezone'] * 3600;
  1551. $this->dst = $this->data['user_dst'] * 3600;
  1552. }
  1553. else
  1554. {
  1555. $this->lang_name = basename($config['default_lang']);
  1556. $this->date_format = $config['default_dateformat'];
  1557. $this->timezone = $config['board_timezone'] * 3600;
  1558. $this->dst = $config['board_dst'] * 3600;
  1559.  
  1560. /**
  1561. * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language
  1562. * If re-enabled we need to make sure only those languages installed are checked
  1563. * Commented out so we do not loose the code.
  1564.  
  1565. if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
  1566. {
  1567. $accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
  1568.  
  1569. foreach ($accept_lang_ary as $accept_lang)
  1570. {
  1571. // Set correct format ... guess full xx_YY form
  1572. $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2));
  1573. $accept_lang = basename($accept_lang);
  1574.  
  1575. if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx"))
  1576. {
  1577. $this->lang_name = $config['default_lang'] = $accept_lang;
  1578. break;
  1579. }
  1580. else
  1581. {
  1582. // No match on xx_YY so try xx
  1583. $accept_lang = substr($accept_lang, 0, 2);
  1584. $accept_lang = basename($accept_lang);
  1585.  
  1586. if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx"))
  1587. {
  1588. $this->lang_name = $config['default_lang'] = $accept_lang;
  1589. break;
  1590. }
  1591. }
  1592. }
  1593. }
  1594. */
  1595. }
  1596.  
  1597. // We include common language file here to not load it every time a custom language file is included
  1598. $lang = &$this->lang;
  1599.  
  1600. // Do not suppress error if in DEBUG_EXTRA mode
  1601. $include_result = (defined('DEBUG_EXTRA')) ? (include $this->lang_path . $this->lang_name . "/common.$phpEx") : (@include $this->lang_path . $this->lang_name . "/common.$phpEx");
  1602.  
  1603. if ($include_result === false)
  1604. {
  1605. die('Language file ' . $this->lang_path . $this->lang_name . "/common.$phpEx" . " couldn't be opened.");
  1606. }
  1607.  
  1608. $this->add_lang($lang_set);
  1609. unset($lang_set);
  1610.  
  1611. if (!empty($_GET['style']) && $auth->acl_get('a_styles') && !defined('ADMIN_START'))
  1612. {
  1613. global $SID, $_EXTRA_URL;
  1614.  
  1615. $style = request_var('style', 0);
  1616. $SID .= '&amp;style=' . $style;
  1617. $_EXTRA_URL = array('style=' . $style);
  1618. }
  1619. else
  1620. {
  1621. // Set up style
  1622. $style = ($style) ? $style : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']);
  1623. }
  1624.  
  1625. $sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, t.template_inherits_id, t.template_inherit_path, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name
  1626. FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i
  1627. WHERE s.style_id = $style
  1628. AND t.template_id = s.template_id
  1629. AND c.theme_id = s.theme_id
  1630. AND i.imageset_id = s.imageset_id";
  1631. $result = $db->sql_query($sql, 3600);
  1632. $this->theme = $db->sql_fetchrow($result);
  1633. $db->sql_freeresult($result);
  1634.  
  1635. // User has wrong style
  1636. if (!$this->theme && $style == $this->data['user_style'])
  1637. {
  1638. $style = $this->data['user_style'] = $config['default_style'];
  1639.  
  1640. $sql = 'UPDATE ' . USERS_TABLE . "
  1641. SET user_style = $style
  1642. WHERE user_id = {$this->data['user_id']}";
  1643. $db->sql_query($sql);
  1644.  
  1645. $sql = 'SELECT s.style_id, t.template_storedb, t.template_path, t.template_id, t.bbcode_bitfield, c.theme_path, c.theme_name, c.theme_storedb, c.theme_id, i.imageset_path, i.imageset_id, i.imageset_name
  1646. FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . ' t, ' . STYLES_THEME_TABLE . ' c, ' . STYLES_IMAGESET_TABLE . " i
  1647. WHERE s.style_id = $style
  1648. AND t.template_id = s.template_id
  1649. AND c.theme_id = s.theme_id
  1650. AND i.imageset_id = s.imageset_id";
  1651. $result = $db->sql_query($sql, 3600);
  1652. $this->theme = $db->sql_fetchrow($result);
  1653. $db->sql_freeresult($result);
  1654. }
  1655.  
  1656. if (!$this->theme)
  1657. {
  1658. trigger_error('Could not get style data', E_USER_ERROR);
  1659. }
  1660.  
  1661. // Now parse the cfg file and cache it
  1662. $parsed_items = $cache->obtain_cfg_items($this->theme);
  1663.  
  1664. // We are only interested in the theme configuration for now
  1665. $parsed_items = $parsed_items['theme'];
  1666.  
  1667. $check_for = array(
  1668. 'parse_css_file' => (int) 0,
  1669. 'pagination_sep' => (string) ', '
  1670. );
  1671.  
  1672. foreach ($check_for as $key => $default_value)
  1673. {
  1674. $this->theme[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value;
  1675. settype($this->theme[$key], gettype($default_value));
  1676.  
  1677. if (is_string($default_value))
  1678. {
  1679. $this->theme[$key] = htmlspecialchars($this->theme[$key]);
  1680. }
  1681. }
  1682.  
  1683. // If the style author specified the theme needs to be cached
  1684. // (because of the used paths and variables) than make sure it is the case.
  1685. // For example, if the theme uses language-specific images it needs to be stored in db.
  1686. if (!$this->theme['theme_storedb'] && $this->theme['parse_css_file'])
  1687. {
  1688. $this->theme['theme_storedb'] = 1;
  1689.  
  1690. $stylesheet = file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/stylesheet.css");
  1691. // Match CSS imports
  1692. $matches = array();
  1693. preg_match_all('/@import url\(["\'](.*)["\']\);/i', $stylesheet, $matches);
  1694.  
  1695. if (sizeof($matches))
  1696. {
  1697. $content = '';
  1698. foreach ($matches[0] as $idx => $match)
  1699. {
  1700. if ($content = @file_get_contents("{$phpbb_root_path}styles/{$this->theme['theme_path']}/theme/" . $matches[1][$idx]))
  1701. {
  1702. $content = trim($content);
  1703. }
  1704. else
  1705. {
  1706. $content = '';
  1707. }
  1708. $stylesheet = str_replace($match, $content, $stylesheet);
  1709. }
  1710. unset($content);
  1711. }
  1712.  
  1713. $stylesheet = str_replace('./', 'styles/' . $this->theme['theme_path'] . '/theme/', $stylesheet);
  1714.  
  1715. $sql_ary = array(
  1716. 'theme_data' => $stylesheet,
  1717. 'theme_mtime' => time(),
  1718. 'theme_storedb' => 1
  1719. );
  1720.  
  1721. $sql = 'UPDATE ' . STYLES_THEME_TABLE . '
  1722. SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
  1723. WHERE theme_id = ' . $this->theme['theme_id'];
  1724. $db->sql_query($sql);
  1725.  
  1726. unset($sql_ary);
  1727. }
  1728.  
  1729. $template->set_template();
  1730.  
  1731. $this->img_lang = (file_exists($phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . $this->lang_name)) ? $this->lang_name : $config['default_lang'];
  1732.  
  1733. // Same query in style.php
  1734. $sql = 'SELECT *
  1735. FROM ' . STYLES_IMAGESET_DATA_TABLE . '
  1736. WHERE imageset_id = ' . $this->theme['imageset_id'] . "
  1737. AND image_filename <> ''
  1738. AND image_lang IN ('" . $db->sql_escape($this->img_lang) . "', '')";
  1739. $result = $db->sql_query($sql, 3600);
  1740.  
  1741. $localised_images = false;
  1742. while ($row = $db->sql_fetchrow($result))
  1743. {
  1744. if ($row['image_lang'])
  1745. {
  1746. $localised_images = true;
  1747. }
  1748.  
  1749. $row['image_filename'] = rawurlencode($row['image_filename']);
  1750. $this->img_array[$row['image_name']] = $row;
  1751. }
  1752. $db->sql_freeresult($result);
  1753.  
  1754. // there were no localised images, try to refresh the localised imageset for the user's language
  1755. if (!$localised_images)
  1756. {
  1757. // Attention: this code ignores the image definition list from acp_styles and just takes everything
  1758. // that the config file contains
  1759. $sql_ary = array();
  1760.  
  1761. $db->sql_transaction('begin');
  1762.  
  1763. $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . '
  1764. WHERE imageset_id = ' . $this->theme['imageset_id'] . '
  1765. AND image_lang = \'' . $db->sql_escape($this->img_lang) . '\'';
  1766. $result = $db->sql_query($sql);
  1767.  
  1768. if (@file_exists("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg"))
  1769. {
  1770. $cfg_data_imageset_data = parse_cfg_file("{$phpbb_root_path}styles/{$this->theme['imageset_path']}/imageset/{$this->img_lang}/imageset.cfg");
  1771. foreach ($cfg_data_imageset_data as $image_name => $value)
  1772. {
  1773. if (strpos($value, '*') !== false)
  1774. {
  1775. if (substr($value, -1, 1) === '*')
  1776. {
  1777. list($image_filename, $image_height) = explode('*', $value);
  1778. $image_width = 0;
  1779. }
  1780. else
  1781. {
  1782. list($image_filename, $image_height, $image_width) = explode('*', $value);
  1783. }
  1784. }
  1785. else
  1786. {
  1787. $image_filename = $value;
  1788. $image_height = $image_width = 0;
  1789. }
  1790.  
  1791. if (strpos($image_name, 'img_') === 0 && $image_filename)
  1792. {
  1793. $image_name = substr($image_name, 4);
  1794. $sql_ary[] = array(
  1795. 'image_name' => (string) $image_name,
  1796. 'image_filename' => (string) $image_filename,
  1797. 'image_height' => (int) $image_height,
  1798. 'image_width' => (int) $image_width,
  1799. 'imageset_id' => (int) $this->theme['imageset_id'],
  1800. 'image_lang' => (string) $this->img_lang,
  1801. );
  1802. }
  1803. }
  1804. }
  1805.  
  1806. if (sizeof($sql_ary))
  1807. {
  1808. $db->sql_multi_insert(STYLES_IMAGESET_DATA_TABLE, $sql_ary);
  1809. $db->sql_transaction('commit');
  1810. $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE);
  1811.  
  1812. add_log('admin', 'LOG_IMAGESET_LANG_REFRESHED', $this->theme['imageset_name'], $this->img_lang);
  1813. }
  1814. else
  1815. {
  1816. $db->sql_transaction('commit');
  1817. add_log('admin', 'LOG_IMAGESET_LANG_MISSING', $this->theme['imageset_name'], $this->img_lang);
  1818. }
  1819. }
  1820.  
  1821. // Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes...
  1822. // After calling it we continue script execution...
  1823. phpbb_user_session_handler();
  1824.  
  1825. // If this function got called from the error handler we are finished here.
  1826. if (defined('IN_ERROR_HANDLER'))
  1827. {
  1828. return;
  1829. }
  1830.  
  1831. // Disable board if the install/ directory is still present
  1832. // For the brave development army we do not care about this, else we need to comment out this everytime we develop locally
  1833. if (!defined('DEBUG_EXTRA') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install'))
  1834. {
  1835. // Adjust the message slightly according to the permissions
  1836. if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))
  1837. {
  1838. $message = 'REMOVE_INSTALL';
  1839. }
  1840. else
  1841. {
  1842. $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
  1843. }
  1844. trigger_error($message);
  1845. }
  1846.  
  1847. // Is board disabled and user not an admin or moderator?
  1848. if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
  1849. {
  1850. if ($this->data['is_bot'])
  1851. {
  1852. send_status_line(503, 'Service Unavailable');
  1853. }
  1854.  
  1855. $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
  1856. trigger_error($message);
  1857. }
  1858.  
  1859. // Is load exceeded?
  1860. if ($config['limit_load'] && $this->load !== false)
  1861. {
  1862. if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !defined('IN_ADMIN'))
  1863. {
  1864. // Set board disabled to true to let the admins/mods get the proper notification
  1865. $config['board_disable'] = '1';
  1866.  
  1867. if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
  1868. {
  1869. if ($this->data['is_bot'])
  1870. {
  1871. send_status_line(503, 'Service Unavailable');
  1872. }
  1873. trigger_error('BOARD_UNAVAILABLE');
  1874. }
  1875. }
  1876. }
  1877.  
  1878. if (isset($this->data['session_viewonline']))
  1879. {
  1880. // Make sure the user is able to hide his session
  1881. if (!$this->data['session_viewonline'])
  1882. {
  1883. // Reset online status if not allowed to hide the session...
  1884. if (!$auth->acl_get('u_hideonline'))
  1885. {
  1886. $sql = 'UPDATE ' . SESSIONS_TABLE . '
  1887. SET session_viewonline = 1
  1888. WHERE session_user_id = ' . $this->data['user_id'];
  1889. $db->sql_query($sql);
  1890. $this->data['session_viewonline'] = 1;
  1891. }
  1892. }
  1893. else if (!$this->data['user_allow_viewonline'])
  1894. {
  1895. // the user wants to hide and is allowed to -> cloaking device on.
  1896. if ($auth->acl_get('u_hideonline'))
  1897. {
  1898. $sql = 'UPDATE ' . SESSIONS_TABLE . '
  1899. SET session_viewonline = 0
  1900. WHERE session_user_id = ' . $this->data['user_id'];
  1901. $db->sql_query($sql);
  1902. $this->data['session_viewonline'] = 0;
  1903. }
  1904. }
  1905. }
  1906.  
  1907.  
  1908. // Does the user need to change their password? If so, redirect to the
  1909. // ucp profile reg_details page ... of course do not redirect if we're already in the ucp
  1910. if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && !empty($this->data['is_registered']) && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400))
  1911. {
  1912. if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx")
  1913. {
  1914. redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&amp;mode=reg_details'));
  1915. }
  1916. }
  1917.  
  1918. return;
  1919. }
  1920.  
  1921. /**
  1922. * More advanced language substitution
  1923. * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms.
  1924. * Params are the language key and the parameters to be substituted.
  1925. * This function/functionality is inspired by SHS` and Ashe.
  1926. *
  1927. * Example call: <samp>$user->lang('NUM_POSTS_IN_QUEUE', 1);</samp>
  1928. */
  1929. function lang()
  1930. {
  1931. $args = func_get_args();
  1932. $key = $args[0];
  1933.  
  1934. if (is_array($key))
  1935. {
  1936. $lang = &$this->lang[array_shift($key)];
  1937.  
  1938. foreach ($key as $_key)
  1939. {
  1940. $lang = &$lang[$_key];
  1941. }
  1942. }
  1943. else
  1944. {
  1945. $lang = &$this->lang[$key];
  1946. }
  1947.  
  1948. // Return if language string does not exist
  1949. if (!isset($lang) || (!is_string($lang) && !is_array($lang)))
  1950. {
  1951. return $key;
  1952. }
  1953.  
  1954. // If the language entry is a string, we simply mimic sprintf() behaviour
  1955. if (is_string($lang))
  1956. {
  1957. if (sizeof($args) == 1)
  1958. {
  1959. return $lang;
  1960. }
  1961.  
  1962. // Replace key with language entry and simply pass along...
  1963. $args[0] = $lang;
  1964. return call_user_func_array('sprintf', $args);
  1965. }
  1966.  
  1967. // It is an array... now handle different nullar/singular/plural forms
  1968. $key_found = false;
  1969.  
  1970. // We now get the first number passed and will select the key based upon this number
  1971. for ($i = 1, $num_args = sizeof($args); $i < $num_args; $i++)
  1972. {
  1973. if (is_int($args[$i]))
  1974. {
  1975. $numbers = array_keys($lang);
  1976.  
  1977. foreach ($numbers as $num)
  1978. {
  1979. if ($num > $args[$i])
  1980. {
  1981. break;
  1982. }
  1983.  
  1984. $key_found = $num;
  1985. }
  1986. break;
  1987. }
  1988. }
  1989.  
  1990. // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form)
  1991. if ($key_found === false)
  1992. {
  1993. $numbers = array_keys($lang);
  1994. $key_found = end($numbers);
  1995. }
  1996.  
  1997. // Use the language string we determined and pass it to sprintf()
  1998. $args[0] = $lang[$key_found];
  1999. return call_user_func_array('sprintf', $args);
  2000. }
  2001.  
  2002. /**
  2003. * Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
  2004. *
  2005. * @param mixed $lang_set specifies the language entries to include
  2006. * @param bool $use_db internal variable for recursion, do not use
  2007. * @param bool $use_help internal variable for recursion, do not use
  2008. *
  2009. * Examples:
  2010. * <code>
  2011. * $lang_set = array('posting', 'help' => 'faq');
  2012. * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq'))
  2013. * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq'))
  2014. * $lang_set = 'posting'
  2015. * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
  2016. * </code>
  2017. */
  2018. function add_lang($lang_set, $use_db = false, $use_help = false)
  2019. {
  2020. global $phpEx;
  2021.  
  2022. if (is_array($lang_set))
  2023. {
  2024. foreach ($lang_set as $key => $lang_file)
  2025. {
  2026. // Please do not delete this line.
  2027. // We have to force the type here, else [array] language inclusion will not work
  2028. $key = (string) $key;
  2029.  
  2030. if ($key == 'db')
  2031. {
  2032. $this->add_lang($lang_file, true, $use_help);
  2033. }
  2034. else if ($key == 'help')
  2035. {
  2036. $this->add_lang($lang_file, $use_db, true);
  2037. }
  2038. else if (!is_array($lang_file))
  2039. {
  2040. $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help);
  2041. }
  2042. else
  2043. {
  2044. $this->add_lang($lang_file, $use_db, $use_help);
  2045. }
  2046. }
  2047. unset($lang_set);
  2048. }
  2049. else if ($lang_set)
  2050. {
  2051. $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help);
  2052. }
  2053. }
  2054.  
  2055. /**
  2056. * Set language entry (called by add_lang)
  2057. * @access private
  2058. */
  2059. function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false)
  2060. {
  2061. global $phpEx;
  2062.  
  2063. // Make sure the language name is set (if the user setup did not happen it is not set)
  2064. if (!$this->lang_name)
  2065. {
  2066. global $config;
  2067. $this->lang_name = basename($config['default_lang']);
  2068. }
  2069.  
  2070. // $lang == $this->lang
  2071. // $help == $this->help
  2072. // - add appropriate variables here, name them as they are used within the language file...
  2073. if (!$use_db)
  2074. {
  2075. if ($use_help && strpos($lang_file, '/') !== false)
  2076. {
  2077. $language_filename = $this->lang_path . $this->lang_name . '/' . substr($lang_file, 0, stripos($lang_file, '/') + 1) . 'help_' . substr($lang_file, stripos($lang_file, '/') + 1) . '.' . $phpEx;
  2078. }
  2079. else
  2080. {
  2081. $language_filename = $this->lang_path . $this->lang_name . '/' . (($use_help) ? 'help_' : '') . $lang_file . '.' . $phpEx;
  2082. }
  2083.  
  2084. if (!file_exists($language_filename))
  2085. {
  2086. global $config;
  2087.  
  2088. if ($this->lang_name == 'en')
  2089. {
  2090. // The user's selected language is missing the file, the board default's language is missing the file, and the file doesn't exist in /en.
  2091. $language_filename = str_replace($this->lang_path . 'en', $this->lang_path . $this->data['user_lang'], $language_filename);
  2092. trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR);
  2093. }
  2094. else if ($this->lang_name == basename($config['default_lang']))
  2095. {
  2096. // Fall back to the English Language
  2097. $this->lang_name = 'en';
  2098. $this->set_lang($lang, $help, $lang_file, $use_db, $use_help);
  2099. }
  2100. else if ($this->lang_name == $this->data['user_lang'])
  2101. {
  2102. // Fall back to the board default language
  2103. $this->lang_name = basename($config['default_lang']);
  2104. $this->set_lang($lang, $help, $lang_file, $use_db, $use_help);
  2105. }
  2106.  
  2107. // Reset the lang name
  2108. $this->lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
  2109. return;
  2110. }
  2111.  
  2112. // Do not suppress error if in DEBUG_EXTRA mode
  2113. $include_result = (defined('DEBUG_EXTRA')) ? (include $language_filename) : (@include $language_filename);
  2114.  
  2115. if ($include_result === false)
  2116. {
  2117. trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR);
  2118. }
  2119. }
  2120. else if ($use_db)
  2121. {
  2122. // Get Database Language Strings
  2123. // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed
  2124. // For example: help:faq, posting
  2125. }
  2126. }
  2127.  
  2128. /**
  2129. * Format user date
  2130. *
  2131. * @param int $gmepoch unix timestamp
  2132. * @param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i.
  2133. * @param bool $forcedate force non-relative date format.
  2134. *
  2135. * @return mixed translated date
  2136. */
  2137. function format_date($gmepoch, $format = false, $forcedate = false)
  2138. {
  2139. static $midnight;
  2140. static $date_cache;
  2141.  
  2142. $format = (!$format) ? $this->date_format : $format;
  2143. $now = time();
  2144. $delta = $now - $gmepoch;
  2145.  
  2146. if (!isset($date_cache[$format]))
  2147. {
  2148. // Is the user requesting a friendly date format (i.e. 'Today 12:42')?
  2149. $date_cache[$format] = array(
  2150. 'is_short' => strpos($format, '|'),
  2151. 'format_short' => substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1),
  2152. 'format_long' => str_replace('|', '', $format),
  2153. 'lang' => $this->lang['datetime'],
  2154. );
  2155.  
  2156. // Short representation of month in format? Some languages use different terms for the long and short format of May
  2157. if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false))
  2158. {
  2159. $date_cache[$format]['lang']['May'] = $this->lang['datetime']['May_short'];
  2160. }
  2161. }
  2162.  
  2163. // Zone offset
  2164. $zone_offset = $this->timezone + $this->dst;
  2165.  
  2166. // Show date <= 1 hour ago as 'xx min ago' but not greater than 60 seconds in the future
  2167. // A small tolerence is given for times in the future but in the same minute are displayed as '< than a minute ago'
  2168. if ($delta <= 3600 && $delta > -60 && ($delta >= -5 || (($now / 60) % 60) == (($gmepoch / 60) % 60)) && $date_cache[$format]['is_short'] !== false && !$forcedate && isset($this->lang['datetime']['AGO']))
  2169. {
  2170. return $this->lang(array('datetime', 'AGO'), max(0, (int) floor($delta / 60)));
  2171. }
  2172.  
  2173. if (!$midnight)
  2174. {
  2175. list($d, $m, $y) = explode(' ', gmdate('j n Y', time() + $zone_offset));
  2176. $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $zone_offset;
  2177. }
  2178.  
  2179. if ($date_cache[$format]['is_short'] !== false && !$forcedate && !($gmepoch < $midnight - 86400 || $gmepoch > $midnight + 172800))
  2180. {
  2181. $day = false;
  2182.  
  2183. if ($gmepoch > $midnight + 86400)
  2184. {
  2185. $day = 'TOMORROW';
  2186. }
  2187. else if ($gmepoch > $midnight)
  2188. {
  2189. $day = 'TODAY';
  2190. }
  2191. else if ($gmepoch > $midnight - 86400)
  2192. {
  2193. $day = 'YESTERDAY';
  2194. }
  2195.  
  2196. if ($day !== false)
  2197. {
  2198. return str_replace('||', $this->lang['datetime'][$day], strtr(@gmdate($date_cache[$format]['format_short'], $gmepoch + $zone_offset), $date_cache[$format]['lang']));
  2199. }
  2200. }
  2201.  
  2202. return strtr(@gmdate($date_cache[$format]['format_long'], $gmepoch + $zone_offset), $date_cache[$format]['lang']);
  2203. }
  2204.  
  2205. /**
  2206. * Get language id currently used by the user
  2207. */
  2208. function get_iso_lang_id()
  2209. {
  2210. global $config, $db;
  2211.  
  2212. if (!empty($this->lang_id))
  2213. {
  2214. return $this->lang_id;
  2215. }
  2216.  
  2217. if (!$this->lang_name)
  2218. {
  2219. $this->lang_name = $config['default_lang'];
  2220. }
  2221.  
  2222. $sql = 'SELECT lang_id
  2223. FROM ' . LANG_TABLE . "
  2224. WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'";
  2225. $result = $db->sql_query($sql);
  2226. $this->lang_id = (int) $db->sql_fetchfield('lang_id');
  2227. $db->sql_freeresult($result);
  2228.  
  2229. return $this->lang_id;
  2230. }
  2231.  
  2232. /**
  2233. * Get users profile fields
  2234. */
  2235. function get_profile_fields($user_id)
  2236. {
  2237. global $db;
  2238.  
  2239. if (isset($this->profile_fields))
  2240. {
  2241. return;
  2242. }
  2243.  
  2244. $sql = 'SELECT *
  2245. FROM ' . PROFILE_FIELDS_DATA_TABLE . "
  2246. WHERE user_id = $user_id";
  2247. $result = $db->sql_query_limit($sql, 1);
  2248. $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row;
  2249. $db->sql_freeresult($result);
  2250. }
  2251.  
  2252. /**
  2253. * Specify/Get image
  2254. * $suffix is no longer used - we know it. ;) It is there for backward compatibility.
  2255. */
  2256. function img($img, $alt = '', $width = false, $suffix = '', $type = 'full_tag')
  2257. {
  2258. static $imgs;
  2259. global $phpbb_root_path;
  2260.  
  2261. $img_data = &$imgs[$img];
  2262.  
  2263. if (empty($img_data))
  2264. {
  2265. if (!isset($this->img_array[$img]))
  2266. {
  2267. // Do not fill the image to let designers decide what to do if the image is empty
  2268. $img_data = '';
  2269. return $img_data;
  2270. }
  2271.  
  2272. // Use URL if told so
  2273. $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path;
  2274.  
  2275. $path = 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename'];
  2276.  
  2277. $img_data['src'] = $root_path . $path;
  2278. $img_data['width'] = $this->img_array[$img]['image_width'];
  2279. $img_data['height'] = $this->img_array[$img]['image_height'];
  2280.  
  2281. // We overwrite the width and height to the phpbb logo's width
  2282. // and height here if the contents of the site_logo file are
  2283. // really equal to the phpbb_logo
  2284. // This allows us to change the dimensions of the phpbb_logo without
  2285. // modifying the imageset.cfg and causing a conflict for everyone
  2286. // who modified it for their custom logo on updating
  2287. if ($img == 'site_logo' && file_exists($phpbb_root_path . $path))
  2288. {
  2289. global $cache;
  2290.  
  2291. $img_file_hashes = $cache->get('imageset_site_logo_md5');
  2292.  
  2293. if ($img_file_hashes === false)
  2294. {
  2295. $img_file_hashes = array();
  2296. }
  2297.  
  2298. $key = $this->theme['imageset_path'] . '::' . $this->img_array[$img]['image_lang'];
  2299. if (!isset($img_file_hashes[$key]))
  2300. {
  2301. $img_file_hashes[$key] = md5(file_get_contents($phpbb_root_path . $path));
  2302. $cache->put('imageset_site_logo_md5', $img_file_hashes);
  2303. }
  2304.  
  2305. $phpbb_logo_hash = '0c461a32cd3621643105f0d02a772c10';
  2306.  
  2307. if ($phpbb_logo_hash == $img_file_hashes[$key])
  2308. {
  2309. $img_data['width'] = '149';
  2310. $img_data['height'] = '52';
  2311. }
  2312. }
  2313. }
  2314.  
  2315. $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt;
  2316.  
  2317. switch ($type)
  2318. {
  2319. case 'src':
  2320. return $img_data['src'];
  2321. break;
  2322.  
  2323. case 'width':
  2324. return ($width === false) ? $img_data['width'] : $width;
  2325. break;
  2326.  
  2327. case 'height':
  2328. return $img_data['height'];
  2329. break;
  2330.  
  2331. default:
  2332. $use_width = ($width === false) ? $img_data['width'] : $width;
  2333.  
  2334. return '<img src="' . $img_data['src'] . '"' . (($use_width) ? ' width="' . $use_width . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />';
  2335. break;
  2336. }
  2337. }
  2338.  
  2339. /**
  2340. * Get option bit field from user options
  2341. */
  2342. function optionget($key, $data = false)
  2343. {
  2344. if (!isset($this->keyvalues[$key]))
  2345. {
  2346. $var = ($data) ? $data : $this->data['user_options'];
  2347. $this->keyvalues[$key] = ($var & 1 << $this->keyoptions[$key]) ? true : false;
  2348. }
  2349.  
  2350. return $this->keyvalues[$key];
  2351. }
  2352.  
  2353. /**
  2354. * Set option bit field for user options
  2355. */
  2356. function optionset($key, $value, $data = false)
  2357. {
  2358. $var = ($data) ? $data : $this->data['user_options'];
  2359.  
  2360. if ($value && !($var & 1 << $this->keyoptions[$key]))
  2361. {
  2362. $var += 1 << $this->keyoptions[$key];
  2363. }
  2364. else if (!$value && ($var & 1 << $this->keyoptions[$key]))
  2365. {
  2366. $var -= 1 << $this->keyoptions[$key];
  2367. }
  2368. else
  2369. {
  2370. return ($data) ? $var : false;
  2371. }
  2372.  
  2373. if (!$data)
  2374. {
  2375. $this->data['user_options'] = $var;
  2376. return true;
  2377. }
  2378. else
  2379. {
  2380. return $var;
  2381. }
  2382. }
  2383.  
  2384. /**
  2385. * Funtion to make the user leave the NEWLY_REGISTERED system group.
  2386. * @access public
  2387. */
  2388. function leave_newly_registered()
  2389. {
  2390. global $db;
  2391.  
  2392. if (empty($this->data['user_new']))
  2393. {
  2394. return false;
  2395. }
  2396.  
  2397. if (!function_exists('remove_newly_registered'))
  2398. {
  2399. global $phpbb_root_path, $phpEx;
  2400.  
  2401. include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
  2402. }
  2403. if ($group = remove_newly_registered($this->data['user_id'], $this->data))
  2404. {
  2405. $this->data['group_id'] = $group;
  2406.  
  2407. }
  2408. $this->data['user_permissions'] = '';
  2409. $this->data['user_new'] = 0;
  2410.  
  2411. return true;
  2412. }
  2413.  
  2414. /**
  2415. * Returns all password protected forum ids the user is currently NOT authenticated for.
  2416. *
  2417. * @return array Array of forum ids
  2418. * @access public
  2419. */
  2420. function get_passworded_forums()
  2421. {
  2422. global $db;
  2423.  
  2424. $sql = 'SELECT f.forum_id, fa.user_id
  2425. FROM ' . FORUMS_TABLE . ' f
  2426. LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa
  2427. ON (fa.forum_id = f.forum_id
  2428. AND fa.session_id = '" . $db->sql_escape($this->session_id) . "')
  2429. WHERE f.forum_password <> ''";
  2430. $result = $db->sql_query($sql);
  2431.  
  2432. $forum_ids = array();
  2433. while ($row = $db->sql_fetchrow($result))
  2434. {
  2435. $forum_id = (int) $row['forum_id'];
  2436.  
  2437. if ($row['user_id'] != $this->data['user_id'])
  2438. {
  2439. $forum_ids[$forum_id] = $forum_id;
  2440. }
  2441. }
  2442. $db->sql_freeresult($result);
  2443.  
  2444. return $forum_ids;
  2445. }
  2446. }
  2447.  
  2448. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement