You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

smf_api.php 31KB

  1. <?php
  2. /******************************************************************************
  3. * smf_api.php *
  4. *******************************************************************************
  5. * SMF: Simple Machines Forum *
  6. * Open-Source Project Inspired by Zef Hemel (zef@zefhemel.com) *
  7. * =========================================================================== *
  8. * Software Version: SMF 1.1 Beta 4 *
  9. * Software by: Simple Machines (http://www.simplemachines.org) *
  10. * Copyright 2001-2005 by: Lewis Media (http://www.lewismedia.com) *
  11. * Support, News, Updates at: http://www.simplemachines.org *
  12. *******************************************************************************
  13. * This program is free software; you may redistribute it and/or modify it *
  14. * under the terms of the provided license as published by Lewis Media. *
  15. * *
  16. * This program is distributed in the hope that it is and will be useful, *
  17. * but WITHOUT ANY WARRANTIES; without even any implied warranty of *
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
  19. * *
  20. * See the "license.txt" file for details of the Simple Machines license. *
  21. * The latest version can always be found at http://www.simplemachines.org. *
  22. ******************************************************************************/
  23. // !!! Groups, Member data? Pull specific fields?
  24. /* This file includes functions that may help integration with other scripts
  25. and programs, such as portals. It is independent of SMF, and meant to run
  26. without disturbing your script. It defines several functions, all of
  27. which start with the smf_ prefix. These are:
  28. bool smf_setLoginCookie(int length, string username or int ID_MEMBER,
  29. string password, bool encrypted = true)
  30. - sets a cookie and session variables to log the user in, for length
  31. seconds from now.
  32. - will find the ID_MEMBER for you if you specify a username.
  33. - please ensure that the username has slashes added to it.
  34. - does no authentication, but if the cookie is wrong it won't work.
  35. - expects the password to be pre-encrypted if encrypted is true.
  36. - returns false on failure (unlikely!), true on success.
  37. - you should call smf_authenticateUser after calling this.
  38. bool smf_authenticateUser()
  39. - authenticates the user with the current cookie ro session data.
  40. - loads data into the $smf_user_info variable.
  41. - returns false if it was unable to authenticate, true otherwise.
  42. - it would be good to call this at the beginning.
  43. int smf_registerMember(string username, string email, string password,
  44. array extra_fields = none, array theme_options = none)
  45. // !!!
  46. void smf_logOnline(string action = $_GET['action'])
  47. - logs the currently authenticated user or guest as online.
  48. - may not always log, because it delays logging if at all possible.
  49. - uses the action specified as the action in the log, a good example
  50. would be "coppermine" or similar.
  51. - you can add entries to the Modifications language files so as to
  52. make this action show up properly on Who's Online - see Who.php for
  53. more details.
  54. bool smf_isOnline(string username or int ID_MEMBER)
  55. - checks if the specified member is currently online.
  56. - will find the appropriate ID_MEMBER if username is given instead.
  57. - returns true if they are online, false otherwise.
  58. string smf_logError(string error_message, string file, int line)
  59. - logs an error, assuming error logging is enabled.
  60. - filename and line should be __FILE__ and __LINE__, respectively.
  61. - returns the error message. (ie. die(log_error($msg));)
  62. string smf_formatTime(int time)
  63. - formats the timestamp time into a readable string.
  64. - adds the appropriate offsets to make the time equivalent to the
  65. user's time.
  66. - return the readable representation as a string.
  67. resource smf_query(string query, string file, int line)
  68. - executes a query using SMF's database connection.
  69. - keeps a count of queries in the $smf_settings['db_count'] setting.
  70. - if an error occurs while executing the query, additionally logs an
  71. error in SMF's error log with the proper information.
  72. - does not do any crashed table prevention.
  73. bool smf_allowedTo(string permission)
  74. - checks to see if the user is allowed to do the specified permission
  75. or any of an array of permissions.
  76. - always returns true for administrators.
  77. - does not account for banning restrictions.
  78. - caches all available permissions upon first call.
  79. - does not provide access to board permissions.
  80. - returns null if no connection to the database has been made, and
  81. true or false depending on the user's permissions.
  82. void smf_loadThemeData(int ID_THEME = default)
  83. - if no ID_THEME is passed, the user's default theme will be used.
  84. - allows 'theme' in the URL to specify the theme, only if ID_THEME is
  85. not passed.
  86. - loads theme settings into $smf_settings['theme'].
  87. - loads theme options into $smf_user_info['theme'].
  88. - does nothing if no connection has been made to the database.
  89. - should be called after loading user information.
  90. void smf_loadSession()
  91. - loads the session, whether from the database or from files.
  92. - makes the session_id available in $smf_user_info.
  93. - will override session handling if the setting is enabled in SMF's
  94. configuration.
  95. bool smf_sessionOpen(string save_path, string session_name)
  96. bool smf_sessionClose()
  97. bool smf_sessionRead(string session_id)
  98. bool smf_sessionWrite(string session_id, string data)
  99. bool smf_sessionDestroy(string session_id)
  100. bool smf_sessionGC(int max_lifetime)
  101. - called only by internal PHP session handling functions.
  102. ---------------------------------------------------------------------------
  103. It also defines the following important variables:
  104. array $smf_settings
  105. - includes all the major settings from Settings.php, as well as all
  106. those from the settings table.
  107. - if smf_loadThemeData has been called, the theme settings will be
  108. available from the theme index.
  109. array $smf_user_info
  110. - only contains useful information after authentication.
  111. - major indexes are is_guest and is_admin, which easily and quickly
  112. tell you about the user's status.
  113. - also includes id, name, email, messages, unread_messages, and many
  114. other values from the members table.
  115. - you can also use the groups index to find what groups the user is in.
  116. - if smf_loadSession has been called, the session code is stored under
  117. session_id.
  118. - if smf_loadThemeData has been called, the theme options will be
  119. available from the theme index.
  120. */
  121. // fixes
  122. $maintenance = 0;
  123. // This is just because SMF in general hates magic quotes at runtime.
  124. //@set_magic_quotes_runtime(0);
  125. // Hopefully the forum is in the same place as this script.
  126. require_once(dirname(__FILE__) . '/Settings.php');
  127. global $smf_settings, $smf_user_info, $smf_connection;
  128. // If $maintenance is set to 2, don't connect to the database at all.
  129. if ($maintenance != 2)
  130. {
  131. // Ignore connection errors, because this is just an API file.
  132. if (empty($db_persist))
  133. $smf_connection = @mysqli_connect($db_server, $db_user, $db_passwd);
  134. else
  135. $smf_connection = @mysqli_pconnect($db_server, $db_user, $db_passwd);
  136. //$db_prefix = '`' . $db_name . '`.' . $db_prefix;
  137. mysqli_select_db($db_name);
  138. $request = smf_query("
  139. SELECT `variable`, `value`
  140. FROM {$db_prefix}settings",__FILE__,__LINE__);
  141. $smf_settings = array();
  142. while ($row = @mysqli_fetch_row($request))
  143. $smf_settings[$row[0]] = $row[1];
  144. mysqli_free_result($request);
  145. }
  146. // Load stuff from the Settings.php file into $smf_settings.
  147. $smf_settings['cookiename'] = $cookiename;
  148. $smf_settings['language'] = $language;
  149. $smf_settings['forum_name'] = $mbname;
  150. $smf_settings['forum_url'] = $boardurl;
  151. $smf_settings['webmaster_email'] = $webmaster_email;
  152. $smf_settings['db_prefix'] = $db_prefix;
  153. $smf_user_info = array();
  154. // Actually set the login cookie...
  155. function smf_setLoginCookie($cookie_length, $id, $password = '', $encrypted = true)
  156. {
  157. // This should come from Settings.php, hopefully.
  158. global $smf_connection, $smf_settings;
  159. // The $id is not numeric; it's probably a username.
  160. if (!is_integer($id))
  161. {
  162. if (!$smf_connection)
  163. return false;
  164. // Save for later use.
  165. $username = $id;
  166. $result = smf_query("
  167. SELECT id_member
  168. FROM $smf_settings[db_prefix]members
  169. WHERE member_name = '$username'
  170. LIMIT 1", __FILE__, __LINE__);
  171. list ($id) = mysqli_fetch_row($result);
  172. mysqli_free_result($result);
  173. // It wasn't found, after all?
  174. if (empty($id))
  175. {
  176. $id = (int) $username;
  177. unset($username);
  178. }
  179. }
  180. // Oh well, I guess it just was not to be...
  181. if (empty($id))
  182. return false;
  183. // The password isn't encrypted, do so.
  184. if (!$encrypted)
  185. {
  186. if (!$smf_connection)
  187. return false;
  188. $result = smf_query("
  189. SELECT member_name, password_salt
  190. FROM $smf_settings[db_prefix]members
  191. WHERE id_member = '" . (int) $id . "'
  192. LIMIT 1", __FILE__, __LINE__);
  193. list ($username, $salt) = mysqli_fetch_row($result);
  194. mysqli_free_result($result);
  195. if (empty($username))
  196. return false;
  197. $password = sha1(sha1(strtolower($username) . $password) . $salt);
  198. }
  199. function smf_cookie_url($local, $global)
  200. {
  201. // Use PHP to parse the URL, hopefully it does its job.
  202. $parsed_url = parse_url($smf_settings['forum_url']);
  203. if (isset($parsed_url['port']))
  204. $parsed_url['host'] .= ':' . $parsed_url['port'];
  205. // Set the cookie to the forum's path only?
  206. if (empty($parsed_url['path']) || !$local)
  207. $parsed_url['path'] = '';
  208. // This is probably very likely for apis and such, no?
  209. if ($global)
  210. {
  211. // Try to figure out where to set the cookie; this can be confused, though.
  212. if (preg_match('~(?:[^\.]+\.)?(.+)\z~i', $parsed_url['host'], $parts) == 1)
  213. $parsed_url['host'] = '.' . $parts[1];
  214. }
  215. // If both options are off, just use no host and /.
  216. elseif (!$local)
  217. $parsed_url['host'] = '';
  218. }
  219. // The cookie may already exist, and have been set with different options.
  220. $cookie_state = (empty($smf_settings['localCookies']) ? 0 : 1) | (empty($smf_settings['globalCookies']) ? 0 : 2);
  221. if (isset($_COOKIE[$smf_settings['cookiename']]))
  222. {
  223. $array = @unserialize($_COOKIE[$smf_settings['cookiename']]);
  224. if (isset($array[3]) && $array[3] != $cookie_state)
  225. {
  226. $cookie_url = smf_cookie_url($array[3] & 1 > 0, $array[3] & 2 > 0);
  227. setcookie($smf_settings['cookiename'], serialize(array(0, '', 0)), time() - 3600, $parsed_url['path'] . '/', $parsed_url['host'], 0);
  228. }
  229. }
  230. // Get the data and path to set it on.
  231. $data = serialize(empty($id) ? array(0, '', 0) : array($id, $password, time() + $cookie_length));
  232. $parsed_url = smf_cookie_url(!empty($smf_settings['localCookies']), !empty($smf_settings['globalCookies']));
  233. // Set the cookie, $_COOKIE, and session variable.
  234. setcookie($smf_settings['cookiename'], $data, time() + $cookie_length, $parsed_url['path'] . '/', $parsed_url['host'], 0);
  235. $_COOKIE[$smf_settings['cookiename']] = $data;
  236. $_SESSION['login_' . $smf_settings['cookiename']] = $data;
  237. return true;
  238. }
  239. function smf_authenticateUser()
  240. {
  241. global $smf_connection, $smf_settings, $smf_user_info;
  242. // No connection, no authentication!
  243. if (!$smf_connection)
  244. return false;
  245. // Check first the cookie, then the session.
  246. if (isset($_COOKIE[$smf_settings['cookiename']]))
  247. {
  248. $_COOKIE[$smf_settings['cookiename']] = stripslashes($_COOKIE[$smf_settings['cookiename']]);
  249. // Fix a security hole in PHP 4.3.9 and below...
  250. if (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[$smf_settings['cookiename']]) == 1)
  251. {
  252. list ($ID_MEMBER, $password) = @unserialize($_COOKIE[$smf_settings['cookiename']]);
  253. $ID_MEMBER = !empty($ID_MEMBER) ? (int) $ID_MEMBER : 0;
  254. }
  255. else
  256. $ID_MEMBER = 0;
  257. }
  258. elseif (isset($_SESSION['login_' . $smf_settings['cookiename']]))
  259. {
  260. list ($ID_MEMBER, $password, $login_span) = @unserialize(stripslashes($_SESSION['login_' . $smf_settings['cookiename']]));
  261. $ID_MEMBER = !empty($ID_MEMBER) && $login_span > time() ? (int) $ID_MEMBER : 0;
  262. }
  263. else
  264. $ID_MEMBER = 0;
  265. // Don't even bother if they have no authentication data.
  266. if (!empty($ID_MEMBER))
  267. {
  268. $request = smf_query("
  269. SELECT *
  270. FROM $smf_settings[db_prefix]members
  271. WHERE id_member = $ID_MEMBER
  272. LIMIT 1", __FILE__, __LINE__);
  273. // Did we find 'im? If not, junk it.
  274. if (mysqli_num_rows($request) != 0)
  275. {
  276. // The base settings array.
  277. $smf_user_info += mysqli_fetch_assoc($request);
  278. if (strlen($password) == 40)
  279. $check = sha1($smf_user_info['passwd'] . $smf_user_info['password_salt']) == $password;
  280. else
  281. $check = false;
  282. // Wrong password or not activated - either way, you're going nowhere.
  283. $ID_MEMBER = $check && ($smf_user_info['is_activated'] == 1 || $smf_user_info['is_activated'] == 11) ? $smf_user_info['id_member'] : 0;
  284. }
  285. else
  286. $ID_MEMBER = 0;
  287. mysqli_free_result($request);
  288. }
  289. if (empty($ID_MEMBER))
  290. $smf_user_info = array('groups' => array(-1));
  291. else
  292. {
  293. if (empty($smf_user_info['additional_groups']))
  294. $smf_user_info['groups'] = array($smf_user_info['id_group'], $smf_user_info['id_post_group']);
  295. else
  296. $smf_user_info['groups'] = array_merge(
  297. array($smf_user_info['id_group'], $smf_user_info['id_post_group']),
  298. explode(',', $smf_user_info['additional_groups'])
  299. );
  300. }
  301. // A few things to make life easier...
  302. $smf_user_info['id'] = &$smf_user_info['id_member'];
  303. $smf_user_info['username'] = &$smf_user_info['member_name'];
  304. $smf_user_info['name'] = &$smf_user_info['real_name'];
  305. $smf_user_info['email'] = &$smf_user_info['email_address'];
  306. $smf_user_info['messages'] = &$smf_user_info['instant_messages'];
  307. $smf_user_info['unread_messages'] = &$smf_user_info['unread_messages'];
  308. $smf_user_info['language'] = empty($smf_user_info['lngfile']) || empty($smf_settings['user_language']) ? $smf_settings['language'] : $smf_user_info['lngfile'];
  309. $smf_user_info['is_guest'] = $ID_MEMBER == 0;
  310. $smf_user_info['is_admin'] = in_array(1, $smf_user_info['groups']);
  311. // This might be set to "forum default"...
  312. if (empty($smf_user_info['timeFormat']))
  313. $smf_user_info['timeFormat'] = $smf_settings['time_format'];
  314. return !$smf_user_info['is_guest'];
  315. }
  316. function smf_registerMember($username, $email, $password, $extra_fields = array(), $theme_options = array())
  317. {
  318. global $smf_settings, $smf_connection;
  319. // No connection means no registrations...
  320. if (!$smf_connection)
  321. return false;
  322. // Can't use that username.
  323. if (preg_match('~[<>&"\'=\\\]~', $username) != 0 || $username == '_' || $username == '|' || strpos($username, '[code') !== false || strpos($username, '[/code') !== false)
  324. return false;
  325. // !!! Validate username isn't already used? Validate reserved, etc.?
  326. $register_vars = array(
  327. 'memberName' => "'$username'",
  328. 'realName' => "'$username'",
  329. 'passwd' => '\'' . sha1(strtolower($username) . $password) . '\'',
  330. 'passwordSalt' => '\'' . substr(md5(rand()), 0, 4) . '\'',
  331. 'posts' => 0,
  332. 'dateRegistered' => time(),
  333. 'is_activated' => 1,
  334. 'personalText' => '\'' . addslashes($smf_settings['default_personalText']) . '\'',
  335. 'pm_email_notify' => 1,
  336. 'ID_THEME' => 0,
  337. 'ID_POST_GROUP' => 4,
  338. );
  339. $register_vars = $extra_fields + $register_vars;
  340. smf_query("
  341. INSERT INTO $smf_settings[db_prefix]members
  342. (" . implode(', ', array_keys($register_vars)) . ")
  343. VALUES (" . implode(', ', $register_vars) . ')', __FILE__, __LINE__);
  344. $ID_MEMBER = db_insert_id();
  345. smf_query("
  346. UPDATE $smf_settings[db_prefix]settings
  347. SET value = value + 1
  348. WHERE variable = 'totalMembers'
  349. LIMIT 1", __FILE__, __LINE__);
  350. smf_query("
  351. REPLACE INTO $smf_settings[db_prefix]settings
  352. (variable, value)
  353. VALUES ('latestMember', $ID_MEMBER),
  354. ('latestRealName', '$username')", __FILE__, __LINE__);
  355. smf_query("
  356. UPDATE {$db_prefix}log_activity
  357. SET registers = registers + 1
  358. WHERE date = " . strftime('%Y%m%d') . "
  359. LIMIT 1", __FILE__, __LINE__);
  360. if (db_affected_rows() == 0)
  361. smf_query("
  362. INSERT IGNORE INTO {$db_prefix}log_activity
  363. (date, registers)
  364. VALUES (" . strftime('%Y%m%d') . ", 1)", __FILE__, __LINE__);
  365. // Theme variables too?
  366. if (!empty($theme_options))
  367. {
  368. $setString = '';
  369. foreach ($theme_options as $var => $val)
  370. $setString .= "
  371. ($memberID, '$var', '$val'),";
  372. smf_query("
  373. INSERT INTO $smf_settings[db_prefix]themes
  374. (ID_MEMBER, variable, value)
  375. VALUES " . substr($setString, 0, -1), __FILE__, __LINE__);
  376. }
  377. return $ID_MEMBER;
  378. }
  379. // Log the current user online.
  380. function smf_logOnline($action = null)
  381. {
  382. global $smf_settings, $smf_connection, $smf_user_info;
  383. if (!$smf_connection)
  384. return false;
  385. // Determine number of seconds required.
  386. $lastActive = $smf_settings['lastActive'] * 60;
  387. // Don't mark them as online more than every so often.
  388. if (empty($_SESSION['log_time']) || $_SESSION['log_time'] < (time() - 8))
  389. $_SESSION['log_time'] = time();
  390. else
  391. return;
  392. $serialized = $_GET;
  393. $serialized['USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'];
  394. unset($serialized['sesc']);
  395. if ($action !== null)
  396. $serialized['action'] = $action;
  397. $serialized = addslashes(serialize($serialized));
  398. // Guests use 0, members use ID_MEMBER.
  399. if ($smf_user_info['is_guest'])
  400. {
  401. smf_query("
  402. DELETE FROM $smf_settings[db_prefix]log_online
  403. WHERE log_time < NOW() - INTERVAL $lastActive SECOND OR session = 'ip$_SERVER[REMOTE_ADDR]'", __FILE__, __LINE__);
  404. smf_query("
  405. INSERT IGNORE INTO $smf_settings[db_prefix]log_online
  406. (session, id_member, ip, url)
  407. VALUES ('ip$_SERVER[REMOTE_ADDR]', 0, IFNULL(INET_ATON('$_SERVER[REMOTE_ADDR]'), 0), '$serialized')", __FILE__, __LINE__);
  408. }
  409. else
  410. {
  411. smf_query("
  412. DELETE FROM $smf_settings[db_prefix]log_online
  413. WHERE log_time < NOW() - INTERVAL $lastActive SECOND OR id_member = $smf_user_info[id] OR session = '" . @session_id() . "'", __FILE__, __LINE__);
  414. smf_query("
  415. INSERT IGNORE INTO $smf_settings[db_prefix]log_online
  416. (session, id_member, ip, url)
  417. VALUES ('" . @session_id() . "', $smf_user_info[id], IFNULL(INET_ATON('$_SERVER[REMOTE_ADDR]'), 0), '$serialized')", __FILE__, __LINE__);
  418. }
  419. }
  420. function smf_isOnline($user)
  421. {
  422. global $smf_settings, $smf_connection;
  423. if (!$smf_connection)
  424. return false;
  425. $result = smf_query("
  426. SELECT lo.id_member
  427. FROM $smf_settings[db_prefix]log_online AS lo" . (!is_integer($user) ? "
  428. LEFT JOIN $smf_settings[db_prefix]members AS mem ON (mem.id_member = lo.id_member)" : '') . "
  429. WHERE lo.id_member = " . (int) $user . (!is_integer($user) ? " OR mem.member_name = '$user'" : '') . "
  430. LIMIT 1", __FILE__, __LINE__);
  431. $return = mysqli_num_rows($result) != 0;
  432. mysqli_free_result($result);
  433. return $return;
  434. }
  435. // Log an error, if the option is on.
  436. function smf_logError($error_message, $file = null, $line = null)
  437. {
  438. global $smf_settings, $smf_connection;
  439. // Check if error logging is actually on and we're connected...
  440. if (empty($smf_settings['enableErrorLogging']) || !$smf_connection)
  441. return $error_message;
  442. // Basically, htmlspecialchars it minus &. (for entities!)
  443. $error_message = strtr($error_message, array('<' => '&lt;', '>' => '&gt;', '"' => '&quot;'));
  444. $error_message = strtr($error_message, array('&lt;br /&gt;' => '<br />', '&lt;b&gt;' => '<b>', '&lt;/b&gt;' => '</b>', "\n" => '<br />'));
  445. // Add a file and line to the error message?
  446. if ($file != null)
  447. $error_message .= '<br />' . $file;
  448. if ($line != null)
  449. $error_message .= '<br />' . $line;
  450. // Just in case there's no ID_MEMBER or IP set yet.
  451. if (empty($smf_user_info['id']))
  452. $smf_user_info['id'] = 0;
  453. // Insert the error into the database.
  454. smf_query("
  455. INSERT INTO $smf_settings[db_prefix]log_errors
  456. (ID_MEMBER, logTime, ip, url, message, session)
  457. VALUES ($smf_user_info[id], " . time() . ", '$_SERVER[REMOTE_ADDR]', '" . (empty($_SERVER['QUERY_STRING']) ? '' : addslashes(htmlspecialchars('?' . $_SERVER['QUERY_STRING']))) . "', '" . addslashes($error_message) . "', '" . @session_id() . "')", __FILE__, __LINE__);
  458. // Return the message to make things simpler.
  459. return $error_message;
  460. }
  461. // Format a time to make it look purdy.
  462. function smf_formatTime($logTime)
  463. {
  464. global $smf_user_info, $smf_settings;
  465. // Offset the time - but we can't have a negative date!
  466. $time = max($logTime + (@$smf_user_info['timeOffset'] + $smf_settings['time_offset']) * 3600, 0);
  467. // Format some in caps, and then any other characters..
  468. return strftime(strtr(!empty($smf_user_info['timeFormat']) ? $smf_user_info['timeFormat'] : $smf_settings['time_format'], array('%a' => ucwords(strftime('%a', $time)), '%A' => ucwords(strftime('%A', $time)), '%b' => ucwords(strftime('%b', $time)), '%B' => ucwords(strftime('%B', $time)))), $time);
  469. }
  470. // Do a query, and if it fails log an error in the SMF error log.
  471. function smf_query($string, $file, $line)
  472. {
  473. global $smf_settings, $smf_connection;
  474. if (!$smf_connection)
  475. return false;
  476. $smf_settings['db_count'] = @$smf_settings['db_count'] + 1;
  477. $ret = mysqli_query($string, $smf_connection);
  478. if ($ret === false)
  479. smf_logError(mysqli_error($smf_connection), $file, $line);
  480. return $ret;
  481. }
  482. // Mother, may I?
  483. function smf_allowedTo($permission)
  484. {
  485. global $smf_settings, $smf_user_info, $smf_connection;
  486. if (!$smf_connection)
  487. return null;
  488. // Administrators can do all, and everyone can do nothing.
  489. if ($smf_user_info['is_admin'] || empty($permission))
  490. return true;
  491. if (!isset($smf_user_info['permissions']))
  492. {
  493. $result = smf_query("
  494. SELECT permission, add_deny
  495. FROM $smf_settings[db_prefix]permissions
  496. WHERE id_group IN (" . implode(', ', $smf_user_info['groups']) . ")", __FILE__, __LINE__);
  497. $removals = array();
  498. $smf_user_info['permissions'] = array();
  499. while ($row = mysqli_fetch_assoc($result))
  500. {
  501. if (empty($row['add_deny']))
  502. $removals[] = $row['permission'];
  503. else
  504. $smf_user_info['permissions'][] = $row['permission'];
  505. }
  506. mysqli_free_result($result);
  507. // And now we get rid of the removals ;).
  508. if (!empty($smf_settings['permission_enable_deny']))
  509. $smf_user_info['permissions'] = array_diff($smf_user_info['permissions'], $removals);
  510. }
  511. // So.... can you?
  512. if (!is_array($permission) && in_array($permission, $smf_user_info['permissions']))
  513. return true;
  514. elseif (is_array($permission) && count(array_intersect($permission, $smf_user_info['permissions'])) != 0)
  515. return true;
  516. else
  517. return false;
  518. }
  519. function smf_loadThemeData($ID_THEME = 0)
  520. {
  521. global $smf_settings, $smf_user_info, $smf_connection;
  522. if (!$smf_connection)
  523. return null;
  524. // The theme was specified by parameter.
  525. if (!empty($ID_THEME))
  526. $theme = (int) $ID_THEME;
  527. // The theme was specified by REQUEST.
  528. elseif (!empty($_REQUEST['theme']))
  529. {
  530. $theme = (int) $_REQUEST['theme'];
  531. $_SESSION['ID_THEME'] = $theme;
  532. }
  533. // The theme was specified by REQUEST... previously.
  534. elseif (!empty($_SESSION['ID_THEME']))
  535. $theme = (int) $_SESSION['ID_THEME'];
  536. // The theme is just the user's choice. (might use ?board=1;theme=0 to force board theme.)
  537. elseif (!empty($smf_user_info['theme']) && !isset($_REQUEST['theme']))
  538. $theme = $smf_user_info['theme'];
  539. // The theme is the forum's default.
  540. else
  541. $theme = $smf_settings['theme_guests'];
  542. // Verify the ID_THEME... no foul play.
  543. if (empty($smf_settings['theme_default']) && $theme == 1 && $ID_THEME != 1)
  544. $theme = $smf_settings['theme_guests'];
  545. elseif (!empty($smf_settings['knownThemes']) && !empty($smf_settings['theme_allow']))
  546. {
  547. $themes = explode(',', $smf_settings['knownThemes']);
  548. if (!in_array($theme, $themes))
  549. $theme = $smf_settings['theme_guests'];
  550. else
  551. $theme = (int) $theme;
  552. }
  553. else
  554. $theme = (int) $theme;
  555. $member = empty($smf_user_info['id']) ? -1 : $smf_user_info['id'];
  556. // Load variables from the current or default theme, global or this user's.
  557. $result = smf_query("
  558. SELECT variable, value, id_member, id_theme
  559. FROM $smf_settings[db_prefix]themes
  560. WHERE id_member IN (-1, 0, $member)
  561. AND id_theme" . ($theme == 1 ? ' = 1' : " IN ($theme, 1)"), __FILE__, __LINE__);
  562. // Pick between $smf_settings['theme'] and $smf_user_info['theme'] depending on whose data it is.
  563. $themeData = array(0 => array(), $member => array());
  564. while ($row = mysqli_fetch_assoc($result))
  565. {
  566. // If this is the themedir of the default theme, store it.
  567. if (in_array($row['variable'], array('theme_dir', 'theme_url', 'images_url')) && $row['id_theme'] == '1' && empty($row['id_member']))
  568. $themeData[0]['default_' . $row['variable']] = $row['value'];
  569. // If this isn't set yet, is a theme option, or is not the default theme..
  570. if (!isset($themeData[$row['id_member']][$row['variable']]) || $row['id_theme'] != '1')
  571. $themeData[$row['id_member']][$row['variable']] = substr($row['variable'], 0, 5) == 'show_' ? $row['value'] == '1' : $row['value'];
  572. }
  573. mysqli_free_result($result);
  574. $smf_settings['theme'] = $themeData[0];
  575. $smf_user_info['theme'] = $themeData[$member];
  576. if (!empty($themeData[-1]))
  577. foreach ($themeData[-1] as $k => $v)
  578. {
  579. if (!isset($smf_user_info['theme'][$k]))
  580. $smf_user_info['theme'][$k] = $v;
  581. }
  582. $smf_settings['theme']['theme_id'] = $theme;
  583. $smf_settings['theme']['actual_theme_url'] = $smf_settings['theme']['theme_url'];
  584. $smf_settings['theme']['actual_images_url'] = $smf_settings['theme']['images_url'];
  585. $smf_settings['theme']['actual_theme_dir'] = $smf_settings['theme']['theme_dir'];
  586. }
  587. // Attempt to start the session, unless it already has been.
  588. function smf_loadSession()
  589. {
  590. global $HTTP_SESSION_VARS, $smf_connection, $smf_settings, $smf_user_info;
  591. // Attempt to change a few PHP settings.
  592. @ini_set('session.use_cookies', true);
  593. @ini_set('session.use_only_cookies', false);
  594. @ini_set('arg_separator.output', '&amp;');
  595. // If it's already been started... probably best to skip this.
  596. if ((@ini_get('session.auto_start') == 1 && !empty($smf_settings['databaseSession_enable'])) || session_id() == '')
  597. {
  598. // Attempt to end the already-started session.
  599. if (@ini_get('session.auto_start') == 1)
  600. @session_write_close();
  601. // This is here to stop people from using bad junky PHPSESSIDs.
  602. if (isset($_REQUEST[session_name()]) && preg_match('~^[A-Za-z0-9]{32}$~', $_REQUEST[session_name()]) == 0 && !isset($_COOKIE[session_name()]))
  603. $_COOKIE[session_name()] = md5(md5('smf_sess_' . time()) . rand());
  604. // Use database sessions?
  605. if (!empty($smf_settings['databaseSession_enable']) && $smf_connection)
  606. session_set_save_handler('smf_sessionOpen', 'smf_sessionClose', 'smf_sessionRead', 'smf_sessionWrite', 'smf_sessionDestroy', 'smf_sessionGC');
  607. elseif (@ini_get('session.gc_maxlifetime') <= 1440 && !empty($smf_settings['databaseSession_lifetime']))
  608. @ini_set('session.gc_maxlifetime', max($smf_settings['databaseSession_lifetime'], 60));
  609. session_start();
  610. }
  611. // While PHP 4.1.x should use $_SESSION, it seems to need this to do it right.
  612. if (@version_compare(PHP_VERSION, '4.2.0') == -1)
  613. $HTTP_SESSION_VARS['smf_php_412_bugfix'] = true;
  614. // Set the randomly generated code.
  615. if (!isset($_SESSION['rand_code']))
  616. $_SESSION['rand_code'] = md5(session_id() . rand());
  617. $smf_user_info['session_id'] = &$_SESSION['rand_code'];
  618. if (!isset($_SESSION['USER_AGENT']))
  619. $_SESSION['USER_AGENT'] = $_SERVER['HTTP_USER_AGENT'];
  620. }
  621. function smf_sessionOpen($save_path, $session_name)
  622. {
  623. return true;
  624. }
  625. function smf_sessionClose()
  626. {
  627. return true;
  628. }
  629. function smf_sessionRead($session_id)
  630. {
  631. global $smf_settings;
  632. if (preg_match('~^[A-Za-z0-9]{16,32}$~', $session_id) == 0)
  633. return false;
  634. // Look for it in the database.
  635. $result = smf_query("
  636. SELECT data
  637. FROM $smf_settings[db_prefix]sessions
  638. WHERE session_id = '" . addslashes($session_id) . "'
  639. LIMIT 1", __FILE__, __LINE__);
  640. list ($sess_data) = mysqli_fetch_row($result);
  641. mysqli_free_result($result);
  642. return $sess_data;
  643. }
  644. function smf_sessionWrite($session_id, $data)
  645. {
  646. global $smf_settings, $smf_connection;
  647. if (preg_match('~^[A-Za-z0-9]{16,32}$~', $session_id) == 0)
  648. return false;
  649. // First try to update an existing row...
  650. $result = smf_query("
  651. UPDATE $smf_settings[db_prefix]sessions
  652. SET data = '" . addslashes($data) . "', last_update = " . time() . "
  653. WHERE session_id = '" . addslashes($session_id) . "'
  654. LIMIT 1", __FILE__, __LINE__);
  655. // If that didn't work, try inserting a new one.
  656. if (mysqli_affected_rows($smf_connection) == 0)
  657. $result = smf_query("
  658. INSERT IGNORE INTO $smf_settings[db_prefix]sessions
  659. (session_id, data, last_update)
  660. VALUES ('" . addslashes($session_id) . "', '" . addslashes($data) . "', " . time() . ")", __FILE__, __LINE__);
  661. return $result;
  662. }
  663. function smf_sessionDestroy($session_id)
  664. {
  665. global $smf_settings;
  666. if (preg_match('~^[A-Za-z0-9]{16,32}$~', $session_id) == 0)
  667. return false;
  668. // Just delete the row...
  669. return smf_query("
  670. DELETE FROM $smf_settings[db_prefix]sessions
  671. WHERE session_id = '" . addslashes($session_id) . "'
  672. LIMIT 1", __FILE__, __LINE__);
  673. }
  674. function smf_sessionGC($max_lifetime)
  675. {
  676. global $smf_settings;
  677. // Just set to the default or lower? Ignore it for a higher value. (hopefully)
  678. if ($max_lifetime <= 1440 && !empty($smf_settings['databaseSession_lifetime']))
  679. $max_lifetime = max($smf_settings['databaseSession_lifetime'], 60);
  680. // Clean up ;).
  681. return smf_query("
  682. DELETE FROM $smf_settings[db_prefix]sessions
  683. WHERE last_update < " . (time() - $max_lifetime), __FILE__, __LINE__);
  684. }
  685. // Define the sha1 function, if it doesn't exist (but the built in one would be faster.)
  686. if (!function_exists('sha1'))
  687. {
  688. function sha1($str)
  689. {
  690. // If we have mhash loaded in, use it instead!
  691. if (function_exists('mhash') && defined('MHASH_SHA1'))
  692. return bin2hex(mhash(MHASH_SHA1, $str));
  693. $nblk = (strlen($str) + 8 >> 6) + 1;
  694. $blks = array_pad(array(), $nblk * 16, 0);
  695. for ($i = 0; $i < strlen($str); $i++)
  696. $blks[$i >> 2] |= ord($str{$i}) << (24 - ($i % 4) * 8);
  697. $blks[$i >> 2] |= 0x80 << (24 - ($i % 4) * 8);
  698. return sha1_core($blks, strlen($str) * 8);
  699. }
  700. // This is the core SHA-1 calculation routine, used by sha1().
  701. function sha1_core($x, $len)
  702. {
  703. @$x[$len >> 5] |= 0x80 << (24 - $len % 32);
  704. $x[(($len + 64 >> 9) << 4) + 15] = $len;
  705. $w = array();
  706. $a = 1732584193;
  707. $b = -271733879;
  708. $c = -1732584194;
  709. $d = 271733878;
  710. $e = -1009589776;
  711. for ($i = 0, $n = count($x); $i < $n; $i += 16)
  712. {
  713. $olda = $a;
  714. $oldb = $b;
  715. $oldc = $c;
  716. $oldd = $d;
  717. $olde = $e;
  718. for ($j = 0; $j < 80; $j++)
  719. {
  720. if ($j < 16)
  721. $w[$j] = @$x[$i + $j];
  722. else
  723. $w[$j] = sha1_rol($w[$j - 3] ^ $w[$j - 8] ^ $w[$j - 14] ^ $w[$j - 16], 1);
  724. $t = sha1_rol($a, 5) + sha1_ft($j, $b, $c, $d) + $e + $w[$j] + sha1_kt($j);
  725. $e = $d;
  726. $d = $c;
  727. $c = sha1_rol($b, 30);
  728. $b = $a;
  729. $a = $t;
  730. }
  731. $a += $olda;
  732. $b += $oldb;
  733. $c += $oldc;
  734. $d += $oldd;
  735. $e += $olde;
  736. }
  737. return dechex($a) . dechex($b) . dechex($c) . dechex($d) . dechex($e);
  738. }
  739. function sha1_ft($t, $b, $c, $d)
  740. {
  741. if ($t < 20)
  742. return ($b & $c) | ((~$b) & $d);
  743. if ($t < 40)
  744. return $b ^ $c ^ $d;
  745. if ($t < 60)
  746. return ($b & $c) | ($b & $d) | ($c & $d);
  747. return $b ^ $c ^ $d;
  748. }
  749. function sha1_kt($t)
  750. {
  751. return $t < 20 ? 1518500249 : ($t < 40 ? 1859775393 : ($t < 60 ? -1894007588 : -899497514));
  752. }
  753. function sha1_rol($num, $cnt)
  754. {
  755. $z = 0x80000000;
  756. if ($z & $num)
  757. $a = ($num >> 1 & (~$z | 0x40000000)) >> (31 - $cnt);
  758. else
  759. $a = $num >> (32 - $cnt);
  760. return ($num << $cnt) | $a;
  761. }
  762. }
  763. ?>