1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace phpMyFAQ; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Creates a new user object. |
7
|
|
|
* |
8
|
|
|
* A user are recognized by the session-id using getUserBySessionId(), by his |
9
|
|
|
* using getUserById() or by his nickname (login) using getUserByLogin(). New |
10
|
|
|
* are created using createNewUser(). |
11
|
|
|
* |
12
|
|
|
* |
13
|
|
|
* |
14
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public License, |
15
|
|
|
* v. 2.0. If a copy of the MPL was not distributed with this file, You can |
16
|
|
|
* obtain one at http://mozilla.org/MPL/2.0/. |
17
|
|
|
* |
18
|
|
|
* @package phpMyFAQ |
19
|
|
|
* |
20
|
|
|
* @author Lars Tiedemann <[email protected]> |
21
|
|
|
* @author Thorsten Rinne <[email protected]> |
22
|
|
|
* @author Sarah Hermann <[email protected]> |
23
|
|
|
* @copyright 2005-2019 phpMyFAQ Team |
24
|
|
|
* @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 |
25
|
|
|
* @link https://www.phpmyfaq.de |
26
|
|
|
* @since 2005-09-17 |
27
|
|
|
*/ |
28
|
|
|
|
29
|
|
|
use phpMyFAQ\Auth\Driver; |
30
|
|
|
use phpMyFAQ\Permission\BasicPermission; |
31
|
|
|
use phpMyFAQ\Permission\MediumPermission; |
32
|
|
|
use phpMyFAQ\User\UserData; |
33
|
|
|
|
34
|
|
|
if (!defined('IS_VALID_PHPMYFAQ')) { |
35
|
|
|
exit(); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
if (!defined('PMF_ENCRYPTION_TYPE')) { |
39
|
|
|
define('PMF_ENCRYPTION_TYPE', 'md5'); // Fallback to md5() |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* User. |
44
|
|
|
* |
45
|
|
|
* @package phpMyFAQ |
46
|
|
|
* @author Lars Tiedemann <[email protected]> |
47
|
|
|
* @author Thorsten Rinne <[email protected]> |
48
|
|
|
* @author Sarah Hermann <[email protected]> |
49
|
|
|
* @copyright 2005-2019 phpMyFAQ Team |
50
|
|
|
* @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0 |
51
|
|
|
* @link https://www.phpmyfaq.de |
52
|
|
|
* @since 2005-09-17 |
53
|
|
|
*/ |
54
|
|
|
class User |
55
|
|
|
{ |
56
|
|
|
const ERROR_UNDEFINED_PARAMETER = 'Following parameter must to be defined: '; |
57
|
|
|
const ERROR_USER_ADD = 'Account could not be created. '; |
58
|
|
|
const ERROR_USER_CANNOT_CREATE_USER = 'User account could not be created. '; |
59
|
|
|
const ERROR_USER_CANNOT_CREATE_USERDATA = 'Entry for user data could not be created. '; |
60
|
|
|
const ERROR_USER_CANNOT_DELETE_USER = 'User account could not be deleted. '; |
61
|
|
|
const ERROR_USER_CANNOT_DELETE_USERDATA = 'Entry for user data could not be deleted. '; |
62
|
|
|
const ERROR_USER_CANNOT_UPDATE_USERDATA = 'Entry for user data could not be updated. '; |
63
|
|
|
const ERROR_USER_CHANGE = 'Account could not be updated. '; |
64
|
|
|
const ERROR_USER_DELETE = 'Account could not be deleted. '; |
65
|
|
|
const ERROR_USER_INCORRECT_LOGIN = 'Specified login could not be found. '; |
66
|
|
|
const ERROR_USER_INCORRECT_PASSWORD = 'Specified password is not correct.'; |
67
|
|
|
const ERROR_USER_INVALID_STATUS = 'Undefined user status.'; |
68
|
|
|
const ERROR_USER_LOGINNAME_TOO_SHORT = 'The chosen loginname is too short.'; |
69
|
|
|
const ERROR_USER_LOGIN_NOT_UNIQUE = 'Specified login name already exists. '; |
70
|
|
|
const ERROR_USER_LOGIN_INVALID = 'The chosen login is invalid. A valid login has at least four characters. Only letters, numbers and underscore _ are allowed. The first letter must be a letter. '; |
71
|
|
|
const ERROR_USER_NO_AUTH = 'No authentication method specified. '; |
72
|
|
|
const ERROR_USER_NO_DB = 'No database specified.'; |
73
|
|
|
const ERROR_USER_NO_PERM = 'No permission container specified.'; |
74
|
|
|
const ERROR_USER_NO_USERID = 'No user-ID found. '; |
75
|
|
|
const ERROR_USER_NO_USERLOGINDATA = 'No user login data found. '; |
76
|
|
|
const ERROR_USER_NOT_FOUND = 'User account could not be found. '; |
77
|
|
|
const ERROR_USER_NOWRITABLE = 'No authentication object is writable. '; |
78
|
|
|
const ERROR_USER_NO_LOGIN_DATA = 'A username and password must be provided. '; |
79
|
|
|
const ERROR_USER_TOO_MANY_FAILED_LOGINS = 'You exceeded the maximum amounts of login attempts and are temporarily blocked. Please try again later.'; |
80
|
|
|
|
81
|
|
|
const STATUS_USER_PROTECTED = 'User account is protected. '; |
82
|
|
|
const STATUS_USER_BLOCKED = 'User account is blocked. '; |
83
|
|
|
const STATUS_USER_ACTIVE = 'User account is active. '; |
84
|
|
|
|
85
|
|
|
// --- ATTRIBUTES --- |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* Permission container. |
89
|
|
|
* |
90
|
|
|
* @var BasicPermission|MediumPermission |
91
|
|
|
*/ |
92
|
|
|
public $perm = null; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* User-data storage container. |
96
|
|
|
* |
97
|
|
|
* @var UserData |
98
|
|
|
*/ |
99
|
|
|
public $userdata = null; |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Default Authentication properties. |
103
|
|
|
* |
104
|
|
|
* @var array |
105
|
|
|
*/ |
106
|
|
|
private $authData = [ |
107
|
|
|
'authSource' => [ |
108
|
|
|
'name' => 'database', |
109
|
|
|
'type' => 'local', |
110
|
|
|
], |
111
|
|
|
'encType' => PMF_ENCRYPTION_TYPE, |
112
|
|
|
'readOnly' => false, |
113
|
|
|
]; |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Public array that contains error messages. |
117
|
|
|
* |
118
|
|
|
* @var array |
119
|
|
|
*/ |
120
|
|
|
public $errors = []; |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* authentication container. |
124
|
|
|
* |
125
|
|
|
* @var Driver[] |
126
|
|
|
*/ |
127
|
|
|
protected $authContainer = []; |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* login string. |
131
|
|
|
* |
132
|
|
|
* @var string |
133
|
|
|
*/ |
134
|
|
|
private $login = ''; |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* minimum length of login string (default: 2). |
138
|
|
|
* |
139
|
|
|
* @var int |
140
|
|
|
*/ |
141
|
|
|
private $loginMinLength = 2; |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* regular expression to find invalid login strings |
145
|
|
|
* (default: /^[a-z0-9][\w\.\-@]+/i ). |
146
|
|
|
* |
147
|
|
|
* @var string |
148
|
|
|
*/ |
149
|
|
|
private $validUsername = '/^[a-z0-9][\w\.\-@]+/i'; |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* user ID. |
153
|
|
|
* |
154
|
|
|
* @var int |
155
|
|
|
*/ |
156
|
|
|
private $userId = -1; |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Status of user. |
160
|
|
|
* |
161
|
|
|
* @var string |
162
|
|
|
*/ |
163
|
|
|
private $status = ''; |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* IS the user a super admin? |
167
|
|
|
* @var bool |
168
|
|
|
*/ |
169
|
|
|
private $isSuperAdmin = false; |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* array of allowed values for status. |
173
|
|
|
* |
174
|
|
|
* @var array |
175
|
|
|
*/ |
176
|
|
|
private $allowedStatus = [ |
177
|
|
|
'active' => self::STATUS_USER_ACTIVE, |
178
|
|
|
'blocked' => self::STATUS_USER_BLOCKED, |
179
|
|
|
'protected' => self::STATUS_USER_PROTECTED, |
180
|
|
|
]; |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Configuration. |
184
|
|
|
* |
185
|
|
|
* @var Configuration |
186
|
|
|
*/ |
187
|
|
|
protected $config = null; |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Constructor. |
191
|
|
|
* |
192
|
|
|
* @param Configuration $config |
193
|
|
|
*/ |
194
|
|
|
public function __construct(Configuration $config) |
195
|
|
|
{ |
196
|
|
|
$this->config = $config; |
197
|
|
|
|
198
|
|
|
$perm = Permission::selectPerm($this->config->get('security.permLevel'), $this->config); |
199
|
|
|
if (!$this->addPerm($perm)) { |
200
|
|
|
return; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
// authentication objects |
204
|
|
|
// always make a 'local' $auth object (see: $authData) |
205
|
|
|
$this->authContainer = []; |
206
|
|
|
$auth = new Auth($this->config); |
207
|
|
|
$authLocal = $auth->selectAuth($this->getAuthSource('name')); |
208
|
|
|
$authLocal->selectEncType($this->getAuthData('encType')); |
209
|
|
|
$authLocal->setReadOnly($this->getAuthData('readOnly')); |
|
|
|
|
210
|
|
|
|
211
|
|
|
if (!$this->addAuth($authLocal, $this->getAuthSource('type'))) { |
|
|
|
|
212
|
|
|
return; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
// additionally, set given $auth objects |
216
|
|
|
if (count($this->authContainer) > 0) { |
217
|
|
|
foreach ($auth as $name => $authObject) { |
|
|
|
|
218
|
|
|
if (!$authObject instanceof Driver && !$this->addAuth($authObject, $name)) { |
219
|
|
|
break; |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
// user data object |
225
|
|
|
$this->userdata = new UserData($this->config); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* adds a permission object to the user. |
230
|
|
|
* |
231
|
|
|
* @param Permission $perm Permission object |
232
|
|
|
* |
233
|
|
|
* @return bool |
234
|
|
|
*/ |
235
|
|
|
public function addPerm(Permission $perm) |
236
|
|
|
{ |
237
|
|
|
if ($this->checkPerm($perm)) { |
238
|
|
|
$this->perm = $perm; |
|
|
|
|
239
|
|
|
return true; |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
$this->perm = null; |
243
|
|
|
return false; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Returns the User ID of the user. |
248
|
|
|
* |
249
|
|
|
* @return int |
250
|
|
|
*/ |
251
|
|
|
public function getUserId() |
252
|
|
|
{ |
253
|
|
|
if (isset($this->userId) && is_int($this->userId)) { |
254
|
|
|
return (int)$this->userId; |
255
|
|
|
} |
256
|
|
|
$this->userId = -1; |
257
|
|
|
$this->errors[] = self::ERROR_USER_NO_USERID; |
258
|
|
|
|
259
|
|
|
return -1; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
/** |
263
|
|
|
* Loads basic user information from the database selecting the user with |
264
|
|
|
* specified user-ID. |
265
|
|
|
* |
266
|
|
|
* @param int $userId User ID |
267
|
|
|
* @param bool $allowBlockedUsers Allow blocked users as well, e.g. in admin |
268
|
|
|
* |
269
|
|
|
* @return bool |
270
|
|
|
*/ |
271
|
|
|
public function getUserById($userId, $allowBlockedUsers = false) |
272
|
|
|
{ |
273
|
|
|
$select = sprintf(' |
274
|
|
|
SELECT |
275
|
|
|
user_id, |
276
|
|
|
login, |
277
|
|
|
account_status, |
278
|
|
|
is_superadmin |
279
|
|
|
FROM |
280
|
|
|
%sfaquser |
281
|
|
|
WHERE |
282
|
|
|
user_id = %d '.($allowBlockedUsers ? '' : "AND account_status != 'blocked'"), |
283
|
|
|
Db::getTablePrefix(), |
284
|
|
|
(int)$userId |
285
|
|
|
); |
286
|
|
|
|
287
|
|
|
$res = $this->config->getDb()->query($select); |
288
|
|
View Code Duplication |
if ($this->config->getDb()->numRows($res) != 1) { |
289
|
|
|
$this->errors[] = self::ERROR_USER_NO_USERID.'error(): '.$this->config->getDb()->error(); |
290
|
|
|
|
291
|
|
|
return false; |
292
|
|
|
} |
293
|
|
|
$user = $this->config->getDb()->fetchArray($res); |
294
|
|
|
$this->userId = (int)$user['user_id']; |
295
|
|
|
$this->login = (string)$user['login']; |
296
|
|
|
$this->status = (string)$user['account_status']; |
297
|
|
|
$this->isSuperAdmin = (bool)$user['is_superadmin']; |
298
|
|
|
|
299
|
|
|
// get encrypted password |
300
|
|
|
// @todo: Add a getEncPassword method to the Auth* classes for the (local and remote) Auth Sources. |
301
|
|
|
if ('db' === $this->getAuthSource('name')) { |
302
|
|
|
$select = sprintf(" |
303
|
|
|
SELECT |
304
|
|
|
pass |
305
|
|
|
FROM |
306
|
|
|
%sfaquserlogin |
307
|
|
|
WHERE |
308
|
|
|
login = '%s'", |
309
|
|
|
Db::getTablePrefix(), |
310
|
|
|
$this->login |
311
|
|
|
); |
312
|
|
|
|
313
|
|
|
$res = $this->config->getDb()->query($select); |
314
|
|
View Code Duplication |
if ($this->config->getDb()->numRows($res) != 1) { |
315
|
|
|
$this->errors[] = self::ERROR_USER_NO_USERLOGINDATA.'error(): '.$this->config->getDb()->error(); |
316
|
|
|
|
317
|
|
|
return false; |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
// get user-data |
321
|
|
|
if (!$this->userdata instanceof UserData) { |
322
|
|
|
$this->userdata = new UserData($this->config); |
323
|
|
|
} |
324
|
|
|
$this->userdata->load($this->getUserId()); |
325
|
|
|
|
326
|
|
|
return true; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* loads basic user information from the database selecting the user with |
331
|
|
|
* specified login. |
332
|
|
|
* |
333
|
|
|
* @param string $login Login name |
334
|
|
|
* @param bool $raiseError Raise error? |
335
|
|
|
* |
336
|
|
|
* @return bool |
337
|
|
|
*/ |
338
|
|
View Code Duplication |
public function getUserByLogin($login, $raiseError = true) |
|
|
|
|
339
|
|
|
{ |
340
|
|
|
$select = sprintf(" |
341
|
|
|
SELECT |
342
|
|
|
user_id, |
343
|
|
|
login, |
344
|
|
|
account_status |
345
|
|
|
FROM |
346
|
|
|
%sfaquser |
347
|
|
|
WHERE |
348
|
|
|
login = '%s'", |
349
|
|
|
Db::getTablePrefix(), |
350
|
|
|
$this->config->getDb()->escape($login) |
351
|
|
|
); |
352
|
|
|
|
353
|
|
|
$res = $this->config->getDb()->query($select); |
354
|
|
|
if ($this->config->getDb()->numRows($res) !== 1) { |
355
|
|
|
if ($raiseError) { |
356
|
|
|
$this->errors[] = self::ERROR_USER_INCORRECT_LOGIN; |
357
|
|
|
} |
358
|
|
|
|
359
|
|
|
return false; |
360
|
|
|
} |
361
|
|
|
$user = $this->config->getDb()->fetchArray($res); |
362
|
|
|
$this->userId = (int)$user['user_id']; |
363
|
|
|
$this->login = (string)$user['login']; |
364
|
|
|
$this->status = (string)$user['account_status']; |
365
|
|
|
|
366
|
|
|
// get user-data |
367
|
|
|
if (!$this->userdata instanceof UserData) { |
368
|
|
|
$this->userdata = new UserData($this->config); |
369
|
|
|
} |
370
|
|
|
$this->userdata->load($this->getUserId()); |
371
|
|
|
|
372
|
|
|
return true; |
373
|
|
|
} |
374
|
|
|
|
375
|
|
|
/** |
376
|
|
|
* loads basic user information from the database selecting the user with |
377
|
|
|
* specified cookie information. |
378
|
|
|
* |
379
|
|
|
* @param string $cookie |
380
|
|
|
* |
381
|
|
|
* @return bool |
382
|
|
|
*/ |
383
|
|
View Code Duplication |
public function getUserByCookie($cookie) |
|
|
|
|
384
|
|
|
{ |
385
|
|
|
$select = sprintf(" |
386
|
|
|
SELECT |
387
|
|
|
user_id, |
388
|
|
|
login, |
389
|
|
|
account_status |
390
|
|
|
FROM |
391
|
|
|
%sfaquser |
392
|
|
|
WHERE |
393
|
|
|
remember_me = '%s' AND account_status != 'blocked'", |
394
|
|
|
Db::getTablePrefix(), |
395
|
|
|
$this->config->getDb()->escape($cookie) |
396
|
|
|
); |
397
|
|
|
|
398
|
|
|
$res = $this->config->getDb()->query($select); |
399
|
|
|
if ($this->config->getDb()->numRows($res) !== 1) { |
400
|
|
|
$this->errors[] = self::ERROR_USER_INCORRECT_LOGIN; |
401
|
|
|
|
402
|
|
|
return false; |
403
|
|
|
} |
404
|
|
|
$user = $this->config->getDb()->fetchArray($res); |
405
|
|
|
|
406
|
|
|
// Don't ever login via anonymous user |
407
|
|
|
if (-1 === $user['user_id']) { |
408
|
|
|
return false; |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
$this->userId = (int)$user['user_id']; |
412
|
|
|
$this->login = (string)$user['login']; |
413
|
|
|
$this->status = (string)$user['account_status']; |
414
|
|
|
|
415
|
|
|
// get user-data |
416
|
|
|
if (!$this->userdata instanceof UserData) { |
417
|
|
|
$this->userdata = new UserData($this->config); |
418
|
|
|
} |
419
|
|
|
$this->userdata->load($this->getUserId()); |
420
|
|
|
|
421
|
|
|
return true; |
422
|
|
|
} |
423
|
|
|
|
424
|
|
|
/** |
425
|
|
|
* Checks if display name is already used. Returns true, if already in use. |
426
|
|
|
* |
427
|
|
|
* @param string $name |
428
|
|
|
* |
429
|
|
|
* @return bool |
430
|
|
|
*/ |
431
|
|
View Code Duplication |
public function checkDisplayName($name) |
|
|
|
|
432
|
|
|
{ |
433
|
|
|
if (!$this->userdata instanceof UserData) { |
434
|
|
|
$this->userdata = new UserData($this->config); |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
if ($name === $this->userdata->fetch('display_name', $name)) { |
438
|
|
|
return true; |
439
|
|
|
} else { |
440
|
|
|
return false; |
441
|
|
|
} |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
/** |
445
|
|
|
* Checks if email address is already used. Returns true, if already in use. |
446
|
|
|
* |
447
|
|
|
* @param string $name |
448
|
|
|
* |
449
|
|
|
* @return bool |
450
|
|
|
*/ |
451
|
|
View Code Duplication |
public function checkMailAddress($name) |
|
|
|
|
452
|
|
|
{ |
453
|
|
|
if (!$this->userdata instanceof UserData) { |
454
|
|
|
$this->userdata = new UserData($this->config); |
455
|
|
|
} |
456
|
|
|
|
457
|
|
|
if ($name === $this->userdata->fetch('email', $name)) { |
458
|
|
|
return true; |
459
|
|
|
} else { |
460
|
|
|
return false; |
461
|
|
|
} |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
/** |
465
|
|
|
* search users by login. |
466
|
|
|
* |
467
|
|
|
* @param string $search Login name |
468
|
|
|
* |
469
|
|
|
* @return array |
470
|
|
|
*/ |
471
|
|
|
public function searchUsers($search) |
472
|
|
|
{ |
473
|
|
|
$select = sprintf(" |
474
|
|
|
SELECT |
475
|
|
|
login, |
476
|
|
|
user_id, |
477
|
|
|
account_status |
478
|
|
|
FROM |
479
|
|
|
%sfaquser |
480
|
|
|
WHERE |
481
|
|
|
login LIKE '%s'", |
482
|
|
|
Db::getTablePrefix(), |
483
|
|
|
$this->config->getDb()->escape($search.'%') |
484
|
|
|
); |
485
|
|
|
|
486
|
|
|
$res = $this->config->getDb()->query($select); |
487
|
|
|
if (!$res) { |
488
|
|
|
return []; |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
$result = []; |
492
|
|
|
while ($row = $this->config->getDb()->fetchArray($res)) { |
493
|
|
|
$result[] = $row; |
494
|
|
|
} |
495
|
|
|
|
496
|
|
|
return $result; |
497
|
|
|
} |
498
|
|
|
|
499
|
|
|
/** |
500
|
|
|
* Creates a new user and stores basic data in the database. |
501
|
|
|
* |
502
|
|
|
* @param string $login |
503
|
|
|
* @param string $pass |
504
|
|
|
* @param string $domain |
505
|
|
|
* @param int $userId |
506
|
|
|
* |
507
|
|
|
* @return boolean |
508
|
|
|
*/ |
509
|
|
|
public function createUser($login, $pass = '', $domain = '', $userId = 0) |
510
|
|
|
{ |
511
|
|
|
foreach ($this->authContainer as $auth) { |
512
|
|
|
if (!$this->checkAuth($auth)) { |
513
|
|
|
return false; |
514
|
|
|
} |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
// is $login valid? |
518
|
|
|
$login = (string)$login; |
519
|
|
|
if (!$this->isValidLogin($login)) { |
520
|
|
|
$this->errors[] = self::ERROR_USER_LOGINNAME_TOO_SHORT; |
521
|
|
|
|
522
|
|
|
return false; |
523
|
|
|
} |
524
|
|
|
|
525
|
|
|
// does $login already exist? |
526
|
|
|
if ($this->getUserByLogin($login, false)) { |
527
|
|
|
$this->errors[] = self::ERROR_USER_LOGIN_NOT_UNIQUE; |
528
|
|
|
|
529
|
|
|
return false; |
530
|
|
|
} |
531
|
|
|
|
532
|
|
|
// set user-ID |
533
|
|
|
if (0 == $userId) { |
534
|
|
|
$this->userId = (int)$this->config->getDb()->nextId(Db::getTablePrefix().'faquser', 'user_id'); |
535
|
|
|
} else { |
536
|
|
|
$this->userId = $userId; |
537
|
|
|
} |
538
|
|
|
|
539
|
|
|
// create user entry |
540
|
|
|
$insert = sprintf(" |
541
|
|
|
INSERT INTO |
542
|
|
|
%sfaquser |
543
|
|
|
(user_id, login, session_timestamp, member_since) |
544
|
|
|
VALUES |
545
|
|
|
(%d, '%s', %d, '%s')", |
546
|
|
|
Db::getTablePrefix(), |
547
|
|
|
$this->getUserId(), |
548
|
|
|
$this->config->getDb()->escape($login), |
549
|
|
|
$_SERVER['REQUEST_TIME'], |
550
|
|
|
date('YmdHis', $_SERVER['REQUEST_TIME']) |
551
|
|
|
); |
552
|
|
|
|
553
|
|
|
$this->config->getDb()->query($insert); |
554
|
|
|
if (!$this->userdata instanceof UserData) { |
555
|
|
|
$this->userdata = new UserData($this->config); |
556
|
|
|
} |
557
|
|
|
$data = $this->userdata->add($this->getUserId()); |
558
|
|
|
if (!$data) { |
559
|
|
|
$this->errors[] = self::ERROR_USER_CANNOT_CREATE_USERDATA; |
560
|
|
|
|
561
|
|
|
return false; |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
// create authentication entry |
565
|
|
|
if ($pass == '') { |
566
|
|
|
$pass = $this->createPassword(); |
567
|
|
|
} |
568
|
|
|
$success = false; |
569
|
|
|
|
570
|
|
|
foreach ($this->authContainer as $name => $auth) { |
571
|
|
|
if ($auth->setReadOnly()) { |
572
|
|
|
continue; |
573
|
|
|
} |
574
|
|
|
if (!$auth->add($login, $pass, $domain)) { |
575
|
|
|
$this->errors[] = self::ERROR_USER_CANNOT_CREATE_USER.'in Auth '.$name; |
576
|
|
|
} else { |
577
|
|
|
$success = true; |
578
|
|
|
} |
579
|
|
|
} |
580
|
|
|
if (!$success) { |
581
|
|
|
return false; |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
if ($this->perm instanceof MediumPermission) { |
585
|
|
|
$this->perm->autoJoin($this->userId); |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
return $this->getUserByLogin($login, false); |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
/** |
592
|
|
|
* deletes the user from the database. |
593
|
|
|
* |
594
|
|
|
* @return bool |
595
|
|
|
*/ |
596
|
|
|
public function deleteUser() |
597
|
|
|
{ |
598
|
|
|
if (!isset($this->userId) || $this->userId == 0) { |
599
|
|
|
$this->errors[] = self::ERROR_USER_NO_USERID; |
600
|
|
|
|
601
|
|
|
return false; |
602
|
|
|
} |
603
|
|
|
|
604
|
|
|
if (!isset($this->login) || strlen($this->login) == 0) { |
605
|
|
|
$this->errors[] = self::ERROR_USER_LOGIN_INVALID; |
606
|
|
|
|
607
|
|
|
return false; |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
if (isset($this->allowedStatus[$this->status]) && $this->allowedStatus[$this->status] == self::STATUS_USER_PROTECTED) { |
611
|
|
|
$this->errors[] = self::ERROR_USER_CANNOT_DELETE_USER.self::STATUS_USER_PROTECTED; |
612
|
|
|
|
613
|
|
|
return false; |
614
|
|
|
} |
615
|
|
|
|
616
|
|
|
$this->perm->refuseAllUserRights($this->userId); |
617
|
|
|
|
618
|
|
|
$delete = sprintf(' |
619
|
|
|
DELETE FROM |
620
|
|
|
%sfaquser |
621
|
|
|
WHERE |
622
|
|
|
user_id = %d', |
623
|
|
|
Db::getTablePrefix(), |
624
|
|
|
$this->userId |
625
|
|
|
); |
626
|
|
|
|
627
|
|
|
$res = $this->config->getDb()->query($delete); |
628
|
|
View Code Duplication |
if (!$res) { |
629
|
|
|
$this->errors[] = self::ERROR_USER_CANNOT_DELETE_USER.'error(): '.$this->config->getDb()->error(); |
630
|
|
|
|
631
|
|
|
return false; |
632
|
|
|
} |
633
|
|
|
|
634
|
|
|
if (!$this->userdata instanceof UserData) { |
635
|
|
|
$this->userdata = new UserData($this->config); |
636
|
|
|
} |
637
|
|
|
$data = $this->userdata->delete($this->getUserId()); |
638
|
|
|
if (!$data) { |
639
|
|
|
$this->errors[] = self::ERROR_USER_CANNOT_DELETE_USERDATA; |
640
|
|
|
|
641
|
|
|
return false; |
642
|
|
|
} |
643
|
|
|
|
644
|
|
|
$readOnly = 0; |
645
|
|
|
$authCount = 0; |
646
|
|
|
$delete = []; |
647
|
|
|
foreach ($this->authContainer as $auth) { |
648
|
|
|
++$authCount; |
649
|
|
|
if ($auth->setReadOnly()) { |
650
|
|
|
++$readOnly; |
651
|
|
|
continue; |
652
|
|
|
} |
653
|
|
|
$delete[] = $auth->delete($this->login); |
654
|
|
|
} |
655
|
|
|
|
656
|
|
|
if ($readOnly == $authCount) { |
657
|
|
|
$this->errors[] = self::ERROR_USER_NO_AUTH_WRITABLE; |
658
|
|
|
} |
659
|
|
|
if (!in_array(true, $delete)) { |
660
|
|
|
return false; |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
return true; |
664
|
|
|
} |
665
|
|
|
|
666
|
|
|
/** |
667
|
|
|
* changes the user's password. If $pass is omitted, a new |
668
|
|
|
* password is generated using the createPassword() method. |
669
|
|
|
* |
670
|
|
|
* @param string $pass Password |
671
|
|
|
* |
672
|
|
|
* @return bool |
673
|
|
|
*/ |
674
|
|
|
public function changePassword($pass = '') |
675
|
|
|
{ |
676
|
|
|
foreach ($this->authContainer as $auth) { |
677
|
|
|
if (!$this->checkAuth($auth)) { |
678
|
|
|
return false; |
679
|
|
|
} |
680
|
|
|
} |
681
|
|
|
|
682
|
|
|
$login = $this->getLogin(); |
683
|
|
|
if ($pass == '') { |
684
|
|
|
$pass = $this->createPassword(); |
685
|
|
|
} |
686
|
|
|
|
687
|
|
|
$success = false; |
688
|
|
|
foreach ($this->authContainer as $auth) { |
689
|
|
|
if ($auth->setReadOnly()) { |
690
|
|
|
continue; |
691
|
|
|
} |
692
|
|
|
if (!$auth->changePassword($login, $pass)) { |
693
|
|
|
continue; |
694
|
|
|
} else { |
695
|
|
|
$success = true; |
696
|
|
|
} |
697
|
|
|
} |
698
|
|
|
|
699
|
|
|
return $success; |
700
|
|
|
} |
701
|
|
|
|
702
|
|
|
/** |
703
|
|
|
* returns the user's status. |
704
|
|
|
* |
705
|
|
|
* @return string |
706
|
|
|
*/ |
707
|
|
|
public function getStatus() |
708
|
|
|
{ |
709
|
|
|
if (isset($this->status) && strlen($this->status) > 0) { |
710
|
|
|
return $this->status; |
711
|
|
|
} |
712
|
|
|
|
713
|
|
|
return false; |
714
|
|
|
} |
715
|
|
|
|
716
|
|
|
/** |
717
|
|
|
* Sets the user's status and updates the database entry. |
718
|
|
|
* |
719
|
|
|
* @param string $status Status |
720
|
|
|
* @return bool |
721
|
|
|
*/ |
722
|
|
|
public function setStatus($status) |
723
|
|
|
{ |
724
|
|
|
// is status allowed? |
725
|
|
|
$status = strtolower($status); |
726
|
|
|
if (!in_array($status, array_keys($this->allowedStatus))) { |
727
|
|
|
$this->errors[] = self::ERROR_USER_INVALID_STATUS; |
728
|
|
|
|
729
|
|
|
return false; |
730
|
|
|
} |
731
|
|
|
|
732
|
|
|
// update status |
733
|
|
|
$this->status = $status; |
734
|
|
|
$update = sprintf(" |
735
|
|
|
UPDATE |
736
|
|
|
%sfaquser |
737
|
|
|
SET |
738
|
|
|
account_status = '%s' |
739
|
|
|
WHERE |
740
|
|
|
user_id = %d", |
741
|
|
|
Db::getTablePrefix(), |
742
|
|
|
$this->config->getDb()->escape($status), |
743
|
|
|
$this->userId |
744
|
|
|
); |
745
|
|
|
|
746
|
|
|
$res = $this->config->getDb()->query($update); |
747
|
|
|
|
748
|
|
|
if ($res) { |
749
|
|
|
return true; |
750
|
|
|
} |
751
|
|
|
|
752
|
|
|
return false; |
753
|
|
|
} |
754
|
|
|
|
755
|
|
|
/** |
756
|
|
|
* Returns a string with error messages. |
757
|
|
|
* |
758
|
|
|
* The string returned by error() contains messages for all errors that |
759
|
|
|
* during object procesing. Messages are separated by new lines. |
760
|
|
|
* |
761
|
|
|
* Error messages are stored in the public array errors. |
762
|
|
|
* |
763
|
|
|
* @return string |
764
|
|
|
*/ |
765
|
|
|
public function error() |
766
|
|
|
{ |
767
|
|
|
$message = ''; |
768
|
|
|
foreach ($this->errors as $error) { |
769
|
|
|
$message .= $error."<br>\n"; |
770
|
|
|
} |
771
|
|
|
$this->errors = []; |
772
|
|
|
|
773
|
|
|
return $message; |
774
|
|
|
} |
775
|
|
|
|
776
|
|
|
/** |
777
|
|
|
* returns true if login is a valid login string. |
778
|
|
|
* |
779
|
|
|
* $this->loginMinLength defines the minimum length the |
780
|
|
|
* login string. If login has more characters than allowed, |
781
|
|
|
* false is returned. |
782
|
|
|
* $this->login_invalidRegExp is a regular expression. |
783
|
|
|
* If login matches this false is returned. |
784
|
|
|
* |
785
|
|
|
* @param string $login Login name |
786
|
|
|
* |
787
|
|
|
* @return bool |
788
|
|
|
*/ |
789
|
|
|
public function isValidLogin($login) |
790
|
|
|
{ |
791
|
|
|
$login = (string)$login; |
792
|
|
|
|
793
|
|
|
if (strlen($login) < $this->loginMinLength || !preg_match($this->validUsername, $login)) { |
794
|
|
|
$this->errors[] = self::ERROR_USER_LOGIN_INVALID; |
795
|
|
|
|
796
|
|
|
return false; |
797
|
|
|
} |
798
|
|
|
|
799
|
|
|
return true; |
800
|
|
|
} |
801
|
|
|
|
802
|
|
|
/** |
803
|
|
|
* adds a new authentication object to the user object. |
804
|
|
|
* |
805
|
|
|
* @param Driver $auth Driver object |
806
|
|
|
* @param string $name Auth name |
807
|
|
|
* |
808
|
|
|
* @return bool |
809
|
|
|
*/ |
810
|
|
|
public function addAuth($auth, $name) |
811
|
|
|
{ |
812
|
|
|
if ($this->checkAuth($auth)) { |
813
|
|
|
$this->authContainer[$name] = $auth; |
814
|
|
|
|
815
|
|
|
return true; |
816
|
|
|
} |
817
|
|
|
|
818
|
|
|
return false; |
819
|
|
|
} |
820
|
|
|
|
821
|
|
|
/** |
822
|
|
|
* Returns true if auth is a valid authentication object. |
823
|
|
|
* |
824
|
|
|
* @param Driver $auth Auth object |
825
|
|
|
* |
826
|
|
|
* @return bool |
827
|
|
|
*/ |
828
|
|
|
protected function checkAuth($auth) |
829
|
|
|
{ |
830
|
|
|
$methods = ['checkPassword']; |
831
|
|
|
foreach ($methods as $method) { |
832
|
|
|
if (!method_exists($auth, $method)) { |
833
|
|
|
return false; |
834
|
|
|
break; |
|
|
|
|
835
|
|
|
} |
836
|
|
|
} |
837
|
|
|
|
838
|
|
|
return true; |
839
|
|
|
} |
840
|
|
|
|
841
|
|
|
/** |
842
|
|
|
* Returns the data aof the auth container. |
843
|
|
|
* |
844
|
|
|
* @return Driver[] |
845
|
|
|
*/ |
846
|
|
|
public function getAuthContainer() |
847
|
|
|
{ |
848
|
|
|
return $this->authContainer; |
849
|
|
|
} |
850
|
|
|
|
851
|
|
|
/** |
852
|
|
|
* Returns a specific entry from the auth data source array. |
853
|
|
|
* |
854
|
|
|
* @param string $key |
855
|
|
|
* |
856
|
|
|
* @return string|null |
857
|
|
|
*/ |
858
|
|
|
public function getAuthSource($key) |
859
|
|
|
{ |
860
|
|
|
if (isset($this->authData['authSource'][$key])) { |
861
|
|
|
return $this->authData['authSource'][$key]; |
862
|
|
|
} else { |
863
|
|
|
return; |
864
|
|
|
} |
865
|
|
|
} |
866
|
|
|
|
867
|
|
|
/** |
868
|
|
|
* Returns a specific entry from the auth data array. |
869
|
|
|
* |
870
|
|
|
* @param string $key |
871
|
|
|
* |
872
|
|
|
* @return string|null |
873
|
|
|
*/ |
874
|
|
|
public function getAuthData($key) |
875
|
|
|
{ |
876
|
|
|
if (isset($this->authData[$key])) { |
877
|
|
|
return $this->authData[$key]; |
878
|
|
|
} else { |
879
|
|
|
return null; |
880
|
|
|
} |
881
|
|
|
} |
882
|
|
|
|
883
|
|
|
/** |
884
|
|
|
* returns true if perm is a valid permission object. |
885
|
|
|
* |
886
|
|
|
* @param Permission $perm Permission object |
887
|
|
|
* |
888
|
|
|
* @return bool |
889
|
|
|
*/ |
890
|
|
|
private function checkPerm($perm) |
891
|
|
|
{ |
892
|
|
|
if ($perm instanceof Permission) { |
893
|
|
|
return true; |
894
|
|
|
} |
895
|
|
|
$this->errors[] = self::ERROR_USER_NO_PERM; |
896
|
|
|
|
897
|
|
|
return false; |
898
|
|
|
} |
899
|
|
|
|
900
|
|
|
/** |
901
|
|
|
* returns the user's login. |
902
|
|
|
* |
903
|
|
|
* @return string |
904
|
|
|
*/ |
905
|
|
|
public function getLogin() |
906
|
|
|
{ |
907
|
|
|
return $this->login; |
908
|
|
|
} |
909
|
|
|
|
910
|
|
|
/** |
911
|
|
|
* Returns the data of the current user. |
912
|
|
|
* |
913
|
|
|
* @param string $field Field |
914
|
|
|
* |
915
|
|
|
* @return array|string|int |
916
|
|
|
*/ |
917
|
|
|
public function getUserData($field = '*') |
918
|
|
|
{ |
919
|
|
|
if (!($this->userdata instanceof UserData)) { |
920
|
|
|
$this->userdata = new UserData($this->config); |
921
|
|
|
} |
922
|
|
|
|
923
|
|
|
return $this->userdata->get($field); |
924
|
|
|
} |
925
|
|
|
|
926
|
|
|
/** |
927
|
|
|
* Adds user data. |
928
|
|
|
* |
929
|
|
|
* @param array $data Array with user data |
930
|
|
|
* |
931
|
|
|
* @return bool |
932
|
|
|
*/ |
933
|
|
|
public function setUserData(Array $data) |
934
|
|
|
{ |
935
|
|
|
if (!($this->userdata instanceof UserData)) { |
936
|
|
|
$this->userdata = new UserData($this->config); |
937
|
|
|
} |
938
|
|
|
$this->userdata->load($this->getUserId()); |
939
|
|
|
|
940
|
|
|
return $this->userdata->set(array_keys($data), array_values($data)); |
941
|
|
|
} |
942
|
|
|
|
943
|
|
|
/** |
944
|
|
|
* Returns an array with the user-IDs of all users found in |
945
|
|
|
* the database. By default, the Anonymous User will not be returned. |
946
|
|
|
* |
947
|
|
|
* @param bool $withoutAnonymous Without anonymous? |
948
|
|
|
* @param bool $allowBlockedUsers Allow blocked users as well, e.g. in admin |
949
|
|
|
* |
950
|
|
|
* @return array |
951
|
|
|
*/ |
952
|
|
View Code Duplication |
public function getAllUsers($withoutAnonymous = true, $allowBlockedUsers = true) |
|
|
|
|
953
|
|
|
{ |
954
|
|
|
$select = sprintf(' |
955
|
|
|
SELECT |
956
|
|
|
user_id |
957
|
|
|
FROM |
958
|
|
|
%sfaquser |
959
|
|
|
WHERE |
960
|
|
|
1 = 1 |
961
|
|
|
%s |
962
|
|
|
%s |
963
|
|
|
ORDER BY |
964
|
|
|
user_id ASC', |
965
|
|
|
Db::getTablePrefix(), |
966
|
|
|
($withoutAnonymous ? 'AND user_id <> -1' : ''), |
967
|
|
|
($allowBlockedUsers ? '' : "AND account_status != 'blocked'") |
968
|
|
|
); |
969
|
|
|
|
970
|
|
|
$res = $this->config->getDb()->query($select); |
971
|
|
|
if (!$res) { |
972
|
|
|
return []; |
973
|
|
|
} |
974
|
|
|
|
975
|
|
|
$result = []; |
976
|
|
|
while ($row = $this->config->getDb()->fetchArray($res)) { |
977
|
|
|
$result[] = $row['user_id']; |
978
|
|
|
} |
979
|
|
|
|
980
|
|
|
return $result; |
981
|
|
|
} |
982
|
|
|
|
983
|
|
|
/** |
984
|
|
|
* Returns an array of all users found in the database. By default, the |
985
|
|
|
* anonymous User will not be returned. The returned array contains the |
986
|
|
|
* user ID as key, the values are login name, account status, authentication |
987
|
|
|
* source and the user creation date. |
988
|
|
|
* |
989
|
|
|
* @param bool $withoutAnonymous Without anonymous? |
990
|
|
|
* |
991
|
|
|
* @return array |
992
|
|
|
*/ |
993
|
|
View Code Duplication |
public function getAllUserData($withoutAnonymous = true) |
|
|
|
|
994
|
|
|
{ |
995
|
|
|
$select = sprintf(' |
996
|
|
|
SELECT |
997
|
|
|
user_id, login, account_status, auth_source, member_since |
998
|
|
|
FROM |
999
|
|
|
%sfaquser |
1000
|
|
|
%s |
1001
|
|
|
ORDER BY |
1002
|
|
|
login ASC', |
1003
|
|
|
Db::getTablePrefix(), |
1004
|
|
|
($withoutAnonymous ? 'WHERE user_id <> -1' : '')); |
1005
|
|
|
|
1006
|
|
|
$res = $this->config->getDb()->query($select); |
1007
|
|
|
if (!$res) { |
1008
|
|
|
return []; |
1009
|
|
|
} |
1010
|
|
|
|
1011
|
|
|
$result = []; |
1012
|
|
|
while ($row = $this->config->getDb()->fetchArray($res)) { |
1013
|
|
|
$result[$row['user_id']] = $row; |
1014
|
|
|
} |
1015
|
|
|
|
1016
|
|
|
return $result; |
1017
|
|
|
} |
1018
|
|
|
|
1019
|
|
|
/** |
1020
|
|
|
* Get all users in <option> tags. |
1021
|
|
|
* |
1022
|
|
|
* @param int $id Selected user ID |
1023
|
|
|
* @param bool $allowBlockedUsers Allow blocked users as well, e.g. in admin |
1024
|
|
|
* |
1025
|
|
|
* @return string |
1026
|
|
|
*/ |
1027
|
|
|
public function getAllUserOptions($id = 1, $allowBlockedUsers = false) |
1028
|
|
|
{ |
1029
|
|
|
$options = ''; |
1030
|
|
|
$allUsers = $this->getAllUsers(true, $allowBlockedUsers); |
1031
|
|
|
|
1032
|
|
|
foreach ($allUsers as $userId) { |
1033
|
|
|
if (-1 !== $userId) { |
1034
|
|
|
$this->getUserById($userId); |
1035
|
|
|
$options .= sprintf( |
1036
|
|
|
'<option value="%d"%s>%s (%s)</option>', |
1037
|
|
|
$userId, |
1038
|
|
|
(($userId === $id) ? ' selected' : ''), |
1039
|
|
|
$this->getUserData('display_name'), |
1040
|
|
|
$this->getLogin() |
1041
|
|
|
); |
1042
|
|
|
} |
1043
|
|
|
} |
1044
|
|
|
|
1045
|
|
|
return $options; |
1046
|
|
|
} |
1047
|
|
|
|
1048
|
|
|
/** |
1049
|
|
|
* sets the minimum login string length. |
1050
|
|
|
* |
1051
|
|
|
* @param int $loginMinLength Minimum length of login name |
1052
|
|
|
*/ |
1053
|
|
|
public function setLoginMinLength($loginMinLength) |
1054
|
|
|
{ |
1055
|
|
|
if (is_int($loginMinLength)) { |
1056
|
|
|
$this->loginMinLength = $loginMinLength; |
1057
|
|
|
} |
1058
|
|
|
} |
1059
|
|
|
|
1060
|
|
|
/** |
1061
|
|
|
* Returns a new password. |
1062
|
|
|
* |
1063
|
|
|
* @param int $minimumLength |
1064
|
|
|
* @param bool $allowUnderscore |
1065
|
|
|
* |
1066
|
|
|
* @return string |
1067
|
|
|
*/ |
1068
|
|
|
public function createPassword($minimumLength = 8, $allowUnderscore = true) |
1069
|
|
|
{ |
1070
|
|
|
// To make passwords harder to get wrong, a few letters & numbers have been omitted. |
1071
|
|
|
// This will ensure safety with browsers using fonts with confusable letters. |
1072
|
|
|
// Removed: o,O,0,1,l,L |
1073
|
|
|
$consonants = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z']; |
1074
|
|
|
$vowels = ['a', 'e', 'i', 'u']; |
1075
|
|
|
$newPassword = ''; |
1076
|
|
|
$skipped = false; |
1077
|
|
|
|
1078
|
|
|
while (strlen($newPassword) < $minimumLength) { |
1079
|
|
|
if (Utils::createRandomNumber(0, 1)) { |
1080
|
|
|
$caseFunc = 'strtoupper'; |
1081
|
|
|
} else { |
1082
|
|
|
$caseFunc = 'strtolower'; |
1083
|
|
|
} |
1084
|
|
|
|
1085
|
|
|
switch (Utils::createRandomNumber(0, $skipped ? 3 : ($allowUnderscore ? 5 : 4))) { |
1086
|
|
|
case 0 : case 1 : $nextChar = $caseFunc($consonants[rand(0, 18)]); |
1087
|
|
|
break; |
1088
|
|
|
case 2: |
1089
|
|
|
case 3: |
1090
|
|
|
$nextChar = $caseFunc($vowels[rand(0, 3)]); |
1091
|
|
|
break; |
1092
|
|
|
case 4: |
1093
|
|
|
$nextChar = rand(2, 9); // No 0 to avoid confusion with O, same for 1 and l. |
1094
|
|
|
break; |
1095
|
|
|
case 5: |
1096
|
|
|
$newPassword .= '_'; |
1097
|
|
|
continue 2; |
1098
|
|
|
break; |
|
|
|
|
1099
|
|
|
} |
1100
|
|
|
|
1101
|
|
|
$skipped = false; |
1102
|
|
|
|
1103
|
|
|
// Ensure letters and numbers only occur once. |
1104
|
|
|
if (strpos($newPassword, $nextChar) === false) { |
1105
|
|
|
$newPassword .= $nextChar; |
|
|
|
|
1106
|
|
|
} else { |
1107
|
|
|
$skipped = true; |
1108
|
|
|
} |
1109
|
|
|
} |
1110
|
|
|
|
1111
|
|
|
return $newPassword; |
1112
|
|
|
} |
1113
|
|
|
|
1114
|
|
|
/** |
1115
|
|
|
* Sends mail to the current user. |
1116
|
|
|
* |
1117
|
|
|
* @param string $subject |
1118
|
|
|
* @param string $message |
1119
|
|
|
* @return bool |
1120
|
|
|
*/ |
1121
|
|
|
public function mailUser($subject, $message) |
1122
|
|
|
{ |
1123
|
|
|
$mail = new Mail($this->config); |
1124
|
|
|
$mail->addTo($this->getUserData('email')); |
1125
|
|
|
$mail->subject = $subject; |
1126
|
|
|
$mail->message = $message; |
1127
|
|
|
$result = $mail->send(); |
1128
|
|
|
unset($mail); |
1129
|
|
|
|
1130
|
|
|
return $result; |
1131
|
|
|
} |
1132
|
|
|
|
1133
|
|
|
/** |
1134
|
|
|
* Returns true on success. |
1135
|
|
|
* |
1136
|
|
|
* This will change a users status to active, and send an email with a new password. |
1137
|
|
|
* |
1138
|
|
|
* @return bool |
1139
|
|
|
*/ |
1140
|
|
|
public function activateUser() |
1141
|
|
|
{ |
1142
|
|
|
if ($this->getStatus() == 'blocked') { |
1143
|
|
|
|
1144
|
|
|
// Generate and change user password. |
1145
|
|
|
$newPassword = $this->createPassword(); |
1146
|
|
|
$this->changePassword($newPassword); |
1147
|
|
|
// Send activation email. |
1148
|
|
|
$subject = '[%sitename%] Login name / activation'; |
1149
|
|
|
$message = sprintf( |
1150
|
|
|
"\nName: %s\nLogin name: %s\nNew password: %s\n\n", |
1151
|
|
|
$this->getUserData('display_name'), |
1152
|
|
|
$this->getLogin(), |
1153
|
|
|
$newPassword |
1154
|
|
|
); |
1155
|
|
|
// Only set to active if the activation mail sent correctly. |
1156
|
|
|
if ($this->mailUser($subject, $message)) { |
1157
|
|
|
return $this->setStatus('active'); |
1158
|
|
|
} |
1159
|
|
|
return true; |
1160
|
|
|
} |
1161
|
|
|
|
1162
|
|
|
return false; |
1163
|
|
|
} |
1164
|
|
|
|
1165
|
|
|
/** |
1166
|
|
|
* Returns true, if a user is a super admin. |
1167
|
|
|
* @return bool |
1168
|
|
|
*/ |
1169
|
|
|
public function isSuperAdmin() |
1170
|
|
|
{ |
1171
|
|
|
return $this->isSuperAdmin; |
1172
|
|
|
} |
1173
|
|
|
|
1174
|
|
|
/** |
1175
|
|
|
* Sets the users "is_superadmin" flag and updates the database entry. |
1176
|
|
|
* @param $isSuperAdmin |
1177
|
|
|
* @return bool |
1178
|
|
|
*/ |
1179
|
|
|
public function setSuperAdmin($isSuperAdmin) |
1180
|
|
|
{ |
1181
|
|
|
$this->isSuperAdmin = $isSuperAdmin; |
1182
|
|
|
$update = sprintf(" |
1183
|
|
|
UPDATE |
1184
|
|
|
%sfaquser |
1185
|
|
|
SET |
1186
|
|
|
is_superadmin = %d |
1187
|
|
|
WHERE |
1188
|
|
|
user_id = %d", |
1189
|
|
|
Db::getTablePrefix(), |
1190
|
|
|
(int)$this->isSuperAdmin, |
1191
|
|
|
$this->userId |
1192
|
|
|
); |
1193
|
|
|
|
1194
|
|
|
$res = $this->config->getDb()->query($update); |
1195
|
|
|
|
1196
|
|
|
if ($res) { |
1197
|
|
|
return true; |
1198
|
|
|
} |
1199
|
|
|
|
1200
|
|
|
return false; |
1201
|
|
|
} |
1202
|
|
|
} |
1203
|
|
|
|
This check looks at variables that 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.