annotate forum/Sources/Subs-Auth.php @ 88:4ff5a6ad1b2b website

Split out RDF to a subrepository (in the Vamp Known Plugins RDF project)
author Chris Cannam
date Tue, 25 Mar 2014 13:24:36 +0000
parents e3e11437ecea
children
rev   line source
Chris@76 1 <?php
Chris@76 2
Chris@76 3 /**
Chris@76 4 * Simple Machines Forum (SMF)
Chris@76 5 *
Chris@76 6 * @package SMF
Chris@76 7 * @author Simple Machines http://www.simplemachines.org
Chris@76 8 * @copyright 2011 Simple Machines
Chris@76 9 * @license http://www.simplemachines.org/about/smf/license.php BSD
Chris@76 10 *
Chris@76 11 * @version 2.0
Chris@76 12 */
Chris@76 13
Chris@76 14 if (!defined('SMF'))
Chris@76 15 die('Hacking attempt...');
Chris@76 16
Chris@76 17 /* This file has functions in it to do with authentication, user handling,
Chris@76 18 and the like. It provides these functions:
Chris@76 19
Chris@76 20 void setLoginCookie(int cookie_length, int id_member, string password = '')
Chris@76 21 - sets the SMF-style login cookie and session based on the id_member
Chris@76 22 and password passed.
Chris@76 23 - password should be already encrypted with the cookie salt.
Chris@76 24 - logs the user out if id_member is zero.
Chris@76 25 - sets the cookie and session to last the number of seconds specified
Chris@76 26 by cookie_length.
Chris@76 27 - when logging out, if the globalCookies setting is enabled, attempts
Chris@76 28 to clear the subdomain's cookie too.
Chris@76 29
Chris@76 30 array url_parts(bool local, bool global)
Chris@76 31 - returns the path and domain to set the cookie on.
Chris@76 32 - normally, local and global should be the localCookies and
Chris@76 33 globalCookies settings, respectively.
Chris@76 34 - uses boardurl to determine these two things.
Chris@76 35 - returns an array with domain and path in it, in that order.
Chris@76 36
Chris@76 37 void KickGuest()
Chris@76 38 - throws guests out to the login screen when guest access is off.
Chris@76 39 - sets $_SESSION['login_url'] to $_SERVER['REQUEST_URL'].
Chris@76 40 - uses the 'kick_guest' sub template found in Login.template.php.
Chris@76 41
Chris@76 42 void InMaintenance()
Chris@76 43 - display a message about being in maintenance mode.
Chris@76 44 - display a login screen with sub template 'maintenance'.
Chris@76 45
Chris@76 46 void adminLogin()
Chris@76 47 - double check the verity of the admin by asking for his or her
Chris@76 48 password.
Chris@76 49 - loads Login.template.php and uses the admin_login sub template.
Chris@76 50 - sends data to template so the admin is sent on to the page they
Chris@76 51 wanted if their password is correct, otherwise they can try
Chris@76 52 again.
Chris@76 53
Chris@76 54 string adminLogin_outputPostVars(string key, string value)
Chris@76 55 - used by the adminLogin() function.
Chris@76 56 - returns 'hidden' HTML form fields, containing key-value-pairs.
Chris@76 57 - if 'value' is an array, the function is called recursively.
Chris@76 58
Chris@76 59 array findMembers(array names, bool use_wildcards = false,
Chris@76 60 bool buddies_only = false, int max = 500)
Chris@76 61 - searches for members whose username, display name, or e-mail address
Chris@76 62 match the given pattern of array names.
Chris@76 63 - accepts wildcards ? and * in the patern if use_wildcards is set.
Chris@76 64 - retrieves a maximum of max members, if passed.
Chris@76 65 - searches only buddies if buddies_only is set.
Chris@76 66 - returns an array containing information about the matching members.
Chris@76 67
Chris@76 68 void JSMembers()
Chris@76 69 - called by index.php?action=findmember.
Chris@76 70 - is used as a popup for searching members.
Chris@76 71 - uses sub template find_members of the Help template.
Chris@76 72 - also used to add members for PM's sent using wap2/imode protocol.
Chris@76 73
Chris@76 74 void RequestMembers()
Chris@76 75 - used by javascript to find members matching the request.
Chris@76 76 - outputs each member name on its own line.
Chris@76 77
Chris@76 78 void resetPassword(int id_member, string username = null)
Chris@76 79 - called by Profile.php when changing someone's username.
Chris@76 80 - checks the validity of the new username.
Chris@76 81 - generates and sets a new password for the given user.
Chris@76 82 - mails the new password to the email address of the user.
Chris@76 83 - if username is not set, only a new password is generated and sent.
Chris@76 84
Chris@76 85 string validateUsername(int memID, string username)
Chris@76 86 - checks a username obeys a load of rules. Returns null if fine.
Chris@76 87
Chris@76 88 string validatePassword(string password, string username,
Chris@76 89 array restrict_in = none)
Chris@76 90 - called when registering/choosing a password.
Chris@76 91 - checks the password obeys the current forum settings for password
Chris@76 92 strength.
Chris@76 93 - if password checking is enabled, will check that none of the words
Chris@76 94 in restrict_in appear in the password.
Chris@76 95 - returns an error identifier if the password is invalid, or null.
Chris@76 96
Chris@76 97 void rebuildModCache()
Chris@76 98 - stores some useful information on the current users moderation powers in the session.
Chris@76 99
Chris@76 100 */
Chris@76 101
Chris@76 102 // Actually set the login cookie...
Chris@76 103 function setLoginCookie($cookie_length, $id, $password = '')
Chris@76 104 {
Chris@76 105 global $cookiename, $boardurl, $modSettings;
Chris@76 106
Chris@76 107 // If changing state force them to re-address some permission caching.
Chris@76 108 $_SESSION['mc']['time'] = 0;
Chris@76 109
Chris@76 110 // The cookie may already exist, and have been set with different options.
Chris@76 111 $cookie_state = (empty($modSettings['localCookies']) ? 0 : 1) | (empty($modSettings['globalCookies']) ? 0 : 2);
Chris@76 112 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)
Chris@76 113 {
Chris@76 114 $array = @unserialize($_COOKIE[$cookiename]);
Chris@76 115
Chris@76 116 // Out with the old, in with the new!
Chris@76 117 if (isset($array[3]) && $array[3] != $cookie_state)
Chris@76 118 {
Chris@76 119 $cookie_url = url_parts($array[3] & 1 > 0, $array[3] & 2 > 0);
Chris@76 120 setcookie($cookiename, serialize(array(0, '', 0)), time() - 3600, $cookie_url[1], $cookie_url[0], !empty($modSettings['secureCookies']));
Chris@76 121 }
Chris@76 122 }
Chris@76 123
Chris@76 124 // Get the data and path to set it on.
Chris@76 125 $data = serialize(empty($id) ? array(0, '', 0) : array($id, $password, time() + $cookie_length, $cookie_state));
Chris@76 126 $cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies']));
Chris@76 127
Chris@76 128 // Set the cookie, $_COOKIE, and session variable.
Chris@76 129 setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0], !empty($modSettings['secureCookies']));
Chris@76 130
Chris@76 131 // If subdomain-independent cookies are on, unset the subdomain-dependent cookie too.
Chris@76 132 if (empty($id) && !empty($modSettings['globalCookies']))
Chris@76 133 setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], '', !empty($modSettings['secureCookies']));
Chris@76 134
Chris@76 135 // Any alias URLs? This is mainly for use with frames, etc.
Chris@76 136 if (!empty($modSettings['forum_alias_urls']))
Chris@76 137 {
Chris@76 138 $aliases = explode(',', $modSettings['forum_alias_urls']);
Chris@76 139
Chris@76 140 $temp = $boardurl;
Chris@76 141 foreach ($aliases as $alias)
Chris@76 142 {
Chris@76 143 // Fake the $boardurl so we can set a different cookie.
Chris@76 144 $alias = strtr(trim($alias), array('http://' => '', 'https://' => ''));
Chris@76 145 $boardurl = 'http://' . $alias;
Chris@76 146
Chris@76 147 $cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies']));
Chris@76 148
Chris@76 149 if ($cookie_url[0] == '')
Chris@76 150 $cookie_url[0] = strtok($alias, '/');
Chris@76 151
Chris@76 152 setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0], !empty($modSettings['secureCookies']));
Chris@76 153 }
Chris@76 154
Chris@76 155 $boardurl = $temp;
Chris@76 156 }
Chris@76 157
Chris@76 158 $_COOKIE[$cookiename] = $data;
Chris@76 159
Chris@76 160 // Make sure the user logs in with a new session ID.
Chris@76 161 if (!isset($_SESSION['login_' . $cookiename]) || $_SESSION['login_' . $cookiename] !== $data)
Chris@76 162 {
Chris@76 163 // Backup and remove the old session.
Chris@76 164 $oldSessionData = $_SESSION;
Chris@76 165 $_SESSION = array();
Chris@76 166 session_destroy();
Chris@76 167
Chris@76 168 // Recreate and restore the new session.
Chris@76 169 loadSession();
Chris@76 170 session_regenerate_id();
Chris@76 171 $_SESSION = $oldSessionData;
Chris@76 172
Chris@76 173 // Version 4.3.2 didn't store the cookie of the new session.
Chris@76 174 if (version_compare(PHP_VERSION, '4.3.2') === 0)
Chris@76 175 {
Chris@76 176 $sessionCookieLifetime = @ini_get('session.cookie_lifetime');
Chris@76 177 setcookie(session_name(), session_id(), time() + (empty($sessionCookieLifetime) ? $cookie_length : $sessionCookieLifetime), $cookie_url[1], $cookie_url[0], !empty($modSettings['secureCookies']));
Chris@76 178 }
Chris@76 179
Chris@76 180 $_SESSION['login_' . $cookiename] = $data;
Chris@76 181 }
Chris@76 182 }
Chris@76 183
Chris@76 184 // PHP < 4.3.2 doesn't have this function
Chris@76 185 if (!function_exists('session_regenerate_id'))
Chris@76 186 {
Chris@76 187 function session_regenerate_id()
Chris@76 188 {
Chris@76 189 // Too late to change the session now.
Chris@76 190 if (headers_sent())
Chris@76 191 return false;
Chris@76 192
Chris@76 193 session_id(strtolower(md5(uniqid(mt_rand(), true))));
Chris@76 194 return true;
Chris@76 195 }
Chris@76 196
Chris@76 197 }
Chris@76 198
Chris@76 199 // Get the domain and path for the cookie...
Chris@76 200 function url_parts($local, $global)
Chris@76 201 {
Chris@76 202 global $boardurl;
Chris@76 203
Chris@76 204 // Parse the URL with PHP to make life easier.
Chris@76 205 $parsed_url = parse_url($boardurl);
Chris@76 206
Chris@76 207 // Is local cookies off?
Chris@76 208 if (empty($parsed_url['path']) || !$local)
Chris@76 209 $parsed_url['path'] = '';
Chris@76 210
Chris@76 211 // Globalize cookies across domains (filter out IP-addresses)?
Chris@76 212 if ($global && preg_match('~^\d{1,3}(\.\d{1,3}){3}$~', $parsed_url['host']) == 0 && preg_match('~(?:[^\.]+\.)?([^\.]{2,}\..+)\z~i', $parsed_url['host'], $parts) == 1)
Chris@76 213 $parsed_url['host'] = '.' . $parts[1];
Chris@76 214
Chris@76 215 // We shouldn't use a host at all if both options are off.
Chris@76 216 elseif (!$local && !$global)
Chris@76 217 $parsed_url['host'] = '';
Chris@76 218
Chris@76 219 // The host also shouldn't be set if there aren't any dots in it.
Chris@76 220 elseif (!isset($parsed_url['host']) || strpos($parsed_url['host'], '.') === false)
Chris@76 221 $parsed_url['host'] = '';
Chris@76 222
Chris@76 223 return array($parsed_url['host'], $parsed_url['path'] . '/');
Chris@76 224 }
Chris@76 225
Chris@76 226 // Kick out a guest when guest access is off...
Chris@76 227 function KickGuest()
Chris@76 228 {
Chris@76 229 global $txt, $context;
Chris@76 230
Chris@76 231 loadLanguage('Login');
Chris@76 232 loadTemplate('Login');
Chris@76 233
Chris@76 234 // Never redirect to an attachment
Chris@76 235 if (strpos($_SERVER['REQUEST_URL'], 'dlattach') === false)
Chris@76 236 $_SESSION['login_url'] = $_SERVER['REQUEST_URL'];
Chris@76 237
Chris@76 238 $context['sub_template'] = 'kick_guest';
Chris@76 239 $context['page_title'] = $txt['login'];
Chris@76 240 }
Chris@76 241
Chris@76 242 // Display a message about the forum being in maintenance mode, etc.
Chris@76 243 function InMaintenance()
Chris@76 244 {
Chris@76 245 global $txt, $mtitle, $mmessage, $context;
Chris@76 246
Chris@76 247 loadLanguage('Login');
Chris@76 248 loadTemplate('Login');
Chris@76 249
Chris@76 250 // Send a 503 header, so search engines don't bother indexing while we're in maintenance mode.
Chris@76 251 header('HTTP/1.1 503 Service Temporarily Unavailable');
Chris@76 252
Chris@76 253 // Basic template stuff..
Chris@76 254 $context['sub_template'] = 'maintenance';
Chris@76 255 $context['title'] = &$mtitle;
Chris@76 256 $context['description'] = &$mmessage;
Chris@76 257 $context['page_title'] = $txt['maintain_mode'];
Chris@76 258 }
Chris@76 259
Chris@76 260 function adminLogin()
Chris@76 261 {
Chris@76 262 global $context, $scripturl, $txt, $user_info, $user_settings;
Chris@76 263
Chris@76 264 loadLanguage('Admin');
Chris@76 265 loadTemplate('Login');
Chris@76 266
Chris@76 267 // They used a wrong password, log it and unset that.
Chris@76 268 if (isset($_POST['admin_hash_pass']) || isset($_POST['admin_pass']))
Chris@76 269 {
Chris@76 270 $txt['security_wrong'] = sprintf($txt['security_wrong'], isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $txt['unknown'], $_SERVER['HTTP_USER_AGENT'], $user_info['ip']);
Chris@76 271 log_error($txt['security_wrong'], 'critical');
Chris@76 272
Chris@76 273 if (isset($_POST['admin_hash_pass']))
Chris@76 274 unset($_POST['admin_hash_pass']);
Chris@76 275 if (isset($_POST['admin_pass']))
Chris@76 276 unset($_POST['admin_pass']);
Chris@76 277
Chris@76 278 $context['incorrect_password'] = true;
Chris@76 279 }
Chris@76 280
Chris@76 281 // Figure out the get data and post data.
Chris@76 282 $context['get_data'] = '?' . construct_query_string($_GET);
Chris@76 283 $context['post_data'] = '';
Chris@76 284
Chris@76 285 // Now go through $_POST. Make sure the session hash is sent.
Chris@76 286 $_POST[$context['session_var']] = $context['session_id'];
Chris@76 287 foreach ($_POST as $k => $v)
Chris@76 288 $context['post_data'] .= adminLogin_outputPostVars($k, $v);
Chris@76 289
Chris@76 290 // Now we'll use the admin_login sub template of the Login template.
Chris@76 291 $context['sub_template'] = 'admin_login';
Chris@76 292
Chris@76 293 // And title the page something like "Login".
Chris@76 294 if (!isset($context['page_title']))
Chris@76 295 $context['page_title'] = $txt['login'];
Chris@76 296
Chris@76 297 obExit();
Chris@76 298
Chris@76 299 // We MUST exit at this point, because otherwise we CANNOT KNOW that the user is privileged.
Chris@76 300 trigger_error('Hacking attempt...', E_USER_ERROR);
Chris@76 301 }
Chris@76 302
Chris@76 303 function adminLogin_outputPostVars($k, $v)
Chris@76 304 {
Chris@76 305 global $smcFunc;
Chris@76 306
Chris@76 307 if (!is_array($v))
Chris@76 308 return '
Chris@76 309 <input type="hidden" name="' . htmlspecialchars($k) . '" value="' . strtr($v, array('"' => '&quot;', '<' => '&lt;', '>' => '&gt;')) . '" />';
Chris@76 310 else
Chris@76 311 {
Chris@76 312 $ret = '';
Chris@76 313 foreach ($v as $k2 => $v2)
Chris@76 314 $ret .= adminLogin_outputPostVars($k . '[' . $k2 . ']', $v2);
Chris@76 315
Chris@76 316 return $ret;
Chris@76 317 }
Chris@76 318 }
Chris@76 319
Chris@76 320 function construct_query_string($get)
Chris@76 321 {
Chris@76 322 global $scripturl;
Chris@76 323
Chris@76 324 $query_string = '';
Chris@76 325
Chris@76 326 // Awww, darn. The $scripturl contains GET stuff!
Chris@76 327 $q = strpos($scripturl, '?');
Chris@76 328 if ($q !== false)
Chris@76 329 {
Chris@76 330 parse_str(preg_replace('/&(\w+)(?=&|$)/', '&$1=', strtr(substr($scripturl, $q + 1), ';', '&')), $temp);
Chris@76 331
Chris@76 332 foreach ($get as $k => $v)
Chris@76 333 {
Chris@76 334 // Only if it's not already in the $scripturl!
Chris@76 335 if (!isset($temp[$k]))
Chris@76 336 $query_string .= urlencode($k) . '=' . urlencode($v) . ';';
Chris@76 337 // If it changed, put it out there, but with an ampersand.
Chris@76 338 elseif ($temp[$k] != $get[$k])
Chris@76 339 $query_string .= urlencode($k) . '=' . urlencode($v) . '&amp;';
Chris@76 340 }
Chris@76 341 }
Chris@76 342 else
Chris@76 343 {
Chris@76 344 // Add up all the data from $_GET into get_data.
Chris@76 345 foreach ($get as $k => $v)
Chris@76 346 $query_string .= urlencode($k) . '=' . urlencode($v) . ';';
Chris@76 347 }
Chris@76 348
Chris@76 349 $query_string = substr($query_string, 0, -1);
Chris@76 350 return $query_string;
Chris@76 351 }
Chris@76 352
Chris@76 353 // Find members by email address, username, or real name.
Chris@76 354 function findMembers($names, $use_wildcards = false, $buddies_only = false, $max = 500)
Chris@76 355 {
Chris@76 356 global $scripturl, $user_info, $modSettings, $smcFunc;
Chris@76 357
Chris@76 358 // If it's not already an array, make it one.
Chris@76 359 if (!is_array($names))
Chris@76 360 $names = explode(',', $names);
Chris@76 361
Chris@76 362 $maybe_email = false;
Chris@76 363 foreach ($names as $i => $name)
Chris@76 364 {
Chris@76 365 // Trim, and fix wildcards for each name.
Chris@76 366 $names[$i] = trim($smcFunc['strtolower']($name));
Chris@76 367
Chris@76 368 $maybe_email |= strpos($name, '@') !== false;
Chris@76 369
Chris@76 370 // Make it so standard wildcards will work. (* and ?)
Chris@76 371 if ($use_wildcards)
Chris@76 372 $names[$i] = strtr($names[$i], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '\'' => '&#039;'));
Chris@76 373 else
Chris@76 374 $names[$i] = strtr($names[$i], array('\'' => '&#039;'));
Chris@76 375 }
Chris@76 376
Chris@76 377 // What are we using to compare?
Chris@76 378 $comparison = $use_wildcards ? 'LIKE' : '=';
Chris@76 379
Chris@76 380 // Nothing found yet.
Chris@76 381 $results = array();
Chris@76 382
Chris@76 383 // This ensures you can't search someones email address if you can't see it.
Chris@76 384 $email_condition = allowedTo('moderate_forum') ? '' : 'hide_email = 0 AND ';
Chris@76 385
Chris@76 386 if ($use_wildcards || $maybe_email)
Chris@76 387 $email_condition = '
Chris@76 388 OR (' . $email_condition . 'email_address ' . $comparison . ' \'' . implode( '\') OR (' . $email_condition . ' email_address ' . $comparison . ' \'', $names) . '\')';
Chris@76 389 else
Chris@76 390 $email_condition = '';
Chris@76 391
Chris@76 392 // Get the case of the columns right - but only if we need to as things like MySQL will go slow needlessly otherwise.
Chris@76 393 $member_name = $smcFunc['db_case_sensitive'] ? 'LOWER(member_name)' : 'member_name';
Chris@76 394 $real_name = $smcFunc['db_case_sensitive'] ? 'LOWER(real_name)' : 'real_name';
Chris@76 395
Chris@76 396 // Search by username, display name, and email address.
Chris@76 397 $request = $smcFunc['db_query']('', '
Chris@76 398 SELECT id_member, member_name, real_name, email_address, hide_email
Chris@76 399 FROM {db_prefix}members
Chris@76 400 WHERE ({raw:member_name_search}
Chris@76 401 OR {raw:real_name_search} {raw:email_condition})
Chris@76 402 ' . ($buddies_only ? 'AND id_member IN ({array_int:buddy_list})' : '') . '
Chris@76 403 AND is_activated IN (1, 11)
Chris@76 404 LIMIT {int:limit}',
Chris@76 405 array(
Chris@76 406 'buddy_list' => $user_info['buddies'],
Chris@76 407 'member_name_search' => $member_name . ' ' . $comparison . ' \'' . implode( '\' OR ' . $member_name . ' ' . $comparison . ' \'', $names) . '\'',
Chris@76 408 'real_name_search' => $real_name . ' ' . $comparison . ' \'' . implode( '\' OR ' . $real_name . ' ' . $comparison . ' \'', $names) . '\'',
Chris@76 409 'email_condition' => $email_condition,
Chris@76 410 'limit' => $max,
Chris@76 411 )
Chris@76 412 );
Chris@76 413 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 414 {
Chris@76 415 $results[$row['id_member']] = array(
Chris@76 416 'id' => $row['id_member'],
Chris@76 417 'name' => $row['real_name'],
Chris@76 418 'username' => $row['member_name'],
Chris@76 419 'email' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['email_address'] : '',
Chris@76 420 'href' => $scripturl . '?action=profile;u=' . $row['id_member'],
Chris@76 421 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>'
Chris@76 422 );
Chris@76 423 }
Chris@76 424 $smcFunc['db_free_result']($request);
Chris@76 425
Chris@76 426 // Return all the results.
Chris@76 427 return $results;
Chris@76 428 }
Chris@76 429
Chris@76 430 function JSMembers()
Chris@76 431 {
Chris@76 432 global $context, $scripturl, $user_info, $smcFunc;
Chris@76 433
Chris@76 434 checkSession('get');
Chris@76 435
Chris@76 436 if (WIRELESS)
Chris@76 437 $context['sub_template'] = WIRELESS_PROTOCOL . '_pm';
Chris@76 438 else
Chris@76 439 {
Chris@76 440 // Why is this in the Help template, you ask? Well, erm... it helps you. Does that work?
Chris@76 441 loadTemplate('Help');
Chris@76 442
Chris@76 443 $context['template_layers'] = array();
Chris@76 444 $context['sub_template'] = 'find_members';
Chris@76 445 }
Chris@76 446
Chris@76 447 if (isset($_REQUEST['search']))
Chris@76 448 $context['last_search'] = $smcFunc['htmlspecialchars']($_REQUEST['search'], ENT_QUOTES);
Chris@76 449 else
Chris@76 450 $_REQUEST['start'] = 0;
Chris@76 451
Chris@76 452 // Allow the user to pass the input to be added to to the box.
Chris@76 453 $context['input_box_name'] = isset($_REQUEST['input']) && preg_match('~^[\w-]+$~', $_REQUEST['input']) === 1 ? $_REQUEST['input'] : 'to';
Chris@76 454
Chris@76 455 // Take the delimiter over GET in case it's \n or something.
Chris@76 456 $context['delimiter'] = isset($_REQUEST['delim']) ? ($_REQUEST['delim'] == 'LB' ? "\n" : $_REQUEST['delim']) : ', ';
Chris@76 457 $context['quote_results'] = !empty($_REQUEST['quote']);
Chris@76 458
Chris@76 459 // List all the results.
Chris@76 460 $context['results'] = array();
Chris@76 461
Chris@76 462 // Some buddy related settings ;)
Chris@76 463 $context['show_buddies'] = !empty($user_info['buddies']);
Chris@76 464 $context['buddy_search'] = isset($_REQUEST['buddies']);
Chris@76 465
Chris@76 466 // If the user has done a search, well - search.
Chris@76 467 if (isset($_REQUEST['search']))
Chris@76 468 {
Chris@76 469 $_REQUEST['search'] = $smcFunc['htmlspecialchars']($_REQUEST['search'], ENT_QUOTES);
Chris@76 470
Chris@76 471 $context['results'] = findMembers(array($_REQUEST['search']), true, $context['buddy_search']);
Chris@76 472 $total_results = count($context['results']);
Chris@76 473
Chris@76 474 $context['page_index'] = constructPageIndex($scripturl . '?action=findmember;search=' . $context['last_search'] . ';' . $context['session_var'] . '=' . $context['session_id'] . ';input=' . $context['input_box_name'] . ($context['quote_results'] ? ';quote=1' : '') . ($context['buddy_search'] ? ';buddies' : ''), $_REQUEST['start'], $total_results, 7);
Chris@76 475
Chris@76 476 // Determine the navigation context (especially useful for the wireless template).
Chris@76 477 $base_url = $scripturl . '?action=findmember;search=' . urlencode($context['last_search']) . (empty($_REQUEST['u']) ? '' : ';u=' . $_REQUEST['u']) . ';' . $context['session_var'] . '=' . $context['session_id'];
Chris@76 478 $context['links'] = array(
Chris@76 479 'first' => $_REQUEST['start'] >= 7 ? $base_url . ';start=0' : '',
Chris@76 480 'prev' => $_REQUEST['start'] >= 7 ? $base_url . ';start=' . ($_REQUEST['start'] - 7) : '',
Chris@76 481 'next' => $_REQUEST['start'] + 7 < $total_results ? $base_url . ';start=' . ($_REQUEST['start'] + 7) : '',
Chris@76 482 'last' => $_REQUEST['start'] + 7 < $total_results ? $base_url . ';start=' . (floor(($total_results - 1) / 7) * 7) : '',
Chris@76 483 'up' => $scripturl . '?action=pm;sa=send' . (empty($_REQUEST['u']) ? '' : ';u=' . $_REQUEST['u']),
Chris@76 484 );
Chris@76 485 $context['page_info'] = array(
Chris@76 486 'current_page' => $_REQUEST['start'] / 7 + 1,
Chris@76 487 'num_pages' => floor(($total_results - 1) / 7) + 1
Chris@76 488 );
Chris@76 489
Chris@76 490 $context['results'] = array_slice($context['results'], $_REQUEST['start'], 7);
Chris@76 491 }
Chris@76 492 else
Chris@76 493 $context['links']['up'] = $scripturl . '?action=pm;sa=send' . (empty($_REQUEST['u']) ? '' : ';u=' . $_REQUEST['u']);
Chris@76 494 }
Chris@76 495
Chris@76 496 function RequestMembers()
Chris@76 497 {
Chris@76 498 global $user_info, $txt, $smcFunc;
Chris@76 499
Chris@76 500 checkSession('get');
Chris@76 501
Chris@76 502 $_REQUEST['search'] = $smcFunc['htmlspecialchars']($_REQUEST['search']) . '*';
Chris@76 503 $_REQUEST['search'] = trim($smcFunc['strtolower']($_REQUEST['search']));
Chris@76 504 $_REQUEST['search'] = strtr($_REQUEST['search'], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '&#038;' => '&amp;'));
Chris@76 505
Chris@76 506 if (function_exists('iconv'))
Chris@76 507 header('Content-Type: text/plain; charset=UTF-8');
Chris@76 508
Chris@76 509 $request = $smcFunc['db_query']('', '
Chris@76 510 SELECT real_name
Chris@76 511 FROM {db_prefix}members
Chris@76 512 WHERE real_name LIKE {string:search}' . (isset($_REQUEST['buddies']) ? '
Chris@76 513 AND id_member IN ({array_int:buddy_list})' : '') . '
Chris@76 514 AND is_activated IN (1, 11)
Chris@76 515 LIMIT ' . ($smcFunc['strlen']($_REQUEST['search']) <= 2 ? '100' : '800'),
Chris@76 516 array(
Chris@76 517 'buddy_list' => $user_info['buddies'],
Chris@76 518 'search' => $_REQUEST['search'],
Chris@76 519 )
Chris@76 520 );
Chris@76 521 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 522 {
Chris@76 523 if (function_exists('iconv'))
Chris@76 524 {
Chris@76 525 $utf8 = iconv($txt['lang_character_set'], 'UTF-8', $row['real_name']);
Chris@76 526 if ($utf8)
Chris@76 527 $row['real_name'] = $utf8;
Chris@76 528 }
Chris@76 529
Chris@76 530 $row['real_name'] = strtr($row['real_name'], array('&amp;' => '&#038;', '&lt;' => '&#060;', '&gt;' => '&#062;', '&quot;' => '&#034;'));
Chris@76 531
Chris@76 532 if (preg_match('~&#\d+;~', $row['real_name']) != 0)
Chris@76 533 {
Chris@76 534 $fixchar = create_function('$n', '
Chris@76 535 if ($n < 128)
Chris@76 536 return chr($n);
Chris@76 537 elseif ($n < 2048)
Chris@76 538 return chr(192 | $n >> 6) . chr(128 | $n & 63);
Chris@76 539 elseif ($n < 65536)
Chris@76 540 return chr(224 | $n >> 12) . chr(128 | $n >> 6 & 63) . chr(128 | $n & 63);
Chris@76 541 else
Chris@76 542 return chr(240 | $n >> 18) . chr(128 | $n >> 12 & 63) . chr(128 | $n >> 6 & 63) . chr(128 | $n & 63);');
Chris@76 543
Chris@76 544 $row['real_name'] = preg_replace('~&#(\d+);~e', '$fixchar(\'$1\')', $row['real_name']);
Chris@76 545 }
Chris@76 546
Chris@76 547 echo $row['real_name'], "\n";
Chris@76 548 }
Chris@76 549 $smcFunc['db_free_result']($request);
Chris@76 550
Chris@76 551 obExit(false);
Chris@76 552 }
Chris@76 553
Chris@76 554 // This function generates a random password for a user and emails it to them.
Chris@76 555 function resetPassword($memID, $username = null)
Chris@76 556 {
Chris@76 557 global $scripturl, $context, $txt, $sourcedir, $modSettings, $smcFunc, $language;
Chris@76 558
Chris@76 559 // Language... and a required file.
Chris@76 560 loadLanguage('Login');
Chris@76 561 require_once($sourcedir . '/Subs-Post.php');
Chris@76 562
Chris@76 563 // Get some important details.
Chris@76 564 $request = $smcFunc['db_query']('', '
Chris@76 565 SELECT member_name, email_address, lngfile
Chris@76 566 FROM {db_prefix}members
Chris@76 567 WHERE id_member = {int:id_member}',
Chris@76 568 array(
Chris@76 569 'id_member' => $memID,
Chris@76 570 )
Chris@76 571 );
Chris@76 572 list ($user, $email, $lngfile) = $smcFunc['db_fetch_row']($request);
Chris@76 573 $smcFunc['db_free_result']($request);
Chris@76 574
Chris@76 575 if ($username !== null)
Chris@76 576 {
Chris@76 577 $old_user = $user;
Chris@76 578 $user = trim($username);
Chris@76 579 }
Chris@76 580
Chris@76 581 // Generate a random password.
Chris@76 582 $newPassword = substr(preg_replace('/\W/', '', md5(mt_rand())), 0, 10);
Chris@76 583 $newPassword_sha1 = sha1(strtolower($user) . $newPassword);
Chris@76 584
Chris@76 585 // Do some checks on the username if needed.
Chris@76 586 if ($username !== null)
Chris@76 587 {
Chris@76 588 validateUsername($memID, $user);
Chris@76 589
Chris@76 590 // Update the database...
Chris@76 591 updateMemberData($memID, array('member_name' => $user, 'passwd' => $newPassword_sha1));
Chris@76 592 }
Chris@76 593 else
Chris@76 594 updateMemberData($memID, array('passwd' => $newPassword_sha1));
Chris@76 595
Chris@76 596 call_integration_hook('integrate_reset_pass', array($old_user, $user, $newPassword));
Chris@76 597
Chris@76 598 $replacements = array(
Chris@76 599 'USERNAME' => $user,
Chris@76 600 'PASSWORD' => $newPassword,
Chris@76 601 );
Chris@76 602
Chris@76 603 $emaildata = loadEmailTemplate('change_password', $replacements, empty($lngfile) || empty($modSettings['userLanguage']) ? $language : $lngfile);
Chris@76 604
Chris@76 605 // Send them the email informing them of the change - then we're done!
Chris@76 606 sendmail($email, $emaildata['subject'], $emaildata['body'], null, null, false, 0);
Chris@76 607 }
Chris@76 608
Chris@76 609 // Is this a valid username?
Chris@76 610 function validateUsername($memID, $username)
Chris@76 611 {
Chris@76 612 global $sourcedir, $txt;
Chris@76 613
Chris@76 614 // No name?! How can you register with no name?
Chris@76 615 if ($username == '')
Chris@76 616 fatal_lang_error('need_username', false);
Chris@76 617
Chris@76 618 // Only these characters are permitted.
Chris@76 619 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)
Chris@76 620 fatal_lang_error('error_invalid_characters_username', false);
Chris@76 621
Chris@76 622 if (stristr($username, $txt['guest_title']) !== false)
Chris@76 623 fatal_lang_error('username_reserved', true, array($txt['guest_title']));
Chris@76 624
Chris@76 625 require_once($sourcedir . '/Subs-Members.php');
Chris@76 626 if (isReservedName($username, $memID, false))
Chris@76 627 fatal_error('(' . htmlspecialchars($username) . ') ' . $txt['name_in_use'], false);
Chris@76 628
Chris@76 629 return null;
Chris@76 630 }
Chris@76 631
Chris@76 632 // This function simply checks whether a password meets the current forum rules.
Chris@76 633 function validatePassword($password, $username, $restrict_in = array())
Chris@76 634 {
Chris@76 635 global $modSettings, $smcFunc;
Chris@76 636
Chris@76 637 // Perform basic requirements first.
Chris@76 638 if ($smcFunc['strlen']($password) < (empty($modSettings['password_strength']) ? 4 : 8))
Chris@76 639 return 'short';
Chris@76 640
Chris@76 641 // Is this enough?
Chris@76 642 if (empty($modSettings['password_strength']))
Chris@76 643 return null;
Chris@76 644
Chris@76 645 // Otherwise, perform the medium strength test - checking if password appears in the restricted string.
Chris@76 646 if (preg_match('~\b' . preg_quote($password, '~') . '\b~', implode(' ', $restrict_in)) != 0)
Chris@76 647 return 'restricted_words';
Chris@76 648 elseif ($smcFunc['strpos']($password, $username) !== false)
Chris@76 649 return 'restricted_words';
Chris@76 650
Chris@76 651 // !!! If pspell is available, use it on the word, and return restricted_words if it doesn't give "bad spelling"?
Chris@76 652
Chris@76 653 // If just medium, we're done.
Chris@76 654 if ($modSettings['password_strength'] == 1)
Chris@76 655 return null;
Chris@76 656
Chris@76 657 // Otherwise, hard test next, check for numbers and letters, uppercase too.
Chris@76 658 $good = preg_match('~(\D\d|\d\D)~', $password) != 0;
Chris@76 659 $good &= $smcFunc['strtolower']($password) != $password;
Chris@76 660
Chris@76 661 return $good ? null : 'chars';
Chris@76 662 }
Chris@76 663
Chris@76 664 // Quickly find out what this user can and cannot do.
Chris@76 665 function rebuildModCache()
Chris@76 666 {
Chris@76 667 global $user_info, $smcFunc;
Chris@76 668
Chris@76 669 // What groups can they moderate?
Chris@76 670 $group_query = allowedTo('manage_membergroups') ? '1=1' : '0=1';
Chris@76 671
Chris@76 672 if ($group_query == '0=1')
Chris@76 673 {
Chris@76 674 $request = $smcFunc['db_query']('', '
Chris@76 675 SELECT id_group
Chris@76 676 FROM {db_prefix}group_moderators
Chris@76 677 WHERE id_member = {int:current_member}',
Chris@76 678 array(
Chris@76 679 'current_member' => $user_info['id'],
Chris@76 680 )
Chris@76 681 );
Chris@76 682 $groups = array();
Chris@76 683 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 684 $groups[] = $row['id_group'];
Chris@76 685 $smcFunc['db_free_result']($request);
Chris@76 686
Chris@76 687 if (empty($groups))
Chris@76 688 $group_query = '0=1';
Chris@76 689 else
Chris@76 690 $group_query = 'id_group IN (' . implode(',', $groups) . ')';
Chris@76 691 }
Chris@76 692
Chris@76 693 // Then, same again, just the boards this time!
Chris@76 694 $board_query = allowedTo('moderate_forum') ? '1=1' : '0=1';
Chris@76 695
Chris@76 696 if ($board_query == '0=1')
Chris@76 697 {
Chris@76 698 $boards = boardsAllowedTo('moderate_board', true);
Chris@76 699
Chris@76 700 if (empty($boards))
Chris@76 701 $board_query = '0=1';
Chris@76 702 else
Chris@76 703 $board_query = 'id_board IN (' . implode(',', $boards) . ')';
Chris@76 704 }
Chris@76 705
Chris@76 706 // What boards are they the moderator of?
Chris@76 707 $boards_mod = array();
Chris@76 708 if (!$user_info['is_guest'])
Chris@76 709 {
Chris@76 710 $request = $smcFunc['db_query']('', '
Chris@76 711 SELECT id_board
Chris@76 712 FROM {db_prefix}moderators
Chris@76 713 WHERE id_member = {int:current_member}',
Chris@76 714 array(
Chris@76 715 'current_member' => $user_info['id'],
Chris@76 716 )
Chris@76 717 );
Chris@76 718 while ($row = $smcFunc['db_fetch_assoc']($request))
Chris@76 719 $boards_mod[] = $row['id_board'];
Chris@76 720 $smcFunc['db_free_result']($request);
Chris@76 721 }
Chris@76 722
Chris@76 723 $mod_query = empty($boards_mod) ? '0=1' : 'b.id_board IN (' . implode(',', $boards_mod) . ')';
Chris@76 724
Chris@76 725 $_SESSION['mc'] = array(
Chris@76 726 'time' => time(),
Chris@76 727 // This looks a bit funny but protects against the login redirect.
Chris@76 728 'id' => $user_info['id'] && $user_info['name'] ? $user_info['id'] : 0,
Chris@76 729 // If you change the format of 'gq' and/or 'bq' make sure to adjust 'can_mod' in Load.php.
Chris@76 730 'gq' => $group_query,
Chris@76 731 'bq' => $board_query,
Chris@76 732 'ap' => boardsAllowedTo('approve_posts'),
Chris@76 733 'mb' => $boards_mod,
Chris@76 734 'mq' => $mod_query,
Chris@76 735 );
Chris@76 736
Chris@76 737 $user_info['mod_cache'] = $_SESSION['mc'];
Chris@76 738 }
Chris@76 739
Chris@76 740 ?>