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('"' => '"', '<' => '<', '>' => '>')) . '" />';
|
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) . '&';
|
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('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '\'' => '''));
|
Chris@76
|
373 else
|
Chris@76
|
374 $names[$i] = strtr($names[$i], array('\'' => '''));
|
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('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '&' => '&'));
|
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('&' => '&', '<' => '<', '>' => '>', '"' => '"'));
|
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 ?> |