comparison forum/Sources/Subs-Auth.php @ 76:e3e11437ecea website

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