Completed
Push — master ( d60430...deff22 )
by
unknown
02:12
created

modManagers::set()   D

Complexity

Conditions 9
Paths 7

Size

Total Lines 27
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 21
nc 7
nop 2
dl 0
loc 27
rs 4.909
c 0
b 0
f 0
1
<?php
2
require_once('MODx.php');
3
4
/**
5
 * Class modUsers
6
 */
7
class modManagers extends MODxAPI
8
{
9
    /**
10
     * @var array
11
     */
12
    protected $default_field = array(
13
        'user'      => array(
14
            'username' => '',
15
            'password' => '',
16
        ),
17
        'attribute' => array(
18
            'fullname'         => '',
19
            'role'             => 0,
20
            'email'            => '',
21
            'phone'            => '',
22
            'mobilephone'      => '',
23
            'blocked'          => 0,
24
            'blockeduntil'     => 0,
25
            'blockedafter'     => 0,
26
            'logincount'       => 0,
27
            'lastlogin'        => 0,
28
            'thislogin'        => 0,
29
            'failedlogincount' => 0,
30
            'sessionid'        => '',
31
            'dob'              => 0,
32
            'gender'           => 0,
33
            'country'          => '',
34
            'state'            => '',
35
            'city'             => '',
36
            'street'           => '',
37
            'zip'              => '',
38
            'fax'              => '',
39
            'photo'            => '',
40
            'comment'          => '',
41
            'createdon'        => 0,
42
            'editedon'         => 0
43
        ),
44
        'hidden'    => array(
45
            'internalKey'
46
        )
47
    );
48
49
    /**
50
     * @var string
51
     */
52
    protected $givenPassword = '';
53
    protected $groupIds = array();
54
    protected $mgrPermissions = array();
55
56
    /**
57
     * MODxAPI constructor.
58
     * @param DocumentParser $modx
59
     * @param bool $debug
60
     * @throws Exception
61
     */
62
    public function __construct(DocumentParser $modx, $debug = false)
63
    {
64
        parent::__construct($modx, $debug);
65
        $this->modx->loadExtension('phpass');
66
    }
67
68
69
    /**
70
     * @param $key
71
     * @return bool
72
     */
73
    public function issetField($key)
74
    {
75
        return (array_key_exists($key, $this->default_field['user']) || array_key_exists($key,
76
                $this->default_field['attribute']) || in_array($key, $this->default_field['hidden']));
77
    }
78
79
    /**
80
     * @param string $data
81
     * @return string|false
82
     */
83
    protected function findUser($data)
84
    {
85
        switch (true) {
86
            case (is_int($data) || ((int)$data > 0 && (string)intval($data) === $data)):
87
                $find = 'attribute.internalKey';
88
                break;
89
            case filter_var($data, FILTER_VALIDATE_EMAIL):
90
                $find = 'attribute.email';
91
                break;
92
            case is_scalar($data):
93
                $find = 'user.username';
94
                break;
95
            default:
96
                $find = false;
97
        }
98
99
        return $find;
100
    }
101
102
    /**
103
     * @param array $data
104
     * @return $this
105
     */
106
    public function create($data = array())
107
    {
108
        parent::create($data);
109
        $this->set('createdon', time());
110
111
        return $this;
112
    }
113
114
    /**
115
     * @param $id
116
     * @return $this
117
     */
118
    public function edit($id)
119
    {
120
        $id = is_scalar($id) ? trim($id) : '';
121
        if ($this->getID() != $id) {
122
            $this->close();
123
            $this->newDoc = false;
124
125
            if (!$find = $this->findUser($id)) {
126
                $this->id = null;
127
            } else {
128
                $this->set('editedon', time());
129
                $result = $this->query("
130
                    SELECT * from {$this->makeTable('user_attributes')} as attribute
131
                    LEFT JOIN {$this->makeTable('manager_users')} as user ON user.id=attribute.internalKey
132
                    WHERE BINARY {$find}='{$this->escape($id)}'
133
                ");
134
                $this->field = $this->modx->db->getRow($result);
135
136
                $this->id = empty($this->field['internalKey']) ? null : $this->get('internalKey');
137
                $this->store($this->toArray());
138
                $result = $this->query("SELECT * FROM {$this->makeTable('user_roles')} WHERE `id`={$this->get('role')}");
139
                $permissions = $this->modx->db->getRow($result);
140
                unset($permissions['id'], $permissions['name'], $permissions['description']);
141
                $this->mgrPermissions = $permissions;
142
                unset($this->field['id']);
143
                unset($this->field['internalKey']);
144
            }
145
        }
146
147
        return $this;
148
    }
149
150
    /**
151
     * @param string $key
152
     * @param $value
153
     * @return $this
154
     */
155
    public function set($key, $value)
156
    {
157
        if (is_scalar($value) && is_scalar($key) && !empty($key)) {
158
            switch ($key) {
159
                case 'password':
160
                    $this->givenPassword = $value;
161
                    $value = $this->getPassword($value);
162
                    break;
163
                case 'sessionid':
164
                    session_regenerate_id(false);
165
                    $value = session_id();
166
                    if ($mid = $this->modx->getLoginUserID('mgr')) {
167
                        $this->modx->db->query("UPDATE {$this->makeTable('active_user_locks')} SET `sid`='{$value}' WHERE `internalKey`={$mid}");
168
                        $this->modx->db->query("UPDATE {$this->makeTable('active_user_sessions')} SET `sid`='{$value}' WHERE `internalKey`={$mid}");
169
                        $this->modx->db->query("UPDATE {$this->makeTable('active_users')} SET `sid`='{$value}' WHERE `internalKey`={$mid}");
170
                    }
171
                    break;
172
                case 'editedon':
173
                case 'createdon':
174
                    $value = $this->getTime($value);
175
                    break;
176
            }
177
            $this->field[$key] = $value;
178
        }
179
180
        return $this;
181
    }
182
183
    /**
184
     * @param $pass
185
     * @return string
186
     */
187
    public function getPassword($pass)
188
    {
189
        return $this->modx->phpass->HashPassword($pass);
190
    }
191
192
    /**
193
     * @param string $name
194
     * @return bool
195
     */
196
    public function hasPermission($name)
197
    {
198
        return (is_string($name) && $name && isset($this->mgrPermissions[$name]));
199
    }
200
201
    /**
202
     * @param bool $fire_events
203
     * @param bool $clearCache
204
     * @return bool|int|null|void
205
     */
206
    public function save($fire_events = false, $clearCache = false)
207
    {
208
        if ($this->get('email') == '' || $this->get('username') == '' || $this->get('password') == '') {
209
            $this->log['EmptyPKField'] = 'Email, username or password is empty <pre>' . print_r($this->toArray(),
210
                    true) . '</pre>';
211
212
            return false;
213
        }
214
215
        if (!$this->checkUnique('manager_users', 'username')) {
216
            $this->log['UniqueUsername'] = 'username not unique <pre>' . print_r($this->get('username'),
217
                    true) . '</pre>';
218
219
            return false;
220
        }
221
222
        if (!$this->checkUnique('user_attributes', 'email', 'internalKey')) {
223
            $this->log['UniqueEmail'] = 'Email not unique <pre>' . print_r($this->get('email'), true) . '</pre>';
224
225
            return false;
226
        }
227
228
        if(!$this->get('role')) {
229
            $this->log['UniqueEmail'] = 'Wrong manager role <pre>' . print_r($this->get('role'), true) . '</pre>';
230
        }
231
        
232
        $this->set('sessionid', '');
233
        $fld = $this->toArray();
234
        foreach ($this->default_field['user'] as $key => $value) {
235
            $tmp = $this->get($key);
236
            if ($this->newDoc && (!is_int($tmp) && $tmp == '')) {
237
                $this->field[$key] = $value;
238
            }
239
            $this->Uset($key, 'user');
240
            unset($fld[$key]);
241
        }
242
        if (!empty($this->set['user'])) {
243
            if ($this->newDoc) {
244
                $SQL = "INSERT into {$this->makeTable('manager_users')} SET " . implode(', ', $this->set['user']);
245
            } else {
246
                $SQL = "UPDATE {$this->makeTable('manager_users')} SET " . implode(', ',
247
                        $this->set['user']) . " WHERE id = " . $this->id;
248
            }
249
            $this->query($SQL);
250
        }
251
252
        if ($this->newDoc) {
253
            $this->id = $this->modx->db->getInsertId();
254
        }
255
256
        foreach ($this->default_field['attribute'] as $key => $value) {
257
            $tmp = $this->get($key);
258
            if ($this->newDoc && (!is_int($tmp) && $tmp == '')) {
259
                $this->field[$key] = $value;
260
            }
261
            $this->Uset($key, 'attribute');
262
            unset($fld[$key]);
263
        }
264
        if (!empty($this->set['attribute'])) {
265
            if ($this->newDoc) {
266
                $this->set('internalKey', $this->id)->Uset('internalKey', 'attribute');
267
                $SQL = "INSERT into {$this->makeTable('user_attributes')} SET " . implode(', ',
268
                        $this->set['attribute']);
269
            } else {
270
                $SQL = "UPDATE {$this->makeTable('user_attributes')} SET " . implode(', ',
271
                        $this->set['attribute']) . " WHERE  internalKey = " . $this->getID();
272
            }
273
            $this->query($SQL);
274
        }
275
        unset($fld['id']);
276
        foreach ($fld as $key => $value) {
277
            if ($value == '' || !$this->isChanged($key)) {
278
                continue;
279
            }
280
            $result = $this->query("SELECT `setting_value` FROM {$this->makeTable('user_settings')} WHERE `user` = '{$this->id}' AND `setting_name` = '{$key}'");
281
            if ($this->modx->db->getRecordCount($result) > 0) {
282
                $this->query("UPDATE {$this->makeTable('user_settings')} SET `setting_value` = '{$value}' WHERE `user` = '{$this->id}' AND `setting_name` = '{$key}';");
283
            } else {
284
                $this->query("INSERT into {$this->makeTable('user_settings')} SET `user` = {$this->id},`setting_name` = '{$key}',`setting_value` = '{$value}';");
285
            }
286
        }
287
        // TODO
288
        if (!$this->newDoc && $this->givenPassword) {
289
            $this->invokeEvent('OnManagerChangePassword', array(
290
                'userObj'      => $this,
291
                'userid'       => $this->id,
292
                'user'         => $this->toArray(),
293
                'userpassword' => $this->givenPassword,
294
                'username'     => $this->get('username')
295
            ), $fire_events);
296
        }
297
298
        if ($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...
299
            $this->setUserGroups($this->id, $this->groupIds);
300
        }
301
        // TODO
302
        $this->invokeEvent('OnManagerSaveUser', array(
303
            'userObj'      => $this,
304
            'mode'         => $this->newDoc ? "new" : "upd",
305
            'user'         => $this->toArray(),
306
            "userid"       => $this->getID(),
307
            "username"     => $this->get('username'),
308
            "userpassword" => $this->givenPassword,
309
            "useremail"    => $this->get('email'),
310
            "userfullname" => $this->get('fullname'),
311
            "userroleid"   => $this->get('role')
312
        ), $fire_events);
313
314
        if ($clearCache) {
315
            $this->clearCache($fire_events);
316
        }
317
318
        return $this->id;
319
    }
320
321
    /**
322
     * @param $ids
323
     * @param bool $fire_events
324
     * @return bool|null|void
325
     */
326
    public function delete($ids, $fire_events = false)
327
    {
328
        if ($this->edit($ids)) {
329
            $flag = $this->query("
330
          DELETE user,attribute FROM {$this->makeTable('user_attributes')} as attribute
331
            LEFT JOIN {$this->makeTable('manager_users')} as user ON user.id=attribute.internalKey
332
            WHERE attribute.internalKey='{$this->escape($this->getID())}'");
333
            $this->query("DELETE FROM {$this->makeTable('user_settings')} WHERE user='{$this->getID()}'");
334
            $this->query("DELETE FROM {$this->makeTable('member_groups')} WHERE member='{$this->getID()}'");
335
            $this->invokeEvent('OnManagerDeleteUser', array(
336
                'userObj'     => $this,
337
                'userid'      => $this->getID(),
338
                'internalKey' => $this->getID(),
339
                'username'    => $this->get('username'),
340
                'timestamp'   => time()
341
            ), $fire_events);
342
        } else {
343
            $flag = false;
344
        }
345
        $this->close();
346
347
        return $flag;
348
    }
349
350
    /**
351
     * @param int $id
352
     * @param bool $fulltime
353
     * @param string $cookieName
354
     * @param bool $fire_events
355
     * @return bool
356
     */
357
    public function authUser($id = 0, $fulltime = true, $cookieName = 'modx_remember_manager', $fire_events = false)
358
    {
359
        $flag = false;
360
        if (null === $this->getID() && $id) {
361
            $this->edit($id);
362
        }
363
        if (null !== $this->getID()) {
364
            $flag = true;
365
            $this->save(false);
366
            $this->SessionHandler('start', $cookieName, $fulltime);
367
            $this->invokeEvent("OnManagerLogin", array(
368
                'userObj'      => $this,
369
                'userid'       => $this->getID(),
370
                'username'     => $this->get('username'),
371
                'userpassword' => $this->givenPassword,
372
                'rememberme'   => $fulltime
373
            ), $fire_events);
374
        }
375
376
        return $flag;
377
    }
378
379
    /**
380
     * @param int $id
381
     * @return bool
382
     */
383
    public function checkBlock($id = 0)
384
    {
385
        $tmp = clone $this;
386
        if ($id && $tmp->getID() != $id) {
387
            $tmp->edit($id);
388
        }
389
        $now = time();
390
391
        $b = $tmp->get('blocked');
392
        $bu = $tmp->get('blockeduntil');
393
        $ba = $tmp->get('blockedafter');
394
        $flag = (($b && !$bu && !$ba) || ($bu && $now < $bu) || ($ba && $now > $ba));
395
        unset($tmp);
396
397
        return $flag;
398
    }
399
400
    /**
401
     * @param $id
402
     * @param $password
403
     * @param $blocker
404
     * @param bool $fire_events
405
     * @return bool
406
     */
407
    public function testAuth($id, $password, $blocker, $fire_events = false)
408
    {
409
        $tmp = clone $this;
410
        if ($id && $tmp->getID() != $id) {
411
            $tmp->edit($id);
412
        }
413
414
        $flag = $pluginFlag = false;
415
        if (
416
            (null !== $tmp->getID()) && (!$blocker || ($blocker && !$tmp->checkBlock($id)))
417
        ) {
418
            $_password = $tmp->get('password');
419
            $eventResult = $this->getInvokeEventResult('OnManagerAuthentication', array(
420
                'userObj'       => $this,
421
                'userid'        => $tmp->getID(),
422
                'username'      => $tmp->get('username'),
423
                'userpassword'  => $password,
424
                'savedpassword' => $_password
425
            ), $fire_events);
426
            if (is_array($eventResult)) {
427
                foreach ($eventResult as $result) {
428
                    $pluginFlag = (bool)$result;
429
                }
430
            } else {
431
                $pluginFlag = (bool)$eventResult;
432
            }
433
            if (!$pluginFlag) {
434
                $hashType = $this->getPasswordHashType($_password);
435
                switch ($hashType) {
436
                    case 'phpass':
437
                        $flag = $this->modx->phpass->CheckPassword($password, $_password);
438
                        break;
439
                    case 'md5':
440
                        $flag = $_password == md5($password);
441
                        break;
442
                    case 'v1':
443
                        $algorithm = \APIhelpers::getkey($this->modx->config, 'pwd_hash_algo', 'UNCRYPT');
444
                        $userAlgorithm = $this->getPasswordHashAlgorithm($_password);
445
                        if ($algorithm !== $userAlgorithm) {
446
                            $algorithm = $userAlgorithm;
447
                        }
448
                        $flag = $_password == $this->makeHash($password, $tmp->getID(), $algorithm);
449
                        break;
450
                }
451
                if ($flag && $hashType == 'md5' || $hashType == 'v1') {
452
                    $tmp->set('password', $password)->save();
453
                    if ($id == $this->getID()) {
454
                        $this->field['password'] = $tmp->get('password');
455
                    }
456
                }
457
            }
458
        }
459
        unset($tmp);
460
461
        return $flag || $pluginFlag;
462
    }
463
464
    /**
465
     * @param string $cookieName
466
     * @param null $fire_events
467
     */
468
    public function logOut($cookieName = 'modx_remember_manager', $fire_events = null)
469
    {
470
        if (!$uid = $this->modx->getLoginUserID('mgr')) {
471
            return;
472
        }
473
        $params = array(
474
            'username'    => $_SESSION['mgrShortname'],
475
            'internalKey' => $uid
476
        );
477
        $this->invokeEvent('OnBeforeManagerLogout', $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...
478
        $this->SessionHandler('destroy', $cookieName ? $cookieName : 'modx_remember_manager');
479
        $this->modx->db->delete($this->modx->getFullTableName('active_user_locks'), "sid = '{$this->modx->sid}'");
480
        // Clean up active_user_sessions
481
        $this->modx->db->delete($this->modx->getFullTableName('active_user_sessions'), "sid = '{$this->modx->sid}'");
482
        $this->invokeEvent('OnManagerLogout', $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...
483
    }
484
485
    /**
486
     * SessionHandler
487
     * Starts the user session on login success. Destroys session on error or logout.
488
     *
489
     * @param string $directive ('start' or 'destroy')
490
     * @param string $cookieName
491
     * @return modUsers
492
     * @author Raymond Irving
493
     * @author Scotty Delicious
494
     *
495
     * remeber может быть числом в секундах
496
     */
497
    protected function SessionHandler($directive, $cookieName, $remember = true)
498
    {
499
        switch ($directive) {
500
            case 'start':
501
                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...
502
                    $_SESSION['usertype'] = 'manager';
503
                    $_SESSION['mgrShortname'] = $this->get('username');
504
                    $_SESSION['mgrFullname'] = $this->get('fullname');
505
                    $_SESSION['mgrEmail'] = $this->get('email');
506
                    $_SESSION['mgrValidated'] = 1;
507
                    $_SESSION['mgrInternalKey'] = $this->getID();
508
                    $_SESSION['mgrFailedlogins'] = $this->get('failedlogincount');
509
                    $_SESSION['mgrLastlogin'] = $this->get('lastlogin');
510
                    $_SESSION['mgrLogincount'] = $this->get('logincount');
511
                    $_SESSION['mgrRole'] = $this->get('role');
512
                    $_SESSION['mgrPermissions'] = $this->mgrPermissions;
513
                    $_SESSION['mgrDocgroups'] = $this->getDocumentGroups();
514
                    $_SESSION['mgrToken'] = md5($this->get('sessionid'));
515
                    if ($remember) {
516
                        $this->setAutoLoginCookie($cookieName, $remember);
517
                    }
518
                }
519
                break;
520
            case 'destroy':
521
                if (isset($_SESSION['mgrValidated'])) {
522
                    unset($_SESSION['usertype']);
523
                    unset($_SESSION['mgrShortname']);
524
                    unset($_SESSION['mgrFullname']);
525
                    unset($_SESSION['mgrEmail']);
526
                    unset($_SESSION['mgrValidated']);
527
                    unset($_SESSION['mgrInternalKey']);
528
                    unset($_SESSION['mgrFailedlogins']);
529
                    unset($_SESSION['mgrLastlogin']);
530
                    unset($_SESSION['mgrLogincount']);
531
                    unset($_SESSION['mgrDocgroups']);
532
                    unset($_SESSION['mgrPermissions']);
533
                    unset($_SESSION['mgrToken']);
534
                    setcookie($cookieName, '', time() - 60, MODX_BASE_URL);
535
                } else {
536
                    if (isset($_COOKIE[session_name()])) {
537
                        setcookie(session_name(), '', time() - 60, MODX_BASE_URL);
538
                    }
539
                    setcookie($cookieName, '', time() - 60, MODX_BASE_URL);
540
                    session_destroy();
541
                }
542
                break;
543
        }
544
545
        return $this;
546
    }
547
548
    /**
549
     * @return bool
550
     */
551
    public function isSecure()
552
    {
553
        $out = $this->modxConfig('server_protocol') == 'http' ? false : true;
554
555
        return $out;
556
    }
557
558
    /**
559
     * @param $cookieName
560
     * @param bool $remember
561
     * @return $this
562
     */
563
    public function setAutoLoginCookie($cookieName, $remember = true)
564
    {
565
        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...
566
            $secure = $this->isSecure();
567
            $remember = is_bool($remember) ? (60 * 60 * 24 * 365 * 5) : (int)$remember;
568
            $cookieValue = $this->get('username');
569
            $cookieExpires = time() + $remember;
570
            setcookie($cookieName, $cookieValue, $cookieExpires, MODX_BASE_URL, '', $secure, true);
571
        }
572
573
        return $this;
574
    }
575
576
    /**
577
     * @param int $userID
578
     * @return array
579
     */
580
    public function getDocumentGroups($userID = 0)
581
    {
582
        $out = array();
583
        $user = $this->switchObject($userID);
584
        if (null !== $user->getID()) {
585
            $member_groups = $this->modx->getFullTableName('member_groups');
586
            $membergroup_access = $this->modx->getFullTableName('membergroup_access');
587
588
            $sql = "SELECT `uga`.`documentgroup` FROM {$member_groups} as `ug`
589
                INNER JOIN {$membergroup_access} as `uga` ON `uga`.`membergroup`=`ug`.`user_group` WHERE `ug`.`member` = " . $user->getID();
590
            $out = $this->modx->db->getColumn('documentgroup', $this->query($sql));
591
592
        }
593
        unset($user);
594
595
        return $out;
596
    }
597
598
    /**
599
     * @param int $userID
600
     * @return array
601
     */
602
    public function getUserGroups($userID = 0)
603
    {
604
        $out = array();
605
        $user = $this->switchObject($userID);
606
        if (null !== $user->getID()) {
607
            $member_groups = $this->makeTable('member_groups');
608
            $membergroup_names = $this->makeTable('membergroup_names');
609
610
            $rs = $this->query("SELECT `ug`.`user_group`, `ugn`.`name` FROM {$member_groups} as `ug`
611
                INNER JOIN {$membergroup_names} as `ugn` ON `ugn`.`id`=`ug`.`user_group`
612
                WHERE `ug`.`member` = " . $user->getID());
613
            while ($row = $this->modx->db->getRow($rs)) {
614
                $out[$row['user_group']] = $row['name'];
615
            }
616
        }
617
        unset($user);
618
619
        return $out;
620
    }
621
622
    /**
623
     * @param int $userID
624
     * @param array $groupIds
625
     * @return $this
626
     */
627
    public function setUserGroups($userID = 0, $groupIds = array())
628
    {
629
        if (!is_array($groupIds)) {
630
            return $this;
631
        }
632
        if ($this->newDoc && $userID == 0) {
633
            $this->groupIds = $groupIds;
634
        } else {
635
            $user = $this->switchObject($userID);
636
            if ($uid = $user->getID()) {
637
                foreach ($groupIds as $gid) {
638
                    $this->query("REPLACE INTO {$this->makeTable('member_groups')} (`user_group`, `member`) VALUES ('{$gid}', '{$uid}')");
639
                }
640
                if (!$this->newDoc) {
641
                    $groupIds = empty($groupIds) ? '0' : implode(',', $groupIds);
642
                    $this->query("DELETE FROM {$this->makeTable('member_groups')} WHERE `member`={$uid} AND `user_group` NOT IN ({$groupIds})");
643
                }
644
            }
645
            unset($user);
646
            $this->groupIds = array();
647
        }
648
649
        return $this;
650
    }
651
652
    /**
653
     * @param string $pass
654
     * @return string
655
     */
656
    public function getPasswordHashType($pass)
657
    {
658
        $out = 'unknown';
659
        if (substr($pass, 0, 1) === '$') {
660
            $out = 'phpass';
661
        } elseif (strpos($pass, '>') !== false) {
662
            $out = 'v1';
663
        } elseif (strlen($pass) === 32) {
664
            $out = 'md5';
665
        }
666
667
        return $out;
668
    }
669
670
    /**
671
     * @param string $pass
672
     * @return string
673
     */
674
    public function getPasswordHashAlgorithm($pass)
675
    {
676
        $pointer = strpos($pass, '>');
677
        $out = $pointer === false ? 'NOSALT' : substr($pass, 0, $pointer);
678
679
        return strtoupper($out);
680
    }
681
682
    /**
683
     * @param string $pass
684
     * @param int $seed
685
     * @param string $algorithm
686
     * @return string
687
     */
688
    public function makeHash($pass, $seed, $algorithm)
689
    {
690
        $salt = md5($pass . $seed);
691
692
        switch ($algorithm) {
693
            case 'BLOWFISH_Y':
694
                $salt = '$2y$07$' . substr($salt, 0, 22);
695
                break;
696
            case 'BLOWFISH_A':
697
                $salt = '$2a$07$' . substr($salt, 0, 22);
698
                break;
699
            case 'SHA512':
700
                $salt = '$6$' . substr($salt, 0, 16);
701
                break;
702
            case 'SHA256':
703
                $salt = '$5$' . substr($salt, 0, 16);
704
                break;
705
            case 'MD5':
706
                $salt = '$1$' . substr($salt, 0, 8);
707
                break;
708
            default:
709
                $algorithm = 'UNCRYPT';
710
                break;
711
        }
712
713
        $pass = $algorithm !== 'UNCRYPT' ? sha1($pass) . crypt($pass, $salt) : sha1($salt . $pass);
714
        $out = strtolower($algorithm) . '>' . md5($salt . $pass) . substr(md5($salt), 0, 8);
715
716
        return $out;
717
    }
718
719
720
}
721