Completed
Push — master ( d88b49...82b4a5 )
by
unknown
02:25
created

modUsers::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
require_once('MODx.php');
3
4
/**
5
 * Class modUsers
6
 */
7
class modUsers extends MODxAPI
8
{
9
    /**
10
     * @var array
11
     */
12
    protected $default_field = array(
13
        'user'      => array(
14
            'username' => '',
15
            'password' => '',
16
            'cachepwd' => ''
17
        ),
18
        'attribute' => array(
19
            'fullname'         => '',
20
            'role'             => '',
21
            'email'            => '',
22
            'phone'            => '',
23
            'mobilephone'      => '',
24
            'blocked'          => 0,
25
            'blockeduntil'     => 0,
26
            'blockedafter'     => 0,
27
            'logincount'       => 0,
28
            'lastlogin'        => 0,
29
            'thislogin'        => 0,
30
            'failedlogincount' => 0,
31
            'sessionid'        => '',
32
            'dob'              => 0,
33
            'gender'           => 0,
34
            'country'          => '',
35
            'state'            => '',
36
            'city'             => '',
37
            'street'           => '',
38
            'zip'              => '',
39
            'fax'              => '',
40
            'photo'            => '',
41
            'comment'          => '',
42
            'createdon'        => 0,
43
            'editedon'         => 0
44
        ),
45
        'hidden'    => array(
46
            'internalKey'
47
        )
48
    );
49
50
    /**
51
     * @var string
52
     */
53
    protected $givenPassword = '';
54
    protected $groupIds = array();
55
56
    /**
57
     * @param $key
58
     * @return bool
59
     */
60
    public function issetField($key)
61
    {
62
        return (array_key_exists($key, $this->default_field['user']) || array_key_exists($key,
63
                $this->default_field['attribute']) || in_array($key, $this->default_field['hidden']));
64
    }
65
66
    /**
67
     * @param string $data
68
     * @return string|false
69
     */
70
    protected function findUser($data)
71
    {
72
        switch (true) {
73
            case (is_int($data) || ((int)$data > 0 && (string)intval($data) === $data)):
74
                $find = 'attribute.internalKey';
75
                break;
76
            case filter_var($data, FILTER_VALIDATE_EMAIL):
77
                $find = 'attribute.email';
78
                break;
79
            case is_scalar($data):
80
                $find = 'user.username';
81
                break;
82
            default:
83
                $find = false;
84
        }
85
86
        return $find;
87
    }
88
89
    /**
90
     * @param array $data
91
     * @return $this
92
     */
93
    public function create($data = array())
94
    {
95
        parent::create($data);
96
        $this->set('createdon', time());
97
98
        return $this;
99
    }
100
101
    /**
102
     * @param $id
103
     * @return $this
104
     */
105
    public function edit($id)
106
    {
107
        $id = is_scalar($id) ? trim($id) : '';
108
        if ($this->getID() != $id) {
109
            $this->close();
110
            $this->newDoc = false;
111
112
            if (!$find = $this->findUser($id)) {
113
                $this->id = null;
114
            } else {
115
                $this->set('editedon', time());
116
                $result = $this->query("
117
                    SELECT * from {$this->makeTable('web_user_attributes')} as attribute
118
                    LEFT JOIN {$this->makeTable('web_users')} as user ON user.id=attribute.internalKey
119
                    WHERE BINARY {$find}='{$this->escape($id)}'
120
                ");
121
                $this->field = $this->modx->db->getRow($result);
122
123
                $this->id = empty($this->field['internalKey']) ? null : $this->get('internalKey');
124
                $this->store($this->toArray());
125
                unset($this->field['id']);
126
                unset($this->field['internalKey']);
127
            }
128
        }
129
130
        return $this;
131
    }
132
133
    /**
134
     * @param string $key
135
     * @param $value
136
     * @return $this
137
     */
138
    public function set($key, $value)
139
    {
140
        if (is_scalar($value) && is_scalar($key) && !empty($key)) {
141
            switch ($key) {
142
                case 'password':
143
                    $this->givenPassword = $value;
144
                    $value = $this->getPassword($value);
145
                    break;
146
                case 'sessionid':
147
                    session_regenerate_id(false);
148
                    $value = session_id();
149
                    break;
150
                case 'editedon':
151
                case 'createdon':
152
                    $value = $this->getTime($value);
153
                    break;
154
            }
155
            $this->field[$key] = $value;
156
        }
157
158
        return $this;
159
    }
160
161
    /**
162
     * @param $pass
163
     * @return string
164
     */
165
    public function getPassword($pass)
166
    {
167
        return md5($pass);
168
    }
169
170
    /**
171
     * @param bool $fire_events
172
     * @param bool $clearCache
173
     * @return bool|int|null|void
174
     */
175
    public function save($fire_events = false, $clearCache = false)
176
    {
177
        if ($this->get('email') == '' || $this->get('username') == '' || $this->get('password') == '') {
178
            $this->log['EmptyPKField'] = 'Email, username or password is empty <pre>' . print_r($this->toArray(),
179
                    true) . '</pre>';
180
181
            return false;
182
        }
183
184
        if (!$this->checkUnique('web_users', 'username')) {
185
            $this->log['UniqueUsername'] = 'username not unique <pre>' . print_r($this->get('username'),
186
                    true) . '</pre>';
187
188
            return false;
189
        }
190
191
        if (!$this->checkUnique('web_user_attributes', 'email', 'internalKey')) {
192
            $this->log['UniqueEmail'] = 'Email not unique <pre>' . print_r($this->get('email'), true) . '</pre>';
193
194
            return false;
195
        }
196
        $time = 
0 ignored issues
show
Unused Code introduced by
$time is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
197
        $this->set('sessionid', '');
198
        $fld = $this->toArray();
199
        foreach ($this->default_field['user'] as $key => $value) {
200
            $tmp = $this->get($key);
201
            if ($this->newDoc && (!is_int($tmp) && $tmp == '')) {
202
                $this->field[$key] = $value;
203
            }
204
            $this->Uset($key, 'user');
205
            unset($fld[$key]);
206
        }
207
        if (!empty($this->set['user'])) {
208
            if ($this->newDoc) {
209
                $SQL = "INSERT into {$this->makeTable('web_users')} SET " . implode(', ', $this->set['user']);
210
            } else {
211
                $SQL = "UPDATE {$this->makeTable('web_users')} SET " . implode(', ',
212
                        $this->set['user']) . " WHERE id = " . $this->id;
213
            }
214
            $this->query($SQL);
215
        }
216
217
        if ($this->newDoc) {
218
            $this->id = $this->modx->db->getInsertId();
219
        }
220
221
        foreach ($this->default_field['attribute'] as $key => $value) {
222
            $tmp = $this->get($key);
223
            if ($this->newDoc && (!is_int($tmp) && $tmp == '')) {
224
                $this->field[$key] = $value;
225
            }
226
            $this->Uset($key, 'attribute');
227
            unset($fld[$key]);
228
        }
229
        if (!empty($this->set['attribute'])) {
230
            if ($this->newDoc) {
231
                $this->set('internalKey', $this->id)->Uset('internalKey', 'attribute');
232
                $SQL = "INSERT into {$this->makeTable('web_user_attributes')} SET " . implode(', ',
233
                        $this->set['attribute']);
234
            } else {
235
                $SQL = "UPDATE {$this->makeTable('web_user_attributes')} SET " . implode(', ',
236
                        $this->set['attribute']) . " WHERE  internalKey = " . $this->getID();
237
            }
238
            $this->query($SQL);
239
        }
240
        unset($fld['id']);
241
        foreach ($fld as $key => $value) {
242
            if ($value == '' || !$this->isChanged($key)) {
243
                continue;
244
            }
245
            $result = $this->query("SELECT `setting_value` FROM {$this->makeTable('web_user_settings')} WHERE `webuser` = '{$this->id}' AND `setting_name` = '{$key}'");
246
            if ($this->modx->db->getRecordCount($result) > 0) {
247
                $this->query("UPDATE {$this->makeTable('web_user_settings')} SET `setting_value` = '{$value}' WHERE `webuser` = '{$this->id}' AND `setting_name` = '{$key}';");
248
            } else {
249
                $this->query("INSERT into {$this->makeTable('web_user_settings')} SET `webuser` = {$this->id},`setting_name` = '{$key}',`setting_value` = '{$value}';");
250
            }
251
        }
252
        if (!$this->newDoc && $this->givenPassword) {
253
            $this->invokeEvent('OnWebChangePassword', array(
254
                'userObj'      => $this,
255
                'userid'       => $this->id,
256
                'user'         => $this->toArray(),
257
                'userpassword' => $this->givenPassword,
258
                'internalKey'  => $this->id,
259
                'username'     => $this->get('username')
260
            ), $fire_events);
261
        }
262
        
263
        if ($this->groupIds) $this->setUserGroups($this->id, $this->groupIds);
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->groupIds of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
264
        
265
        $this->invokeEvent('OnWebSaveUser', array(
266
            'userObj' => $this,
267
            'mode'    => $this->newDoc ? "new" : "upd",
268
            'id'      => $this->id,
269
            'user'    => $this->toArray()
270
        ), $fire_events);
271
272
        if ($clearCache) {
273
            $this->clearCache($fire_events);
274
        }
275
276
        return $this->id;
277
    }
278
279
    /**
280
     * @param $ids
281
     * @param bool $fire_events
282
     * @return bool|null|void
283
     */
284
    public function delete($ids, $fire_events = false)
285
    {
286
        if ($this->edit($ids)) {
287
            $flag = $this->query("
288
          DELETE user,attribute FROM {$this->makeTable('web_user_attributes')} as attribute
289
            LEFT JOIN {$this->makeTable('web_users')} as user ON user.id=attribute.internalKey
290
            WHERE attribute.internalKey='{$this->escape($this->getID())}'");
291
            $this->query("DELETE FROM {$this->makeTable('web_user_settings')} WHERE webuser='{$this->getID()}'");
292
            $this->query("DELETE FROM {$this->makeTable('web_groups')} WHERE webuser='{$this->getID()}'");
293
            $this->invokeEvent('OnWebDeleteUser', array(
294
                'userObj'     => $this,
295
                'userid'      => $this->getID(),
296
                'internalKey' => $this->getID(),
297
                'username'    => $this->get('username'),
298
                'timestamp'   => time()
299
            ), $fire_events);
300
        } else {
301
            $flag = false;
302
        }
303
        $this->close();
304
305
        return $flag;
306
    }
307
308
    /**
309
     * @param int $id
310
     * @param bool $fulltime
311
     * @param string $cookieName
312
     * @param bool $fire_events
313
     * @return bool
314
     */
315
    public function authUser($id = 0, $fulltime = true, $cookieName = 'WebLoginPE', $fire_events = false)
316
    {
317
        $flag = false;
318
        if (null === $this->getID() && $id) {
319
            $this->edit($id);
320
        }
321
        if (null !== $this->getID()) {
322
            $flag = true;
323
            $this->save(false);
324
            $this->SessionHandler('start', $cookieName, $fulltime);
325
            $this->invokeEvent("OnWebLogin", array(
326
                'userObj'      => $this,
327
                'userid'       => $this->getID(),
328
                'username'     => $this->get('username'),
329
                'userpassword' => $this->givenPassword,
330
                'rememberme'   => $fulltime
331
            ), $fire_events);
332
        }
333
334
        return $flag;
335
    }
336
337
    /**
338
     * @param int $id
339
     * @return bool
340
     */
341
    public function checkBlock($id = 0)
342
    {
343
        $tmp = clone $this;
344
        if ($id && $tmp->getID() != $id) {
345
            $tmp->edit($id);
346
        }
347
        $now = time();
348
349
        $b = $tmp->get('blocked');
350
        $bu = $tmp->get('blockeduntil');
351
        $ba = $tmp->get('blockedafter');
352
        $flag = (($b && !$bu && !$ba) || ($bu && $now < $bu) || ($ba && $now > $ba));
353
        unset($tmp);
354
355
        return $flag;
356
    }
357
358
    /**
359
     * @param $id
360
     * @param $password
361
     * @param $blocker
362
     * @param bool $fire_events
363
     * @return bool
364
     */
365
    public function testAuth($id, $password, $blocker, $fire_events = false)
366
    {
367
        $tmp = clone $this;
368
        if ($id && $tmp->getID() != $id) {
369
            $tmp->edit($id);
370
        }
371
372
        $flag = $pluginFlag = false;
373
        if (
374
            (null !== $tmp->getID()) && (!$blocker || ($blocker && !$tmp->checkBlock($id)))
375
        ) {
376
            $eventResult = $this->getInvokeEventResult('OnWebAuthentication', array(
377
                'userObj'       => $this,
378
                'userid'        => $tmp->getID(),
379
                'username'      => $tmp->get('username'),
380
                'userpassword'  => $password,
381
                'savedpassword' => $tmp->get('password')
382
            ), $fire_events);
383
            if (is_array($eventResult)) {
384
                foreach ($eventResult as $result) {
385
                    $pluginFlag = (bool)$result;
386
                }
387
            } else {
388
                $pluginFlag = (bool)$eventResult;
389
            }
390
            if (!$pluginFlag) {
391
                $flag = ($tmp->get('password') == $tmp->getPassword($password));
392
            }
393
        }
394
        unset($tmp);
395
396
        return $flag || $pluginFlag;
397
    }
398
399
    /**
400
     * @param bool $fulltime
401
     * @param string $cookieName
402
     * @return bool
403
     */
404
    public function AutoLogin($fulltime = true, $cookieName = 'WebLoginPE', $fire_events = null)
405
    {
406
        $flag = false;
407
        if (isset($_COOKIE[$cookieName])) {
408
            $cookie = explode('|', $_COOKIE[$cookieName], 3);
409
            if (isset($cookie[0], $cookie[1], $cookie[2]) && strlen($cookie[0]) == 32 && strlen($cookie[1]) == 32) {
410
                $this->close();
411
                $q = $this->modx->db->query("SELECT id FROM " . $this->makeTable('web_users') . " WHERE md5(username)='{$this->escape($cookie[0])}'");
412
                $id = $this->modx->db->getValue($q);
413
                if (
414
                    $this->edit($id) 
415
                    && null !== $this->getID() 
416
                    && $this->get('password') == $cookie[1] 
417
                    && $this->get('sessionid') == $cookie[2] 
418
                    && !$this->checkBlock($this->getID())
419
                ) {
420
                    $flag = $this->authUser($this->getID(), $fulltime, $cookieName, $fire_events);
421
422
                }
423
            }
424
        }
425
426
        return $flag;
427
    }
428
429
    /**
430
     * @param string $cookieName
431
     * @param null $fire_events
432
     */
433
    public function logOut($cookieName = 'WebLoginPE', $fire_events = null)
434
    {
435
        if (!$uid = $this->modx->getLoginUserID('web')) {
436
            return;
437
        }
438
        $params = array(
439
            'username'    => $_SESSION['webShortname'],
440
            'internalKey' => $uid,
441
            'userid'      => $uid // Bugfix by TS
442
        );
443
        $this->invokeEvent('OnBeforeWebLogout', $params, $fire_events);
0 ignored issues
show
Documentation introduced by
$fire_events is of type null, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
444
        $this->SessionHandler('destroy', $cookieName ? $cookieName : 'WebLoginPE');
445
        $this->invokeEvent('OnWebLogout', $params, $fire_events);
0 ignored issues
show
Documentation introduced by
$fire_events is of type null, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
446
    }
447
448
    /**
449
     * SessionHandler
450
     * Starts the user session on login success. Destroys session on error or logout.
451
     *
452
     * @param string $directive ('start' or 'destroy')
453
     * @param string $cookieName
454
     * @return modUsers
455
     * @author Raymond Irving
456
     * @author Scotty Delicious
457
     *
458
     * remeber может быть числом в секундах
459
     */
460
    protected function SessionHandler($directive, $cookieName, $remember = true)
461
    {
462
        switch ($directive) {
463
            case 'start':
464
                if ($this->getID()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getID() of type null|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
465
                    $_SESSION['webShortname'] = $this->get('username');
466
                    $_SESSION['webFullname'] = $this->get('fullname');
467
                    $_SESSION['webEmail'] = $this->get('email');
468
                    $_SESSION['webValidated'] = 1;
469
                    $_SESSION['webInternalKey'] = $this->getID();
470
                    $_SESSION['webValid'] = base64_encode($this->get('password'));
471
                    $_SESSION['webUser'] = base64_encode($this->get('username'));
472
                    $_SESSION['webFailedlogins'] = $this->get('failedlogincount');
473
                    $_SESSION['webLastlogin'] = $this->get('lastlogin');
474
                    $_SESSION['webnrlogins'] = $this->get('logincount');
475
                    $_SESSION['webUsrConfigSet'] = array();
476
                    $_SESSION['webUserGroupNames'] = $this->getUserGroups();
477
                    $_SESSION['webDocgroups'] = $this->getDocumentGroups();
478
                    if ($remember) {
479
                        $this->setAutoLoginCookie($cookieName, $remember);
480
                    }
481
                }
482
                break;
483
            case 'destroy':
484
                if (isset($_SESSION['mgrValidated'])) {
485
                    unset($_SESSION['webShortname']);
486
                    unset($_SESSION['webFullname']);
487
                    unset($_SESSION['webEmail']);
488
                    unset($_SESSION['webValidated']);
489
                    unset($_SESSION['webInternalKey']);
490
                    unset($_SESSION['webValid']);
491
                    unset($_SESSION['webUser']);
492
                    unset($_SESSION['webFailedlogins']);
493
                    unset($_SESSION['webLastlogin']);
494
                    unset($_SESSION['webnrlogins']);
495
                    unset($_SESSION['webUsrConfigSet']);
496
                    unset($_SESSION['webUserGroupNames']);
497
                    unset($_SESSION['webDocgroups']);
498
499
                    setcookie($cookieName, '', time() - 60, '/');
500
                } else {
501
                    if (isset($_COOKIE[session_name()])) {
502
                        setcookie(session_name(), '', time() - 60, '/');
503
                    }
504
                    setcookie($cookieName, '', time() - 60, '/');
505
                    session_destroy();
506
                }
507
                break;
508
        }
509
510
        return $this;
511
    }
512
513
    /**
514
     * @return bool
515
     */
516
    public function isSecure()
517
    {
518
        $out = $this->modxConfig('server_protocol') == 'http' ? false : true;
519
520
        return $out;
521
    }
522
523
    /**
524
     * @param $cookieName
525
     * @param bool $remember
526
     * @return $this
527
     */
528
    public function setAutoLoginCookie($cookieName, $remember = true)
529
    {
530
        if (!empty($cookieName) && $this->getID()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getID() of type null|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
531
            $secure = $this->isSecure();
532
            $remember = is_bool($remember) ? (60 * 60 * 24 * 365 * 5) : (int)$remember;
533
            $cookieValue = array(md5($this->get('username')), $this->get('password'), $this->get('sessionid'), $remember);
534
            $cookieValue = implode('|', $cookieValue);
535
            $cookieExpires = time() + $remember;
536
            setcookie($cookieName, $cookieValue, $cookieExpires, '/', '', $secure, true);
537
        }
538
539
        return $this;
540
    }
541
542
    /**
543
     * @param int $userID
544
     * @return array
545
     */
546
    public function getDocumentGroups($userID = 0)
547
    {
548
        $out = array();
549
        $user = $this->switchObject($userID);
550
        if (null !== $user->getID()) {
551
            $web_groups = $this->modx->getFullTableName('web_groups');
552
            $webgroup_access = $this->modx->getFullTableName('webgroup_access');
553
554
            $sql = "SELECT `uga`.`documentgroup` FROM {$web_groups} as `ug`
555
                INNER JOIN {$webgroup_access} as `uga` ON `uga`.`webgroup`=`ug`.`webgroup`
556
                WHERE `ug`.`webuser` = " . $user->getID();
557
            $out = $this->modx->db->getColumn('documentgroup', $this->query($sql));
558
559
        }
560
        unset($user);
561
562
        return $out;
563
    }
564
565
    /**
566
     * @param int $userID
567
     * @return array
568
     */
569
    public function getUserGroups($userID = 0)
570
    {
571
        $out = array();
572
        $user = $this->switchObject($userID);
573
        if (null !== $user->getID()) {
574
            $web_groups = $this->makeTable('web_groups');
575
            $webgroup_names = $this->makeTable('webgroup_names');
576
577
            $rs = $this->query("SELECT `ug`.`webgroup`, `ugn`.`name` FROM {$web_groups} as `ug`
578
                INNER JOIN {$webgroup_names} as `ugn` ON `ugn`.`id`=`ug`.`webgroup`
579
                WHERE `ug`.`webuser` = " . $user->getID());
580
            while ($row = $this->modx->db->getRow($rs)) {
581
                $out[$row['webgroup']] = $row['name'];
582
            }
583
        }
584
        unset($user);
585
586
        return $out;
587
    }
588
589
    /**
590
     * @param int $userID
591
     * @param array $groupIds
592
     * @return $this
593
     */
594
    public function setUserGroups($userID = 0, $groupIds = array())
595
    {
596
        if (!is_array($groupIds)) return $this;
597
        if ($this->newDoc && $userID == 0) {
598
            $this->groupIds = $groupIds;
599
        } else {
600
            $user = $this->switchObject($userID);
601
            if ($uid = $user->getID()) {
602
                foreach ($groupIds as $gid) {
603
                    $this->query("REPLACE INTO {$this->makeTable('web_groups')} (`webgroup`, `webuser`) VALUES ('{$gid}', '{$uid}')");
604
                }
605
                if (!$this->newDoc) {
606
                    $groupIds = empty($groupIds) ? '0' : implode(',', $groupIds);
607
                    $this->query("DELETE FROM {$this->makeTable('web_groups')} WHERE `webuser`={$uid} AND `webgroup` NOT IN ({$groupIds})");
608
                }
609
            }
610
            unset($user);
611
            $this->groupIds = array();
612
        }
613
614
        return $this;
615
    }
616
}
617