PageRenderTime 67ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/sources/subs/Auth.subs.php

https://github.com/Arantor/Elkarte
PHP | 683 lines | 372 code | 116 blank | 195 comment | 79 complexity | 3a029b62a69f8acd789a83c400732e40 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0
  1. <?php
  2. /**
  3. * @name ElkArte Forum
  4. * @copyright ElkArte Forum contributors
  5. * @license BSD http://opensource.org/licenses/BSD-3-Clause
  6. *
  7. * This software is a derived product, based on:
  8. *
  9. * Simple Machines Forum (SMF)
  10. * copyright: 2011 Simple Machines (http://www.simplemachines.org)
  11. * license: BSD, See included LICENSE.TXT for terms and conditions.
  12. *
  13. * @version 1.0 Alpha
  14. *
  15. * This file has functions in it to do with authentication, user handling, and the like.
  16. *
  17. */
  18. if (!defined('ELKARTE'))
  19. die('No access...');
  20. /**
  21. * Sets the login cookie and session based on the id_member and password passed.
  22. * - password should be already encrypted with the cookie salt.
  23. * - logs the user out if id_member is zero.
  24. * - sets the cookie and session to last the number of seconds specified by cookie_length.
  25. * - when logging out, if the globalCookies setting is enabled, attempts to clear the subdomain's cookie too.
  26. *
  27. * @param int $cookie_length
  28. * @param int $id The id of the member
  29. * @param string $password = ''
  30. */
  31. function setLoginCookie($cookie_length, $id, $password = '')
  32. {
  33. global $cookiename, $boardurl, $modSettings;
  34. // If changing state force them to re-address some permission caching.
  35. $_SESSION['mc']['time'] = 0;
  36. // The cookie may already exist, and have been set with different options.
  37. $cookie_state = (empty($modSettings['localCookies']) ? 0 : 1) | (empty($modSettings['globalCookies']) ? 0 : 2);
  38. if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\{i:0;(i:\d{1,6}|s:[1-8]:"\d{1,8}");i:1;s:(0|40):"([a-fA-F0-9]{40})?";i:2;[id]:\d{1,14};(i:3;i:\d;)?\}$~', $_COOKIE[$cookiename]) === 1)
  39. {
  40. $array = @unserialize($_COOKIE[$cookiename]);
  41. // Out with the old, in with the new!
  42. if (isset($array[3]) && $array[3] != $cookie_state)
  43. {
  44. $cookie_url = url_parts($array[3] & 1 > 0, $array[3] & 2 > 0);
  45. elk_setcookie($cookiename, serialize(array(0, '', 0)), time() - 3600, $cookie_url[1], $cookie_url[0]);
  46. }
  47. }
  48. // Get the data and path to set it on.
  49. $data = serialize(empty($id) ? array(0, '', 0) : array($id, $password, time() + $cookie_length, $cookie_state));
  50. $cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies']));
  51. // Set the cookie, $_COOKIE, and session variable.
  52. elk_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0]);
  53. // If subdomain-independent cookies are on, unset the subdomain-dependent cookie too.
  54. if (empty($id) && !empty($modSettings['globalCookies']))
  55. elk_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], '');
  56. // Any alias URLs? This is mainly for use with frames, etc.
  57. if (!empty($modSettings['forum_alias_urls']))
  58. {
  59. $aliases = explode(',', $modSettings['forum_alias_urls']);
  60. $temp = $boardurl;
  61. foreach ($aliases as $alias)
  62. {
  63. // Fake the $boardurl so we can set a different cookie.
  64. $alias = strtr(trim($alias), array('http://' => '', 'https://' => ''));
  65. $boardurl = 'http://' . $alias;
  66. $cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies']));
  67. if ($cookie_url[0] == '')
  68. $cookie_url[0] = strtok($alias, '/');
  69. elk_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0]);
  70. }
  71. $boardurl = $temp;
  72. }
  73. $_COOKIE[$cookiename] = $data;
  74. // Make sure the user logs in with a new session ID.
  75. if (!isset($_SESSION['login_' . $cookiename]) || $_SESSION['login_' . $cookiename] !== $data)
  76. {
  77. // We need to meddle with the session.
  78. require_once(SOURCEDIR . '/Session.php');
  79. // Backup and remove the old session.
  80. $oldSessionData = $_SESSION;
  81. $_SESSION = array();
  82. session_destroy();
  83. // Recreate and restore the new session.
  84. loadSession();
  85. // @todo should we use session_regenerate_id(true); now that we are 5.1+
  86. session_regenerate_id();
  87. $_SESSION = $oldSessionData;
  88. $_SESSION['login_' . $cookiename] = $data;
  89. }
  90. }
  91. /**
  92. * Get the domain and path for the cookie
  93. * - normally, local and global should be the localCookies and globalCookies settings, respectively.
  94. * - uses boardurl to determine these two things.
  95. *
  96. * @param bool $local
  97. * @param bool $global
  98. * @return array an array to set the cookie on with domain and path in it, in that order
  99. */
  100. function url_parts($local, $global)
  101. {
  102. global $boardurl, $modSettings;
  103. // Parse the URL with PHP to make life easier.
  104. $parsed_url = parse_url($boardurl);
  105. // Is local cookies off?
  106. if (empty($parsed_url['path']) || !$local)
  107. $parsed_url['path'] = '';
  108. if (!empty($modSettings['globalCookiesDomain']) && strpos($boardurl, $modSettings['globalCookiesDomain']) !== false)
  109. $parsed_url['host'] = $modSettings['globalCookiesDomain'];
  110. // Globalize cookies across domains (filter out IP-addresses)?
  111. elseif ($global && preg_match('~^\d{1,3}(\.\d{1,3}){3}$~', $parsed_url['host']) == 0 && preg_match('~(?:[^\.]+\.)?([^\.]{2,}\..+)\z~i', $parsed_url['host'], $parts) == 1)
  112. $parsed_url['host'] = '.' . $parts[1];
  113. // We shouldn't use a host at all if both options are off.
  114. elseif (!$local && !$global)
  115. $parsed_url['host'] = '';
  116. // The host also shouldn't be set if there aren't any dots in it.
  117. elseif (!isset($parsed_url['host']) || strpos($parsed_url['host'], '.') === false)
  118. $parsed_url['host'] = '';
  119. return array($parsed_url['host'], $parsed_url['path'] . '/');
  120. }
  121. /**
  122. * Throws guests out to the login screen when guest access is off.
  123. * - sets $_SESSION['login_url'] to $_SERVER['REQUEST_URL'].
  124. * - uses the 'kick_guest' sub template found in Login.template.php.
  125. */
  126. function KickGuest()
  127. {
  128. global $txt, $context;
  129. loadLanguage('Login');
  130. loadTemplate('Login');
  131. // Never redirect to an attachment
  132. if (strpos($_SERVER['REQUEST_URL'], 'dlattach') === false)
  133. $_SESSION['login_url'] = $_SERVER['REQUEST_URL'];
  134. $context['sub_template'] = 'kick_guest';
  135. $context['page_title'] = $txt['login'];
  136. }
  137. /**
  138. * Display a message about the forum being in maintenance mode.
  139. * - display a login screen with sub template 'maintenance'.
  140. * - sends a 503 header, so search engines don't bother indexing while we're in maintenance mode.
  141. */
  142. function InMaintenance()
  143. {
  144. global $txt, $mtitle, $mmessage, $context;
  145. loadLanguage('Login');
  146. loadTemplate('Login');
  147. // Send a 503 header, so search engines don't bother indexing while we're in maintenance mode.
  148. header('HTTP/1.1 503 Service Temporarily Unavailable');
  149. // Basic template stuff..
  150. $context['sub_template'] = 'maintenance';
  151. $context['title'] = &$mtitle;
  152. $context['description'] = &$mmessage;
  153. $context['page_title'] = $txt['maintain_mode'];
  154. }
  155. /**
  156. * Question the verity of the admin by asking for his or her password.
  157. * - loads Login.template.php and uses the admin_login sub template.
  158. * - sends data to template so the admin is sent on to the page they
  159. * wanted if their password is correct, otherwise they can try again.
  160. *
  161. * @param string $type = 'admin'
  162. */
  163. function adminLogin($type = 'admin')
  164. {
  165. global $context, $scripturl, $txt, $user_info, $user_settings;
  166. loadLanguage('Admin');
  167. loadTemplate('Login');
  168. // Validate what type of session check this is.
  169. $types = array();
  170. call_integration_hook('integrate_validateSession', array($types));
  171. $type = in_array($type, $types) || $type == 'moderate' ? $type : 'admin';
  172. // They used a wrong password, log it and unset that.
  173. if (isset($_POST[$type . '_hash_pass']) || isset($_POST[$type . '_pass']))
  174. {
  175. $txt['security_wrong'] = sprintf($txt['security_wrong'], isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $txt['unknown'], $_SERVER['HTTP_USER_AGENT'], $user_info['ip']);
  176. log_error($txt['security_wrong'], 'critical');
  177. if (isset($_POST[$type . '_hash_pass']))
  178. unset($_POST[$type . '_hash_pass']);
  179. if (isset($_POST[$type . '_pass']))
  180. unset($_POST[$type . '_pass']);
  181. $context['incorrect_password'] = true;
  182. }
  183. createToken('admin-login');
  184. // Figure out the get data and post data.
  185. $context['get_data'] = '?' . construct_query_string($_GET);
  186. $context['post_data'] = '';
  187. // Now go through $_POST. Make sure the session hash is sent.
  188. $_POST[$context['session_var']] = $context['session_id'];
  189. foreach ($_POST as $k => $v)
  190. $context['post_data'] .= adminLogin_outputPostVars($k, $v);
  191. // Now we'll use the admin_login sub template of the Login template.
  192. $context['sub_template'] = 'admin_login';
  193. // And title the page something like "Login".
  194. if (!isset($context['page_title']))
  195. $context['page_title'] = $txt['login'];
  196. // The type of action.
  197. $context['sessionCheckType'] = $type;
  198. obExit();
  199. // We MUST exit at this point, because otherwise we CANNOT KNOW that the user is privileged.
  200. trigger_error('Hacking attempt...', E_USER_ERROR);
  201. }
  202. /**
  203. * Used by the adminLogin() function.
  204. * if 'value' is an array, the function is called recursively.
  205. *
  206. * @param string $k key
  207. * @param string $v value
  208. * @return string 'hidden' HTML form fields, containing key-value-pairs
  209. */
  210. function adminLogin_outputPostVars($k, $v)
  211. {
  212. global $smcFunc;
  213. if (!is_array($v))
  214. return '
  215. <input type="hidden" name="' . htmlspecialchars($k) . '" value="' . strtr($v, array('"' => '&quot;', '<' => '&lt;', '>' => '&gt;')) . '" />';
  216. else
  217. {
  218. $ret = '';
  219. foreach ($v as $k2 => $v2)
  220. $ret .= adminLogin_outputPostVars($k . '[' . $k2 . ']', $v2);
  221. return $ret;
  222. }
  223. }
  224. /**
  225. * Properly urlencodes a string to be used in a query
  226. *
  227. * @global type $scripturl
  228. * @param type $get
  229. * @return our query string
  230. */
  231. function construct_query_string($get)
  232. {
  233. global $scripturl;
  234. $query_string = '';
  235. // Awww, darn. The $scripturl contains GET stuff!
  236. $q = strpos($scripturl, '?');
  237. if ($q !== false)
  238. {
  239. parse_str(preg_replace('/&(\w+)(?=&|$)/', '&$1=', strtr(substr($scripturl, $q + 1), ';', '&')), $temp);
  240. foreach ($get as $k => $v)
  241. {
  242. // Only if it's not already in the $scripturl!
  243. if (!isset($temp[$k]))
  244. $query_string .= urlencode($k) . '=' . urlencode($v) . ';';
  245. // If it changed, put it out there, but with an ampersand.
  246. elseif ($temp[$k] != $get[$k])
  247. $query_string .= urlencode($k) . '=' . urlencode($v) . '&amp;';
  248. }
  249. }
  250. else
  251. {
  252. // Add up all the data from $_GET into get_data.
  253. foreach ($get as $k => $v)
  254. $query_string .= urlencode($k) . '=' . urlencode($v) . ';';
  255. }
  256. $query_string = substr($query_string, 0, -1);
  257. return $query_string;
  258. }
  259. /**
  260. * Finds members by email address, username, or real name.
  261. * - searches for members whose username, display name, or e-mail address match the given pattern of array names.
  262. * - searches only buddies if buddies_only is set.
  263. *
  264. * @param array $names
  265. * @param bool $use_wildcards = false, accepts wildcards ? and * in the patern if true
  266. * @param bool $buddies_only = false,
  267. * @param int $max = 500 retrieves a maximum of max members, if passed
  268. * @return array containing information about the matching members
  269. */
  270. function findMembers($names, $use_wildcards = false, $buddies_only = false, $max = 500)
  271. {
  272. global $scripturl, $user_info, $modSettings, $smcFunc;
  273. // If it's not already an array, make it one.
  274. if (!is_array($names))
  275. $names = explode(',', $names);
  276. $maybe_email = false;
  277. foreach ($names as $i => $name)
  278. {
  279. // Trim, and fix wildcards for each name.
  280. $names[$i] = trim($smcFunc['strtolower']($name));
  281. $maybe_email |= strpos($name, '@') !== false;
  282. // Make it so standard wildcards will work. (* and ?)
  283. if ($use_wildcards)
  284. $names[$i] = strtr($names[$i], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '\'' => '&#039;'));
  285. else
  286. $names[$i] = strtr($names[$i], array('\'' => '&#039;'));
  287. }
  288. // What are we using to compare?
  289. $comparison = $use_wildcards ? 'LIKE' : '=';
  290. // Nothing found yet.
  291. $results = array();
  292. // This ensures you can't search someones email address if you can't see it.
  293. $email_condition = allowedTo('moderate_forum') ? '' : 'hide_email = 0 AND ';
  294. if ($use_wildcards || $maybe_email)
  295. $email_condition = '
  296. OR (' . $email_condition . 'email_address ' . $comparison . ' \'' . implode( '\') OR (' . $email_condition . ' email_address ' . $comparison . ' \'', $names) . '\')';
  297. else
  298. $email_condition = '';
  299. // Get the case of the columns right - but only if we need to as things like MySQL will go slow needlessly otherwise.
  300. $member_name = $smcFunc['db_case_sensitive'] ? 'LOWER(member_name)' : 'member_name';
  301. $real_name = $smcFunc['db_case_sensitive'] ? 'LOWER(real_name)' : 'real_name';
  302. // Search by username, display name, and email address.
  303. $request = $smcFunc['db_query']('', '
  304. SELECT id_member, member_name, real_name, email_address, hide_email
  305. FROM {db_prefix}members
  306. WHERE ({raw:member_name_search}
  307. OR {raw:real_name_search} {raw:email_condition})
  308. ' . ($buddies_only ? 'AND id_member IN ({array_int:buddy_list})' : '') . '
  309. AND is_activated IN (1, 11)
  310. LIMIT {int:limit}',
  311. array(
  312. 'buddy_list' => $user_info['buddies'],
  313. 'member_name_search' => $member_name . ' ' . $comparison . ' \'' . implode( '\' OR ' . $member_name . ' ' . $comparison . ' \'', $names) . '\'',
  314. 'real_name_search' => $real_name . ' ' . $comparison . ' \'' . implode( '\' OR ' . $real_name . ' ' . $comparison . ' \'', $names) . '\'',
  315. 'email_condition' => $email_condition,
  316. 'limit' => $max,
  317. )
  318. );
  319. while ($row = $smcFunc['db_fetch_assoc']($request))
  320. {
  321. $results[$row['id_member']] = array(
  322. 'id' => $row['id_member'],
  323. 'name' => $row['real_name'],
  324. 'username' => $row['member_name'],
  325. 'email' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['email_address'] : '',
  326. 'href' => $scripturl . '?action=profile;u=' . $row['id_member'],
  327. 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>'
  328. );
  329. }
  330. $smcFunc['db_free_result']($request);
  331. // Return all the results.
  332. return $results;
  333. }
  334. /**
  335. * Generates a random password for a user and emails it to them.
  336. * - called by ProfileOptions controller when changing someone's username.
  337. * - checks the validity of the new username.
  338. * - generates and sets a new password for the given user.
  339. * - mails the new password to the email address of the user.
  340. * - if username is not set, only a new password is generated and sent.
  341. *
  342. * @param int $memID
  343. * @param string $username = null
  344. */
  345. function resetPassword($memID, $username = null)
  346. {
  347. global $modSettings, $smcFunc, $language;
  348. // Language... and a required file.
  349. loadLanguage('Login');
  350. require_once(SUBSDIR . '/Mail.subs.php');
  351. // Get some important details.
  352. $request = $smcFunc['db_query']('', '
  353. SELECT member_name, email_address, lngfile
  354. FROM {db_prefix}members
  355. WHERE id_member = {int:id_member}',
  356. array(
  357. 'id_member' => $memID,
  358. )
  359. );
  360. list ($user, $email, $lngfile) = $smcFunc['db_fetch_row']($request);
  361. $smcFunc['db_free_result']($request);
  362. if ($username !== null)
  363. {
  364. $old_user = $user;
  365. $user = trim($username);
  366. }
  367. // Generate a random password.
  368. $newPassword = substr(preg_replace('/\W/', '', md5(mt_rand())), 0, 10);
  369. $newPassword_sha1 = sha1(strtolower($user) . $newPassword);
  370. // Do some checks on the username if needed.
  371. if ($username !== null)
  372. {
  373. validateUsername($memID, $user);
  374. // Update the database...
  375. updateMemberData($memID, array('member_name' => $user, 'passwd' => $newPassword_sha1));
  376. }
  377. else
  378. updateMemberData($memID, array('passwd' => $newPassword_sha1));
  379. call_integration_hook('integrate_reset_pass', array($old_user, $user, $newPassword));
  380. $replacements = array(
  381. 'USERNAME' => $user,
  382. 'PASSWORD' => $newPassword,
  383. );
  384. $emaildata = loadEmailTemplate('change_password', $replacements, empty($lngfile) || empty($modSettings['userLanguage']) ? $language : $lngfile);
  385. // Send them the email informing them of the change - then we're done!
  386. sendmail($email, $emaildata['subject'], $emaildata['body'], null, null, false, 0);
  387. }
  388. /**
  389. * Checks a username obeys a load of rules
  390. *
  391. * @param int $memID
  392. * @param string $username
  393. * @param boolean $return_error
  394. * @param boolean $check_reserved_name
  395. * @return string Returns null if fine
  396. */
  397. function validateUsername($memID, $username, $return_error = false, $check_reserved_name = true)
  398. {
  399. global $txt, $smcFunc, $user_info;
  400. $errors = array();
  401. // Don't use too long a name.
  402. if ($smcFunc['strlen']($username) > 25)
  403. $errors[] = array('lang', 'error_long_name');
  404. // No name?! How can you register with no name?
  405. if ($username == '')
  406. $errors[] = array('lang', 'need_username');
  407. // Only these characters are permitted.
  408. if (in_array($username, array('_', '|')) || preg_match('~[<>&"\'=\\\\]~', preg_replace('~&#(?:\\d{1,7}|x[0-9a-fA-F]{1,6});~', '', $username)) != 0 || strpos($username, '[code') !== false || strpos($username, '[/code') !== false)
  409. $errors[] = array('lang', 'error_invalid_characters_username');
  410. if (stristr($username, $txt['guest_title']) !== false)
  411. $errors[] = array('lang', 'username_reserved', 'general', array($txt['guest_title']));
  412. if ($check_reserved_name)
  413. {
  414. require_once(SUBSDIR . '/Members.subs.php');
  415. if (isReservedName($username, $memID, false))
  416. $errors[] = array('done', '(' . htmlspecialchars($username) . ') ' . $txt['name_in_use']);
  417. }
  418. if ($return_error)
  419. return $errors;
  420. elseif (empty($errors))
  421. return null;
  422. loadLanguage('Errors');
  423. $error = $errors[0];
  424. $message = $error[0] == 'lang' ? (empty($error[3]) ? $txt[$error[1]] : vsprintf($txt[$error[1]], $error[3])) : $error[1];
  425. fatal_error($message, empty($error[2]) || $user_info['is_admin'] ? false : $error[2]);
  426. }
  427. /**
  428. * Checks whether a password meets the current forum rules
  429. * - called when registering/choosing a password.
  430. * - checks the password obeys the current forum settings for password strength.
  431. * - if password checking is enabled, will check that none of the words in restrict_in appear in the password.
  432. * - returns an error identifier if the password is invalid, or null.
  433. *
  434. * @param string $password
  435. * @param string $username
  436. * @param array $restrict_in = array()
  437. * @return string an error identifier if the password is invalid
  438. */
  439. function validatePassword($password, $username, $restrict_in = array())
  440. {
  441. global $modSettings, $smcFunc;
  442. // Perform basic requirements first.
  443. if ($smcFunc['strlen']($password) < (empty($modSettings['password_strength']) ? 4 : 8))
  444. return 'short';
  445. // Is this enough?
  446. if (empty($modSettings['password_strength']))
  447. return null;
  448. // Otherwise, perform the medium strength test - checking if password appears in the restricted string.
  449. if (preg_match('~\b' . preg_quote($password, '~') . '\b~', implode(' ', $restrict_in)) != 0)
  450. return 'restricted_words';
  451. elseif ($smcFunc['strpos']($password, $username) !== false)
  452. return 'restricted_words';
  453. // If just medium, we're done.
  454. if ($modSettings['password_strength'] == 1)
  455. return null;
  456. // Otherwise, hard test next, check for numbers and letters, uppercase too.
  457. $good = preg_match('~(\D\d|\d\D)~', $password) != 0;
  458. $good &= $smcFunc['strtolower']($password) != $password;
  459. return $good ? null : 'chars';
  460. }
  461. /**
  462. * Quickly find out what moderation authority this user has
  463. * - builds the moderator, group and board level querys for the user
  464. * - stores the information on the current users moderation powers in $user_info['mod_cache'] and $_SESSION['mc']
  465. */
  466. function rebuildModCache()
  467. {
  468. global $user_info, $smcFunc;
  469. // What groups can they moderate?
  470. $group_query = allowedTo('manage_membergroups') ? '1=1' : '0=1';
  471. if ($group_query == '0=1')
  472. {
  473. $request = $smcFunc['db_query']('', '
  474. SELECT id_group
  475. FROM {db_prefix}group_moderators
  476. WHERE id_member = {int:current_member}',
  477. array(
  478. 'current_member' => $user_info['id'],
  479. )
  480. );
  481. $groups = array();
  482. while ($row = $smcFunc['db_fetch_assoc']($request))
  483. $groups[] = $row['id_group'];
  484. $smcFunc['db_free_result']($request);
  485. if (empty($groups))
  486. $group_query = '0=1';
  487. else
  488. $group_query = 'id_group IN (' . implode(',', $groups) . ')';
  489. }
  490. // Then, same again, just the boards this time!
  491. $board_query = allowedTo('moderate_forum') ? '1=1' : '0=1';
  492. if ($board_query == '0=1')
  493. {
  494. $boards = boardsAllowedTo('moderate_board', true);
  495. if (empty($boards))
  496. $board_query = '0=1';
  497. else
  498. $board_query = 'id_board IN (' . implode(',', $boards) . ')';
  499. }
  500. // What boards are they the moderator of?
  501. $boards_mod = array();
  502. if (!$user_info['is_guest'])
  503. {
  504. $request = $smcFunc['db_query']('', '
  505. SELECT id_board
  506. FROM {db_prefix}moderators
  507. WHERE id_member = {int:current_member}',
  508. array(
  509. 'current_member' => $user_info['id'],
  510. )
  511. );
  512. while ($row = $smcFunc['db_fetch_assoc']($request))
  513. $boards_mod[] = $row['id_board'];
  514. $smcFunc['db_free_result']($request);
  515. }
  516. $mod_query = empty($boards_mod) ? '0=1' : 'b.id_board IN (' . implode(',', $boards_mod) . ')';
  517. $_SESSION['mc'] = array(
  518. 'time' => time(),
  519. // This looks a bit funny but protects against the login redirect.
  520. 'id' => $user_info['id'] && $user_info['name'] ? $user_info['id'] : 0,
  521. // If you change the format of 'gq' and/or 'bq' make sure to adjust 'can_mod' in Load.php.
  522. 'gq' => $group_query,
  523. 'bq' => $board_query,
  524. 'ap' => boardsAllowedTo('approve_posts'),
  525. 'mb' => $boards_mod,
  526. 'mq' => $mod_query,
  527. );
  528. call_integration_hook('integrate_mod_cache');
  529. $user_info['mod_cache'] = $_SESSION['mc'];
  530. // Might as well clean up some tokens while we are at it.
  531. cleanTokens();
  532. }
  533. /**
  534. * The same thing as setcookie but gives support for HTTP-Only cookies in PHP < 5.2
  535. *
  536. * @param string $name
  537. * @param string $value = ''
  538. * @param int $expire = 0
  539. * @param string $path = ''
  540. * @param string $domain = ''
  541. * @param bool $secure = false
  542. * @param bool $httponly = null
  543. */
  544. function elk_setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = null, $httponly = null)
  545. {
  546. global $modSettings;
  547. // In case a customization wants to override the default settings
  548. if ($httponly === null)
  549. $httponly = !empty($modSettings['httponlyCookies']);
  550. if ($secure === null)
  551. $secure = !empty($modSettings['secureCookies']);
  552. // Intercept cookie?
  553. call_integration_hook('integrate_cookie', array($name, $value, $expire, $path, $domain, $secure, $httponly));
  554. // This function is pointless if we have PHP >= 5.2.
  555. if (version_compare(PHP_VERSION, '5.2', '>='))
  556. return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
  557. // $httponly is the only reason I made this function. If it's not being used, use setcookie().
  558. if (!$httponly)
  559. return setcookie($name, $value, $expire, $path, $domain, $secure);
  560. // Ugh, looks like we have to resort to using a manual process.
  561. header('Set-Cookie: '.rawurlencode($name).'='.rawurlencode($value)
  562. .(empty($domain) ? '' : '; Domain='.$domain)
  563. .(empty($expire) ? '' : '; Max-Age='.$expire)
  564. .(empty($path) ? '' : '; Path='.$path)
  565. .(!$secure ? '' : '; Secure')
  566. .(!$httponly ? '' : '; HttpOnly'), false);
  567. }