|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* This file has functions in it to do with authentication, user handling, and the like. |
|
5
|
|
|
* |
|
6
|
|
|
* @name ElkArte Forum |
|
7
|
|
|
* @copyright ElkArte Forum contributors |
|
8
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
|
9
|
|
|
* |
|
10
|
|
|
* This file contains code covered by: |
|
11
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
|
12
|
|
|
* license: BSD, See included LICENSE.TXT for terms and conditions. |
|
13
|
|
|
* |
|
14
|
|
|
* @version 1.1 Release Candidate 1 |
|
15
|
|
|
* |
|
16
|
|
|
*/ |
|
17
|
|
|
|
|
18
|
|
|
/** |
|
19
|
|
|
* Sets the login cookie and session based on the id_member and password passed. |
|
20
|
|
|
* |
|
21
|
|
|
* What it does: |
|
22
|
|
|
* |
|
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 by cookie_length. |
|
26
|
|
|
* - when logging out, if the globalCookies setting is enabled, attempts to clear the subdomain's cookie too. |
|
27
|
|
|
* |
|
28
|
|
|
* @package Authorization |
|
29
|
|
|
* @param int $cookie_length |
|
30
|
|
|
* @param int $id The id of the member |
|
31
|
|
|
* @param string $password = '' |
|
32
|
|
|
*/ |
|
33
|
|
|
function setLoginCookie($cookie_length, $id, $password = '') |
|
34
|
|
|
{ |
|
35
|
1 |
|
global $cookiename, $boardurl, $modSettings; |
|
36
|
|
|
|
|
37
|
|
|
// If changing state force them to re-address some permission caching. |
|
38
|
1 |
|
$_SESSION['mc']['time'] = 0; |
|
39
|
|
|
|
|
40
|
|
|
// Let's be sure it is an int to simplify the regexp used to validate the cookie |
|
41
|
1 |
|
$id = (int) $id; |
|
42
|
|
|
|
|
43
|
|
|
// The cookie may already exist, and have been set with different options. |
|
44
|
1 |
|
$cookie_state = (empty($modSettings['localCookies']) ? 0 : 1) | (empty($modSettings['globalCookies']) ? 0 : 2); |
|
45
|
|
|
|
|
46
|
1 |
|
if (isset($_COOKIE[$cookiename])) |
|
47
|
1 |
|
{ |
|
48
|
|
View Code Duplication |
$array = serializeToJson($_COOKIE[$cookiename], function ($array_from) use ($cookiename) { |
|
49
|
|
|
global $modSettings; |
|
50
|
|
|
|
|
51
|
|
|
require_once(SUBSDIR . '/Auth.subs.php'); |
|
52
|
|
|
$_COOKIE[$cookiename] = json_encode($array_from); |
|
53
|
|
|
setLoginCookie(60 * $modSettings['cookieTime'], $array_from[0], $array_from[1]); |
|
54
|
|
|
}); |
|
55
|
|
|
|
|
56
|
|
|
// Out with the old, in with the new! |
|
57
|
|
|
if (isset($array[3]) && $array[3] != $cookie_state) |
|
58
|
|
|
{ |
|
59
|
|
|
$cookie_url = url_parts($array[3] & 1 > 0, $array[3] & 2 > 0); |
|
60
|
|
|
elk_setcookie($cookiename, json_encode(array(0, '', 0)), time() - 3600, $cookie_url[1], $cookie_url[0]); |
|
61
|
|
|
} |
|
62
|
|
|
} |
|
63
|
|
|
|
|
64
|
|
|
// Get the data and path to set it on. |
|
65
|
1 |
|
$data = json_encode(empty($id) ? array(0, '', 0) : array($id, $password, time() + $cookie_length, $cookie_state)); |
|
66
|
1 |
|
$cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
|
67
|
|
|
|
|
68
|
|
|
// Set the cookie, $_COOKIE, and session variable. |
|
69
|
1 |
|
elk_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0]); |
|
70
|
|
|
|
|
71
|
|
|
// If subdomain-independent cookies are on, unset the subdomain-dependent cookie too. |
|
72
|
1 |
|
if (empty($id) && !empty($modSettings['globalCookies'])) |
|
73
|
1 |
|
elk_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], ''); |
|
74
|
|
|
|
|
75
|
|
|
// Any alias URLs? This is mainly for use with frames, etc. |
|
76
|
1 |
|
if (!empty($modSettings['forum_alias_urls'])) |
|
77
|
1 |
|
{ |
|
78
|
|
|
$aliases = explode(',', $modSettings['forum_alias_urls']); |
|
79
|
|
|
|
|
80
|
|
|
$temp = $boardurl; |
|
81
|
|
|
foreach ($aliases as $alias) |
|
82
|
|
|
{ |
|
83
|
|
|
// Fake the $boardurl so we can set a different cookie. |
|
84
|
|
|
$alias = strtr(trim($alias), array('http://' => '', 'https://' => '')); |
|
85
|
|
|
$boardurl = 'http://' . $alias; |
|
86
|
|
|
|
|
87
|
|
|
$cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
|
88
|
|
|
|
|
89
|
|
|
if ($cookie_url[0] == '') |
|
90
|
|
|
$cookie_url[0] = strtok($alias, '/'); |
|
91
|
|
|
|
|
92
|
|
|
elk_setcookie($cookiename, $data, time() + $cookie_length, $cookie_url[1], $cookie_url[0]); |
|
93
|
|
|
} |
|
94
|
|
|
|
|
95
|
|
|
$boardurl = $temp; |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
1 |
|
$_COOKIE[$cookiename] = $data; |
|
99
|
|
|
|
|
100
|
|
|
// Make sure the user logs in with a new session ID. |
|
101
|
1 |
|
if (!isset($_SESSION['login_' . $cookiename]) || $_SESSION['login_' . $cookiename] !== $data) |
|
102
|
1 |
|
{ |
|
103
|
|
|
// We need to meddle with the session. |
|
104
|
1 |
|
require_once(SOURCEDIR . '/Session.php'); |
|
105
|
|
|
|
|
106
|
|
|
// Backup the old session. |
|
107
|
1 |
|
$oldSessionData = $_SESSION; |
|
108
|
|
|
|
|
109
|
|
|
// Remove the old session data and file / db entry |
|
110
|
1 |
|
$_SESSION = array(); |
|
111
|
1 |
|
session_destroy(); |
|
112
|
|
|
|
|
113
|
|
|
// Recreate and restore the new session. |
|
114
|
1 |
|
loadSession(); |
|
115
|
|
|
|
|
116
|
|
|
// Get a new session id, and load it with the data |
|
117
|
1 |
|
session_regenerate_id(); |
|
118
|
1 |
|
$_SESSION = $oldSessionData; |
|
119
|
|
|
|
|
120
|
1 |
|
$_SESSION['login_' . $cookiename] = $data; |
|
121
|
1 |
|
} |
|
122
|
1 |
|
} |
|
123
|
|
|
|
|
124
|
|
|
/** |
|
125
|
|
|
* Get the domain and path for the cookie |
|
126
|
|
|
* |
|
127
|
|
|
* What it does: |
|
128
|
|
|
* |
|
129
|
|
|
* - normally, local and global should be the localCookies and globalCookies settings, respectively. |
|
130
|
|
|
* - uses boardurl to determine these two things. |
|
131
|
|
|
* |
|
132
|
|
|
* @package Authorization |
|
133
|
|
|
* @param bool $local |
|
134
|
|
|
* @param bool $global |
|
135
|
|
|
*/ |
|
136
|
|
|
function url_parts($local, $global) |
|
137
|
|
|
{ |
|
138
|
1 |
|
global $boardurl, $modSettings; |
|
139
|
|
|
|
|
140
|
|
|
// Parse the URL with PHP to make life easier. |
|
141
|
1 |
|
$parsed_url = parse_url($boardurl); |
|
142
|
|
|
|
|
143
|
|
|
// Is local cookies off? |
|
144
|
1 |
|
if (empty($parsed_url['path']) || !$local) |
|
145
|
1 |
|
$parsed_url['path'] = ''; |
|
146
|
|
|
|
|
147
|
1 |
|
if (!empty($modSettings['globalCookiesDomain']) && strpos($boardurl, $modSettings['globalCookiesDomain']) !== false) |
|
148
|
1 |
|
$parsed_url['host'] = $modSettings['globalCookiesDomain']; |
|
149
|
|
|
|
|
150
|
|
|
// Globalize cookies across domains (filter out IP-addresses)? |
|
151
|
1 |
|
elseif ($global && preg_match('~^\d{1,3}(\.\d{1,3}){3}$~', $parsed_url['host']) == 0 && preg_match('~(?:[^\.]+\.)?([^\.]{2,}\..+)\z~i', $parsed_url['host'], $parts) == 1) |
|
152
|
|
|
$parsed_url['host'] = '.' . $parts[1]; |
|
153
|
|
|
|
|
154
|
|
|
// We shouldn't use a host at all if both options are off. |
|
155
|
1 |
|
elseif (!$local && !$global) |
|
156
|
1 |
|
$parsed_url['host'] = ''; |
|
157
|
|
|
|
|
158
|
|
|
// The host also shouldn't be set if there aren't any dots in it. |
|
159
|
|
|
elseif (!isset($parsed_url['host']) || strpos($parsed_url['host'], '.') === false) |
|
160
|
|
|
$parsed_url['host'] = ''; |
|
161
|
|
|
|
|
162
|
1 |
|
return array($parsed_url['host'], $parsed_url['path'] . '/'); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* Question the verity of the admin by asking for his or her password. |
|
167
|
|
|
* |
|
168
|
|
|
* What it does: |
|
169
|
|
|
* |
|
170
|
|
|
* - loads Login.template.php and uses the admin_login sub template. |
|
171
|
|
|
* - sends data to template so the admin is sent on to the page they |
|
172
|
|
|
* wanted if their password is correct, otherwise they can try again. |
|
173
|
|
|
* |
|
174
|
|
|
* @package Authorization |
|
175
|
|
|
* @param string $type = 'admin' |
|
176
|
|
|
* @throws Elk_Exception |
|
177
|
|
|
*/ |
|
178
|
|
|
function adminLogin($type = 'admin') |
|
179
|
|
|
{ |
|
180
|
|
|
global $context, $txt, $user_info; |
|
181
|
|
|
|
|
182
|
|
|
loadLanguage('Admin'); |
|
183
|
|
|
loadTemplate('Login'); |
|
184
|
|
|
loadJavascriptFile('sha256.js', array('defer' => true)); |
|
185
|
|
|
|
|
186
|
|
|
// Validate what type of session check this is. |
|
187
|
|
|
$types = array(); |
|
188
|
|
|
call_integration_hook('integrate_validateSession', array(&$types)); |
|
189
|
|
|
$type = in_array($type, $types) || $type == 'moderate' ? $type : 'admin'; |
|
190
|
|
|
|
|
191
|
|
|
// They used a wrong password, log it and unset that. |
|
192
|
|
|
if (isset($_POST[$type . '_hash_pass']) || isset($_POST[$type . '_pass'])) |
|
193
|
|
|
{ |
|
194
|
|
|
// log some info along with it! referer, user agent |
|
195
|
|
|
$req = request(); |
|
196
|
|
|
$txt['security_wrong'] = sprintf($txt['security_wrong'], isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $txt['unknown'], $req->user_agent(), $user_info['ip']); |
|
197
|
|
|
Errors::instance()->log_error($txt['security_wrong'], 'critical'); |
|
198
|
|
|
|
|
199
|
|
|
if (isset($_POST[$type . '_hash_pass'])) |
|
200
|
|
|
unset($_POST[$type . '_hash_pass']); |
|
201
|
|
|
if (isset($_POST[$type . '_pass'])) |
|
202
|
|
|
unset($_POST[$type . '_pass']); |
|
203
|
|
|
|
|
204
|
|
|
$context['incorrect_password'] = true; |
|
205
|
|
|
} |
|
206
|
|
|
|
|
207
|
|
|
createToken('admin-login'); |
|
208
|
|
|
|
|
209
|
|
|
// Figure out the get data and post data. |
|
210
|
|
|
$context['get_data'] = '?' . construct_query_string($_GET); |
|
211
|
|
|
$context['post_data'] = ''; |
|
212
|
|
|
|
|
213
|
|
|
// Now go through $_POST. Make sure the session hash is sent. |
|
214
|
|
|
$_POST[$context['session_var']] = $context['session_id']; |
|
215
|
|
|
foreach ($_POST as $k => $v) |
|
216
|
|
|
$context['post_data'] .= adminLogin_outputPostVars($k, $v); |
|
217
|
|
|
|
|
218
|
|
|
// Now we'll use the admin_login sub template of the Login template. |
|
219
|
|
|
$context['sub_template'] = 'admin_login'; |
|
220
|
|
|
|
|
221
|
|
|
// And title the page something like "Login". |
|
222
|
|
|
if (!isset($context['page_title'])) |
|
223
|
|
|
$context['page_title'] = $txt['admin_login']; |
|
224
|
|
|
|
|
225
|
|
|
// The type of action. |
|
226
|
|
|
$context['sessionCheckType'] = $type; |
|
227
|
|
|
|
|
228
|
|
|
obExit(); |
|
229
|
|
|
|
|
230
|
|
|
// We MUST exit at this point, because otherwise we CANNOT KNOW that the user is privileged. |
|
231
|
|
|
trigger_error('Hacking attempt...', E_USER_ERROR); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
/** |
|
235
|
|
|
* Used by the adminLogin() function. |
|
236
|
|
|
* |
|
237
|
|
|
* What it does: |
|
238
|
|
|
* - if 'value' is an array, the function is called recursively. |
|
239
|
|
|
* |
|
240
|
|
|
* @package Authorization |
|
241
|
|
|
* @param string $k key |
|
242
|
|
|
* @param string|boolean $v value |
|
243
|
|
|
* @return string 'hidden' HTML form fields, containing key-value-pairs |
|
244
|
|
|
*/ |
|
245
|
|
|
function adminLogin_outputPostVars($k, $v) |
|
246
|
|
|
{ |
|
247
|
|
|
if (!is_array($v)) |
|
248
|
|
|
return ' |
|
249
|
|
|
<input type="hidden" name="' . htmlspecialchars($k, ENT_COMPAT, 'UTF-8') . '" value="' . strtr($v, array('"' => '"', '<' => '<', '>' => '>')) . '" />'; |
|
|
|
|
|
|
250
|
|
|
else |
|
251
|
|
|
{ |
|
252
|
|
|
$ret = ''; |
|
253
|
|
|
foreach ($v as $k2 => $v2) |
|
254
|
|
|
$ret .= adminLogin_outputPostVars($k . '[' . $k2 . ']', $v2); |
|
255
|
|
|
|
|
256
|
|
|
return $ret; |
|
257
|
|
|
} |
|
258
|
|
|
} |
|
259
|
|
|
|
|
260
|
|
|
/** |
|
261
|
|
|
* Properly urlencodes a string to be used in a query |
|
262
|
|
|
* |
|
263
|
|
|
* @package Authorization |
|
264
|
|
|
* @param mixed[] $get associative array from $_GET |
|
265
|
|
|
* @return string query string |
|
266
|
|
|
*/ |
|
267
|
|
|
function construct_query_string($get) |
|
268
|
|
|
{ |
|
269
|
|
|
global $scripturl; |
|
270
|
|
|
|
|
271
|
|
|
$query_string = ''; |
|
272
|
|
|
|
|
273
|
|
|
// Awww, darn. The $scripturl contains GET stuff! |
|
274
|
|
|
$q = strpos($scripturl, '?'); |
|
275
|
|
|
if ($q !== false) |
|
276
|
|
|
{ |
|
277
|
|
|
parse_str(preg_replace('/&(\w+)(?=&|$)/', '&$1=', strtr(substr($scripturl, $q + 1), ';', '&')), $temp); |
|
278
|
|
|
|
|
279
|
|
|
foreach ($get as $k => $v) |
|
280
|
|
|
{ |
|
281
|
|
|
// Only if it's not already in the $scripturl! |
|
282
|
|
|
if (!isset($temp[$k])) |
|
283
|
|
|
$query_string .= urlencode($k) . '=' . urlencode($v) . ';'; |
|
284
|
|
|
// If it changed, put it out there, but with an ampersand. |
|
285
|
|
View Code Duplication |
elseif ($temp[$k] != $get[$k]) |
|
286
|
|
|
$query_string .= urlencode($k) . '=' . urlencode($v) . '&'; |
|
287
|
|
|
} |
|
288
|
|
|
} |
|
289
|
|
View Code Duplication |
else |
|
290
|
|
|
{ |
|
291
|
|
|
// Add up all the data from $_GET into get_data. |
|
292
|
|
|
foreach ($get as $k => $v) |
|
293
|
|
|
$query_string .= urlencode($k) . '=' . urlencode($v) . ';'; |
|
294
|
|
|
} |
|
295
|
|
|
|
|
296
|
|
|
$query_string = substr($query_string, 0, -1); |
|
297
|
|
|
return $query_string; |
|
298
|
|
|
} |
|
299
|
|
|
|
|
300
|
|
|
/** |
|
301
|
|
|
* Finds members by email address, username, or real name. |
|
302
|
|
|
* |
|
303
|
|
|
* What it does: |
|
304
|
|
|
* |
|
305
|
|
|
* - searches for members whose username, display name, or e-mail address match the given pattern of array names. |
|
306
|
|
|
* - searches only buddies if buddies_only is set. |
|
307
|
|
|
* |
|
308
|
|
|
* @package Authorization |
|
309
|
|
|
* @param string[]|string $names |
|
310
|
|
|
* @param bool $use_wildcards = false, accepts wildcards ? and * in the pattern if true |
|
311
|
|
|
* @param bool $buddies_only = false, |
|
312
|
|
|
* @param int $max = 500 retrieves a maximum of max members, if passed |
|
313
|
|
|
* @return array containing information about the matching members |
|
314
|
|
|
*/ |
|
315
|
|
|
function findMembers($names, $use_wildcards = false, $buddies_only = false, $max = 500) |
|
316
|
|
|
{ |
|
317
|
|
|
global $scripturl, $user_info; |
|
318
|
|
|
|
|
319
|
|
|
$db = database(); |
|
320
|
|
|
|
|
321
|
|
|
// If it's not already an array, make it one. |
|
322
|
|
|
if (!is_array($names)) |
|
323
|
|
|
$names = explode(',', $names); |
|
324
|
|
|
|
|
325
|
|
|
$maybe_email = false; |
|
326
|
|
|
foreach ($names as $i => $name) |
|
327
|
|
|
{ |
|
328
|
|
|
// Trim, and fix wildcards for each name. |
|
329
|
|
|
$names[$i] = trim(Util::strtolower($name)); |
|
330
|
|
|
|
|
331
|
|
|
$maybe_email |= strpos($name, '@') !== false; |
|
332
|
|
|
|
|
333
|
|
|
// Make it so standard wildcards will work. (* and ?) |
|
334
|
|
|
if ($use_wildcards) |
|
335
|
|
|
$names[$i] = strtr($names[$i], array('%' => '\%', '_' => '\_', '*' => '%', '?' => '_', '\'' => ''')); |
|
336
|
|
|
else |
|
337
|
|
|
$names[$i] = strtr($names[$i], array('\'' => ''')); |
|
338
|
|
|
} |
|
339
|
|
|
|
|
340
|
|
|
// What are we using to compare? |
|
341
|
|
|
$comparison = $use_wildcards ? 'LIKE' : '='; |
|
342
|
|
|
|
|
343
|
|
|
// Nothing found yet. |
|
344
|
|
|
$results = array(); |
|
345
|
|
|
|
|
346
|
|
|
// This ensures you can't search someones email address if you can't see it. |
|
347
|
|
|
$email_condition = allowedTo('moderate_forum') ? '' : 'hide_email = 0 AND '; |
|
348
|
|
|
|
|
349
|
|
|
if ($use_wildcards || $maybe_email) |
|
350
|
|
|
$email_condition = ' |
|
351
|
|
|
OR (' . $email_condition . 'email_address ' . $comparison . ' \'' . implode('\') OR (' . $email_condition . ' email_address ' . $comparison . ' \'', $names) . '\')'; |
|
352
|
|
|
else |
|
353
|
|
|
$email_condition = ''; |
|
354
|
|
|
|
|
355
|
|
|
// Get the case of the columns right - but only if we need to as things like MySQL will go slow needlessly otherwise. |
|
356
|
|
|
$member_name = defined('DB_CASE_SENSITIVE') ? 'LOWER(member_name)' : 'member_name'; |
|
357
|
|
|
$real_name = defined('DB_CASE_SENSITIVE') ? 'LOWER(real_name)' : 'real_name'; |
|
358
|
|
|
|
|
359
|
|
|
// Search by username, display name, and email address. |
|
360
|
|
|
$request = $db->query('', ' |
|
361
|
|
|
SELECT id_member, member_name, real_name, email_address, hide_email |
|
362
|
|
|
FROM {db_prefix}members |
|
363
|
|
|
WHERE ({raw:member_name_search} |
|
364
|
|
|
OR {raw:real_name_search} {raw:email_condition}) |
|
365
|
|
|
' . ($buddies_only ? 'AND id_member IN ({array_int:buddy_list})' : '') . ' |
|
366
|
|
|
AND is_activated IN (1, 11) |
|
367
|
|
|
LIMIT {int:limit}', |
|
368
|
|
|
array( |
|
369
|
|
|
'buddy_list' => $user_info['buddies'], |
|
370
|
|
|
'member_name_search' => $member_name . ' ' . $comparison . ' \'' . implode('\' OR ' . $member_name . ' ' . $comparison . ' \'', $names) . '\'', |
|
371
|
|
|
'real_name_search' => $real_name . ' ' . $comparison . ' \'' . implode('\' OR ' . $real_name . ' ' . $comparison . ' \'', $names) . '\'', |
|
372
|
|
|
'email_condition' => $email_condition, |
|
373
|
|
|
'limit' => $max, |
|
374
|
|
|
) |
|
375
|
|
|
); |
|
376
|
|
|
while ($row = $db->fetch_assoc($request)) |
|
377
|
|
|
{ |
|
378
|
|
|
$results[$row['id_member']] = array( |
|
379
|
|
|
'id' => $row['id_member'], |
|
380
|
|
|
'name' => $row['real_name'], |
|
381
|
|
|
'username' => $row['member_name'], |
|
382
|
|
|
'email' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['email_address'] : '', |
|
383
|
|
|
'href' => $scripturl . '?action=profile;u=' . $row['id_member'], |
|
384
|
|
|
'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>' |
|
385
|
|
|
); |
|
386
|
|
|
} |
|
387
|
|
|
$db->free_result($request); |
|
388
|
|
|
|
|
389
|
|
|
// Return all the results. |
|
390
|
|
|
return $results; |
|
391
|
|
|
} |
|
392
|
|
|
|
|
393
|
|
|
/** |
|
394
|
|
|
* Generates a random password for a user and emails it to them. |
|
395
|
|
|
* |
|
396
|
|
|
* What it does: |
|
397
|
|
|
* |
|
398
|
|
|
* - called by ProfileOptions controller when changing someone's username. |
|
399
|
|
|
* - checks the validity of the new username. |
|
400
|
|
|
* - generates and sets a new password for the given user. |
|
401
|
|
|
* - mails the new password to the email address of the user. |
|
402
|
|
|
* - if username is not set, only a new password is generated and sent. |
|
403
|
|
|
* |
|
404
|
|
|
* @package Authorization |
|
405
|
|
|
* |
|
406
|
|
|
* @param int $memID |
|
407
|
|
|
* @param string|null $username = null |
|
408
|
|
|
* |
|
409
|
|
|
* @throws Elk_Exception |
|
410
|
|
|
*/ |
|
411
|
|
|
function resetPassword($memID, $username = null) |
|
412
|
|
|
{ |
|
413
|
|
|
global $modSettings, $language, $user_info; |
|
414
|
|
|
|
|
415
|
|
|
// Language... and a required file. |
|
416
|
|
|
loadLanguage('Login'); |
|
417
|
|
|
require_once(SUBSDIR . '/Mail.subs.php'); |
|
418
|
|
|
|
|
419
|
|
|
// Get some important details. |
|
420
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
|
421
|
|
|
$result = getBasicMemberData($memID, array('preferences' => true)); |
|
422
|
|
|
$user = $result['member_name']; |
|
423
|
|
|
$email = $result['email_address']; |
|
424
|
|
|
$lngfile = $result['lngfile']; |
|
425
|
|
|
|
|
426
|
|
|
if ($username !== null) |
|
427
|
|
|
{ |
|
428
|
|
|
$old_user = $user; |
|
429
|
|
|
$user = trim($username); |
|
430
|
|
|
} |
|
431
|
|
|
|
|
432
|
|
|
// Generate a random password. |
|
433
|
|
|
$tokenizer = new Token_Hash(); |
|
434
|
|
|
$newPassword = $tokenizer->generate_hash(14); |
|
435
|
|
|
|
|
436
|
|
|
// Create a db hash for the generated password |
|
437
|
|
|
require_once(EXTDIR . '/PasswordHash.php'); |
|
438
|
|
|
$t_hasher = new PasswordHash(8, false); |
|
439
|
|
|
$newPassword_sha256 = hash('sha256', strtolower($user) . $newPassword); |
|
440
|
|
|
$db_hash = $t_hasher->HashPassword($newPassword_sha256); |
|
441
|
|
|
|
|
442
|
|
|
// Do some checks on the username if needed. |
|
443
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
|
444
|
|
|
if ($username !== null) |
|
445
|
|
|
{ |
|
446
|
|
|
$errors = ElkArte\Errors\ErrorContext::context('reset_pwd', 0); |
|
447
|
|
|
validateUsername($memID, $user, 'reset_pwd'); |
|
448
|
|
|
|
|
449
|
|
|
// If there are "important" errors and you are not an admin: log the first error |
|
450
|
|
|
// Otherwise grab all of them and don't log anything |
|
451
|
|
|
$error_severity = $errors->hasErrors(1) && !$user_info['is_admin'] ? 1 : null; |
|
452
|
|
View Code Duplication |
foreach ($errors->prepareErrors($error_severity) as $error) |
|
453
|
|
|
throw new Elk_Exception($error, $error_severity === null ? false : 'general'); |
|
454
|
|
|
|
|
455
|
|
|
// Update the database... |
|
456
|
|
|
updateMemberData($memID, array('member_name' => $user, 'passwd' => $db_hash)); |
|
457
|
|
|
} |
|
458
|
|
|
else |
|
459
|
|
|
updateMemberData($memID, array('passwd' => $db_hash)); |
|
460
|
|
|
|
|
461
|
|
|
call_integration_hook('integrate_reset_pass', array($old_user, $user, $newPassword)); |
|
|
|
|
|
|
462
|
|
|
|
|
463
|
|
|
$replacements = array( |
|
464
|
|
|
'USERNAME' => $user, |
|
465
|
|
|
'PASSWORD' => $newPassword, |
|
466
|
|
|
); |
|
467
|
|
|
|
|
468
|
|
|
$emaildata = loadEmailTemplate('change_password', $replacements, empty($lngfile) || empty($modSettings['userLanguage']) ? $language : $lngfile); |
|
469
|
|
|
|
|
470
|
|
|
// Send them the email informing them of the change - then we're done! |
|
471
|
|
|
sendmail($email, $emaildata['subject'], $emaildata['body'], null, null, false, 0); |
|
472
|
|
|
} |
|
473
|
|
|
|
|
474
|
|
|
/** |
|
475
|
|
|
* Checks a username obeys a load of rules |
|
476
|
|
|
* |
|
477
|
|
|
* - Returns null if fine |
|
478
|
|
|
* |
|
479
|
|
|
* @package Authorization |
|
480
|
|
|
* @param int $memID |
|
481
|
|
|
* @param string $username |
|
482
|
|
|
* @param string $ErrorContext |
|
483
|
|
|
* @param boolean $check_reserved_name |
|
484
|
|
|
* @param boolean $fatal pass through to isReservedName |
|
485
|
|
|
* @return string |
|
486
|
|
|
* @throws Elk_Exception |
|
487
|
|
|
*/ |
|
488
|
|
|
function validateUsername($memID, $username, $ErrorContext = 'register', $check_reserved_name = true, $fatal = true) |
|
489
|
|
|
{ |
|
490
|
3 |
|
global $txt; |
|
491
|
|
|
|
|
492
|
3 |
|
$errors = ElkArte\Errors\ErrorContext::context($ErrorContext, 0); |
|
493
|
|
|
|
|
494
|
|
|
// Don't use too long a name. |
|
495
|
3 |
|
if (Util::strlen($username) > 25) |
|
496
|
3 |
|
$errors->addError('error_long_name'); |
|
497
|
|
|
|
|
498
|
|
|
// No name?! How can you register with no name? |
|
499
|
3 |
|
if ($username == '') |
|
500
|
3 |
|
$errors->addError('need_username'); |
|
501
|
|
|
|
|
502
|
|
|
// Only these characters are permitted. |
|
503
|
3 |
|
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) |
|
504
|
3 |
|
$errors->addError('error_invalid_characters_username'); |
|
505
|
|
|
|
|
506
|
3 |
|
if (stristr($username, $txt['guest_title']) !== false) |
|
507
|
3 |
|
$errors->addError(array('username_reserved', array($txt['guest_title'])), 1); |
|
508
|
|
|
|
|
509
|
|
|
if ($check_reserved_name) |
|
510
|
3 |
|
{ |
|
511
|
1 |
|
require_once(SUBSDIR . '/Members.subs.php'); |
|
512
|
1 |
|
if (isReservedName($username, $memID, false, $fatal)) |
|
513
|
1 |
|
$errors->addError(array('name_in_use', array(htmlspecialchars($username, ENT_COMPAT, 'UTF-8')))); |
|
514
|
1 |
|
} |
|
515
|
3 |
|
} |
|
516
|
|
|
|
|
517
|
|
|
/** |
|
518
|
|
|
* Checks whether a password meets the current forum rules |
|
519
|
|
|
* |
|
520
|
|
|
* What it does: |
|
521
|
|
|
* |
|
522
|
|
|
* - called when registering/choosing a password. |
|
523
|
|
|
* - checks the password obeys the current forum settings for password strength. |
|
524
|
|
|
* - if password checking is enabled, will check that none of the words in restrict_in appear in the password. |
|
525
|
|
|
* - returns an error identifier if the password is invalid, or null. |
|
526
|
|
|
* |
|
527
|
|
|
* @package Authorization |
|
528
|
|
|
* @param string $password |
|
529
|
|
|
* @param string $username |
|
530
|
|
|
* @param string[] $restrict_in = array() |
|
531
|
|
|
* @return string an error identifier if the password is invalid |
|
532
|
|
|
*/ |
|
533
|
|
|
function validatePassword($password, $username, $restrict_in = array()) |
|
534
|
|
|
{ |
|
535
|
1 |
|
global $modSettings, $txt; |
|
536
|
|
|
|
|
537
|
|
|
// Perform basic requirements first. |
|
538
|
1 |
|
if (Util::strlen($password) < (empty($modSettings['password_strength']) ? 4 : 8)) |
|
539
|
1 |
|
{ |
|
540
|
|
|
loadLanguage('Errors'); |
|
541
|
|
|
$txt['profile_error_password_short'] = sprintf($txt['profile_error_password_short'], empty($modSettings['password_strength']) ? 4 : 8); |
|
542
|
|
|
return 'short'; |
|
543
|
|
|
} |
|
544
|
|
|
|
|
545
|
|
|
// Is this enough? |
|
546
|
1 |
|
if (empty($modSettings['password_strength'])) |
|
547
|
1 |
|
return null; |
|
548
|
|
|
|
|
549
|
|
|
// Otherwise, perform the medium strength test - checking if password appears in the restricted string. |
|
550
|
|
|
if (preg_match('~\b' . preg_quote($password, '~') . '\b~', implode(' ', $restrict_in)) != 0) |
|
551
|
|
|
return 'restricted_words'; |
|
552
|
|
|
elseif (Util::strpos($password, $username) !== false) |
|
553
|
|
|
return 'restricted_words'; |
|
554
|
|
|
|
|
555
|
|
|
// If just medium, we're done. |
|
556
|
|
|
if ($modSettings['password_strength'] == 1) |
|
557
|
|
|
return null; |
|
558
|
|
|
|
|
559
|
|
|
// Otherwise, hard test next, check for numbers and letters, uppercase too. |
|
560
|
|
|
$good = preg_match('~(\D\d|\d\D)~', $password) != 0; |
|
561
|
|
|
$good &= Util::strtolower($password) != $password; |
|
562
|
|
|
|
|
563
|
|
|
return $good ? null : 'chars'; |
|
564
|
|
|
} |
|
565
|
|
|
|
|
566
|
|
|
/** |
|
567
|
|
|
* Checks whether an entered password is correct for the user |
|
568
|
|
|
* |
|
569
|
|
|
* What it does: |
|
570
|
|
|
* |
|
571
|
|
|
* - called when logging in or whenever a password needs to be validated for a user |
|
572
|
|
|
* - used to generate a new hash for the db, used during registration or any password changes |
|
573
|
|
|
* - if a non SHA256 password is sent, will generate one with SHA256(user + password) and return it in password |
|
574
|
|
|
* |
|
575
|
|
|
* @package Authorization |
|
576
|
|
|
* @param string $password user password if not already 64 characters long will be SHA256 with the user name |
|
577
|
|
|
* @param string $hash hash as generated from a SHA256 password |
|
578
|
|
|
* @param string $user user name only required if creating a SHA-256 password |
|
579
|
|
|
* @param boolean $returnhash flag to determine if we are returning a hash suitable for the database |
|
580
|
|
|
*/ |
|
581
|
|
|
function validateLoginPassword(&$password, $hash, $user = '', $returnhash = false) |
|
582
|
|
|
{ |
|
583
|
|
|
// Our hashing controller |
|
584
|
5 |
|
require_once(EXTDIR . '/PasswordHash.php'); |
|
585
|
|
|
|
|
586
|
|
|
// Base-2 logarithm of the iteration count used for password stretching, the |
|
587
|
|
|
// higher the number the more secure and CPU time consuming |
|
588
|
5 |
|
$hash_cost_log2 = 10; |
|
589
|
|
|
|
|
590
|
|
|
// Do we require the hashes to be portable to older systems (less secure)? |
|
591
|
5 |
|
$hash_portable = false; |
|
592
|
|
|
|
|
593
|
|
|
// Get an instance of the hasher |
|
594
|
5 |
|
$hasher = new PasswordHash($hash_cost_log2, $hash_portable); |
|
595
|
|
|
|
|
596
|
|
|
// If the password is not 64 characters, lets make it a (SHA-256) |
|
597
|
5 |
|
if (strlen($password) !== 64) |
|
598
|
5 |
|
$password = hash('sha256', Util::strtolower($user) . un_htmlspecialchars($password)); |
|
599
|
|
|
|
|
600
|
|
|
// They need a password hash, something to save in the db? |
|
601
|
|
|
if ($returnhash) |
|
602
|
5 |
|
{ |
|
603
|
3 |
|
$passhash = $hasher->HashPassword($password); |
|
604
|
|
|
|
|
605
|
|
|
// Something is not right, we can not generate a valid hash that's <20 characters |
|
606
|
3 |
|
if (strlen($passhash) < 20) |
|
607
|
3 |
|
$passhash = false; |
|
608
|
3 |
|
} |
|
609
|
|
|
// Or doing a password check? |
|
610
|
|
|
else |
|
611
|
2 |
|
$passhash = (bool) $hasher->CheckPassword($password, $hash); |
|
612
|
|
|
|
|
613
|
5 |
|
unset($hasher); |
|
614
|
|
|
|
|
615
|
5 |
|
return $passhash; |
|
616
|
|
|
} |
|
617
|
|
|
|
|
618
|
|
|
/** |
|
619
|
|
|
* Quickly find out what moderation authority this user has |
|
620
|
|
|
* |
|
621
|
|
|
* What it does: |
|
622
|
|
|
* |
|
623
|
|
|
* - builds the moderator, group and board level querys for the user |
|
624
|
|
|
* - stores the information on the current users moderation powers in $user_info['mod_cache'] and $_SESSION['mc'] |
|
625
|
|
|
* |
|
626
|
|
|
* @package Authorization |
|
627
|
|
|
*/ |
|
628
|
|
|
function rebuildModCache() |
|
629
|
|
|
{ |
|
630
|
|
|
global $user_info; |
|
631
|
|
|
|
|
632
|
|
|
$db = database(); |
|
633
|
|
|
|
|
634
|
|
|
// What groups can they moderate? |
|
635
|
|
|
$group_query = allowedTo('manage_membergroups') ? '1=1' : '0=1'; |
|
636
|
|
|
|
|
637
|
|
|
if ($group_query == '0=1') |
|
638
|
|
|
{ |
|
639
|
|
|
$groups = $db->fetchQueryCallback(' |
|
640
|
|
|
SELECT id_group |
|
641
|
|
|
FROM {db_prefix}group_moderators |
|
642
|
|
|
WHERE id_member = {int:current_member}', |
|
643
|
|
|
array( |
|
644
|
|
|
'current_member' => $user_info['id'], |
|
645
|
|
|
), |
|
646
|
|
|
function ($row) |
|
647
|
|
|
{ |
|
648
|
|
|
return $row['id_group']; |
|
649
|
|
|
} |
|
650
|
|
|
); |
|
651
|
|
|
|
|
652
|
|
|
if (empty($groups)) |
|
653
|
|
|
$group_query = '0=1'; |
|
654
|
|
|
else |
|
655
|
|
|
$group_query = 'id_group IN (' . implode(',', $groups) . ')'; |
|
656
|
|
|
} |
|
657
|
|
|
|
|
658
|
|
|
// Then, same again, just the boards this time! |
|
659
|
|
|
$board_query = allowedTo('moderate_forum') ? '1=1' : '0=1'; |
|
660
|
|
|
|
|
661
|
|
|
if ($board_query == '0=1') |
|
662
|
|
|
{ |
|
663
|
|
|
$boards = boardsAllowedTo('moderate_board', true); |
|
664
|
|
|
|
|
665
|
|
|
if (empty($boards)) |
|
666
|
|
|
$board_query = '0=1'; |
|
667
|
|
|
else |
|
668
|
|
|
$board_query = 'id_board IN (' . implode(',', $boards) . ')'; |
|
669
|
|
|
} |
|
670
|
|
|
|
|
671
|
|
|
// What boards are they the moderator of? |
|
672
|
|
|
$boards_mod = array(); |
|
673
|
|
|
if (!$user_info['is_guest']) |
|
674
|
|
|
{ |
|
675
|
|
|
require_once(SUBSDIR . '/Boards.subs.php'); |
|
676
|
|
|
$boards_mod = boardsModerated($user_info['id']); |
|
677
|
|
|
} |
|
678
|
|
|
|
|
679
|
|
|
$mod_query = empty($boards_mod) ? '0=1' : 'b.id_board IN (' . implode(',', $boards_mod) . ')'; |
|
680
|
|
|
|
|
681
|
|
|
$_SESSION['mc'] = array( |
|
682
|
|
|
'time' => time(), |
|
683
|
|
|
// This looks a bit funny but protects against the login redirect. |
|
684
|
|
|
'id' => $user_info['id'] && $user_info['name'] ? $user_info['id'] : 0, |
|
685
|
|
|
// If you change the format of 'gq' and/or 'bq' make sure to adjust 'can_mod' in Load.php. |
|
686
|
|
|
'gq' => $group_query, |
|
687
|
|
|
'bq' => $board_query, |
|
688
|
|
|
'ap' => boardsAllowedTo('approve_posts'), |
|
689
|
|
|
'mb' => $boards_mod, |
|
690
|
|
|
'mq' => $mod_query, |
|
691
|
|
|
); |
|
692
|
|
|
call_integration_hook('integrate_mod_cache'); |
|
693
|
|
|
|
|
694
|
|
|
$user_info['mod_cache'] = $_SESSION['mc']; |
|
695
|
|
|
|
|
696
|
|
|
// Might as well clean up some tokens while we are at it. |
|
697
|
|
|
cleanTokens(); |
|
698
|
|
|
} |
|
699
|
|
|
|
|
700
|
|
|
/** |
|
701
|
|
|
* The same thing as setcookie but allows for integration hook |
|
702
|
|
|
* |
|
703
|
|
|
* @package Authorization |
|
704
|
|
|
* @param string $name |
|
705
|
|
|
* @param string $value = '' |
|
706
|
|
|
* @param int $expire = 0 |
|
707
|
|
|
* @param string $path = '' |
|
708
|
|
|
* @param string $domain = '' |
|
709
|
|
|
* @param boolean|null $secure = false |
|
710
|
|
|
* @param boolean|null $httponly = null |
|
711
|
|
|
*/ |
|
712
|
|
|
function elk_setcookie($name, $value = '', $expire = 0, $path = '', $domain = '', $secure = null, $httponly = null) |
|
713
|
|
|
{ |
|
714
|
1 |
|
global $modSettings; |
|
715
|
|
|
|
|
716
|
|
|
// In case a customization wants to override the default settings |
|
717
|
1 |
|
if ($httponly === null) |
|
718
|
1 |
|
$httponly = !empty($modSettings['httponlyCookies']); |
|
719
|
1 |
|
if ($secure === null) |
|
720
|
1 |
|
$secure = !empty($modSettings['secureCookies']); |
|
721
|
|
|
|
|
722
|
|
|
// Intercept cookie? |
|
723
|
1 |
|
call_integration_hook('integrate_cookie', array($name, $value, $expire, $path, $domain, $secure, $httponly)); |
|
724
|
|
|
|
|
725
|
1 |
|
return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly); |
|
726
|
|
|
} |
|
727
|
|
|
|
|
728
|
|
|
/** |
|
729
|
|
|
* This functions determines whether this is the first login of the given user. |
|
730
|
|
|
* |
|
731
|
|
|
* @package Authorization |
|
732
|
|
|
* @param int $id_member the id of the member to check for |
|
733
|
|
|
*/ |
|
734
|
|
|
function isFirstLogin($id_member) |
|
735
|
|
|
{ |
|
736
|
|
|
// First login? |
|
737
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
|
738
|
|
|
$member = getBasicMemberData($id_member, array('moderation' => true)); |
|
739
|
|
|
|
|
740
|
|
|
return !empty($member) && $member['last_login'] == 0; |
|
741
|
|
|
} |
|
742
|
|
|
|
|
743
|
|
|
/** |
|
744
|
|
|
* Search for a member by given criteria |
|
745
|
|
|
* |
|
746
|
|
|
* @package Authorization |
|
747
|
|
|
* |
|
748
|
|
|
* @param string $where |
|
749
|
|
|
* @param mixed[] $where_params array of values to used in the where statement |
|
750
|
|
|
* @param bool $fatal |
|
751
|
|
|
* |
|
752
|
|
|
* @return array of members data or false on failure |
|
753
|
|
|
* @throws Elk_Exception no_user_with_email |
|
754
|
|
|
*/ |
|
755
|
|
|
function findUser($where, $where_params, $fatal = true) |
|
756
|
|
|
{ |
|
757
|
|
|
$db = database(); |
|
758
|
|
|
|
|
759
|
|
|
// Find the user! |
|
760
|
|
|
$request = $db->query('', ' |
|
761
|
|
|
SELECT id_member, real_name, member_name, email_address, is_activated, validation_code, lngfile, openid_uri, secret_question, passwd |
|
762
|
|
|
FROM {db_prefix}members |
|
763
|
|
|
WHERE ' . $where . ' |
|
764
|
|
|
LIMIT 1', |
|
765
|
|
|
array_merge($where_params, array( |
|
766
|
|
|
)) |
|
767
|
|
|
); |
|
768
|
|
|
|
|
769
|
|
|
// Maybe email? |
|
770
|
|
|
if ($db->num_rows($request) == 0 && empty($_REQUEST['uid']) && isset($where_params['email_address'])) |
|
771
|
|
|
{ |
|
772
|
|
|
$db->free_result($request); |
|
773
|
|
|
|
|
774
|
|
|
$request = $db->query('', ' |
|
775
|
|
|
SELECT id_member, real_name, member_name, email_address, is_activated, validation_code, lngfile, openid_uri, secret_question |
|
776
|
|
|
FROM {db_prefix}members |
|
777
|
|
|
WHERE email_address = {string:email_address} |
|
778
|
|
|
LIMIT 1', |
|
779
|
|
|
array_merge($where_params, array( |
|
780
|
|
|
)) |
|
781
|
|
|
); |
|
782
|
|
|
if ($db->num_rows($request) == 0) |
|
783
|
|
|
{ |
|
784
|
|
|
if ($fatal) |
|
785
|
|
|
throw new Elk_Exception('no_user_with_email', false); |
|
786
|
|
|
else |
|
787
|
|
|
return false; |
|
788
|
|
|
} |
|
789
|
|
|
} |
|
790
|
|
|
|
|
791
|
|
|
$member = $db->fetch_assoc($request); |
|
792
|
|
|
$db->free_result($request); |
|
793
|
|
|
|
|
794
|
|
|
return $member; |
|
795
|
|
|
} |
|
796
|
|
|
|
|
797
|
|
|
/** |
|
798
|
|
|
* Find users by their email address. |
|
799
|
|
|
* |
|
800
|
|
|
* @package Authorization |
|
801
|
|
|
* @param string $email |
|
802
|
|
|
* @param string|null $username |
|
803
|
|
|
* @return boolean |
|
804
|
|
|
*/ |
|
805
|
|
|
function userByEmail($email, $username = null) |
|
806
|
|
|
{ |
|
807
|
4 |
|
$db = database(); |
|
808
|
|
|
|
|
809
|
4 |
|
$request = $db->query('', ' |
|
810
|
|
|
SELECT id_member |
|
811
|
|
|
FROM {db_prefix}members |
|
812
|
4 |
|
WHERE email_address = {string:email_address}' . ($username === null ? '' : ' |
|
813
|
4 |
|
OR email_address = {string:username}') . ' |
|
814
|
4 |
|
LIMIT 1', |
|
815
|
|
|
array( |
|
816
|
4 |
|
'email_address' => $email, |
|
817
|
4 |
|
'username' => $username, |
|
818
|
|
|
) |
|
819
|
4 |
|
); |
|
820
|
|
|
|
|
821
|
4 |
|
$return = $db->num_rows($request) != 0; |
|
822
|
4 |
|
$db->free_result($request); |
|
823
|
|
|
|
|
824
|
4 |
|
return $return; |
|
825
|
|
|
} |
|
826
|
|
|
|
|
827
|
|
|
/** |
|
828
|
|
|
* Generate a random validation code. |
|
829
|
|
|
* |
|
830
|
|
|
* @package Authorization |
|
831
|
|
|
* @param int $length the number of characters to return |
|
832
|
|
|
*/ |
|
833
|
|
|
function generateValidationCode($length = 10) |
|
834
|
|
|
{ |
|
835
|
1 |
|
$tokenizer = new Token_Hash(); |
|
836
|
|
|
|
|
837
|
1 |
|
return $tokenizer->generate_hash((int) $length); |
|
838
|
|
|
} |
|
839
|
|
|
|
|
840
|
|
|
/** |
|
841
|
|
|
* This function loads many settings of a user given by name or email. |
|
842
|
|
|
* |
|
843
|
|
|
* @package Authorization |
|
844
|
|
|
* @param string $name |
|
845
|
|
|
* @param bool $is_id if true it treats $name as a member ID and try to load the data for that ID |
|
846
|
|
|
* @return mixed[]|false false if nothing is found |
|
847
|
|
|
*/ |
|
848
|
|
|
function loadExistingMember($name, $is_id = false) |
|
849
|
|
|
{ |
|
850
|
2 |
|
$db = database(); |
|
851
|
|
|
|
|
852
|
|
|
if ($is_id) |
|
853
|
2 |
|
{ |
|
854
|
1 |
|
$request = $db->query('', ' |
|
855
|
|
|
SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, |
|
856
|
|
|
openid_uri, passwd_flood, otp_secret, enable_otp, otp_used |
|
857
|
|
|
FROM {db_prefix}members |
|
858
|
|
|
WHERE id_member = {int:id_member} |
|
859
|
1 |
|
LIMIT 1', |
|
860
|
|
|
array( |
|
861
|
1 |
|
'id_member' => (int) $name, |
|
862
|
|
|
) |
|
863
|
1 |
|
); |
|
864
|
1 |
|
} |
|
865
|
|
|
else |
|
866
|
|
|
{ |
|
867
|
|
|
// Try to find the user, assuming a member_name was passed... |
|
868
|
1 |
|
$request = $db->query('', ' |
|
869
|
|
|
SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, |
|
870
|
|
|
openid_uri, passwd_flood, otp_secret, enable_otp, otp_used |
|
871
|
|
|
FROM {db_prefix}members |
|
872
|
1 |
|
WHERE ' . (defined('DB_CASE_SENSITIVE') ? 'LOWER(member_name) = LOWER({string:user_name})' : 'member_name = {string:user_name}') . ' |
|
873
|
1 |
|
LIMIT 1', |
|
874
|
|
|
array( |
|
875
|
1 |
|
'user_name' => defined('DB_CASE_SENSITIVE') ? strtolower($name) : $name, |
|
876
|
|
|
) |
|
877
|
1 |
|
); |
|
878
|
|
|
// Didn't work. Try it as an email address. |
|
879
|
1 |
|
if ($db->num_rows($request) == 0 && strpos($name, '@') !== false) |
|
880
|
1 |
|
{ |
|
881
|
|
|
$db->free_result($request); |
|
882
|
|
|
|
|
883
|
|
|
$request = $db->query('', ' |
|
884
|
|
|
SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri, |
|
885
|
|
|
passwd_flood, otp_secret, enable_otp, otp_used |
|
886
|
|
|
FROM {db_prefix}members |
|
887
|
|
|
WHERE email_address = {string:user_name} |
|
888
|
|
|
LIMIT 1', |
|
889
|
|
|
array( |
|
890
|
|
|
'user_name' => $name, |
|
891
|
|
|
) |
|
892
|
|
|
); |
|
893
|
|
|
} |
|
894
|
|
|
} |
|
895
|
|
|
|
|
896
|
|
|
// Nothing? Ah the horror... |
|
897
|
2 |
|
if ($db->num_rows($request) == 0) |
|
898
|
2 |
|
$user_settings = false; |
|
899
|
|
|
else |
|
900
|
|
|
{ |
|
901
|
2 |
|
$user_settings = $db->fetch_assoc($request); |
|
902
|
2 |
|
$user_settings['id_member'] = (int) $user_settings['id_member']; |
|
903
|
|
|
} |
|
904
|
|
|
|
|
905
|
2 |
|
$db->free_result($request); |
|
906
|
|
|
|
|
907
|
2 |
|
return $user_settings; |
|
908
|
|
|
} |
|
909
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.