Completed
Push — master ( 8bf202...0bf21d )
by Agel_Nash
04:43 queued 01:49
created

Actions::getBackUrl()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 5
nop 1
dl 0
loc 10
rs 8.8571
c 0
b 0
f 0
1
<?php namespace DLUsers;
2
3
include_once(MODX_BASE_PATH . 'assets/lib/APIHelpers.class.php');
4
include_once(MODX_BASE_PATH . 'assets/lib/Helpers/FS.php');
5
include_once(MODX_BASE_PATH . 'assets/lib/MODxAPI/modUsers.php');
6
include_once(MODX_BASE_PATH . 'assets/snippets/DocLister/lib/DLTemplate.class.php');
7
include_once(MODX_BASE_PATH . 'assets/snippets/DocLister/lib/DLCollection.class.php');
8
9
use APIHelpers, DocumentParser, DLCollection, DLTemplate;
10
use Helpers\FS;
11
12
/**
13
 * Class Actions
14
 * @package DLUsers
15
 */
16
class Actions
17
{
18
    /**
19
     * Объект DocumentParser - основной класс MODX
20
     * @var \DocumentParser
21
     * @access protected
22
     */
23
    protected $modx = null;
24
    public $userObj = null;
25
    /**
26
     * @var DLCollection
27
     */
28
    public $url;
29
    protected static $lang = null;
30
    protected static $langDic = array();
31
    /**
32
     * @var Actions cached reference to singleton instance
33
     */
34
    protected static $instance;
35
36
    protected $config = array();
37
38
    /**
39
     * gets the instance via lazy initialization (created on first usage)
40
     *
41
     * @return self
42
     */
43
    public static function getInstance(DocumentParser $modx, $lang, $userClass = 'modUsers', $debug = false)
44
    {
45
46
        if (null === self::$instance) {
47
            self::$instance = new self($modx, $userClass, $debug);
48
        }
49
50
        self::$lang = $lang;
51
        self::loadLang($lang);
52
53
        return self::$instance;
54
    }
55
56
    /**
57
     * is not allowed to call from outside: private!
58
     *
59
     */
60
    private function __construct(DocumentParser $modx, $userClass, $debug)
61
    {
62
        $this->modx = $modx;
63
        $this->userObj = new $userClass($this->modx, $debug);
64
        $this->url = new DLCollection($this->modx);
65
66
        $site_url = $this->modx->getConfig('site_url');
67
        $site_start = $this->modx->getConfig('site_start', 1);
68
        $error_page = $this->modx->getConfig('error_page', $site_start);
69
        $unauthorized_page = $this->modx->getConfig('unauthorized_page', $error_page);
70
71
        $this->config = compact('site_url', 'site_start', 'error_page', 'unauthorized_page');
72
    }
73
74
    /**
75
     * prevent the instance from being cloned
76
     *
77
     * @return void
78
     */
79
    private function __clone()
80
    {
81
82
    }
83
84
    /**
85
     * prevent from being unserialized
86
     *
87
     * @return void
88
     */
89
    private function __wakeup()
90
    {
91
92
    }
93
94
    /**
95
     * Сброс авторизации и обновление страницы
96
     */
97
    public function logout($params)
98
    {
99
        $LogoutName = APIHelpers::getkey($params, 'LogoutName', 'logout');
100
        if (is_scalar($LogoutName) && !empty($LogoutName) && isset($_GET[$LogoutName])) {
101
            $userID = $this->UserID('web');
102
            if ($userID) {
103
                $this->userObj->edit($userID);
104
                $params = array();
105
                if ($this->userObj->getID()) {
106
                    $params = array(
107
                        "userid"   => $this->userObj->getID(),
108
                        "username" => $this->userObj->get('username')
109
                    );
110
                    $this->modx->invokeEvent("OnBeforeWebLogout", $params);
111
                }
112
                $this->userObj->logOut();
113
                if ($this->userObj->getID()) {
114
                    $this->modx->invokeEvent("OnWebLogout", $params);
115
                }
116
117
                $go = APIHelpers::getkey($params, 'url', '');
118
                if (empty($go)) {
119
                    $go = str_replace(
120
                        array("?" . $LogoutName, "&" . $LogoutName),
121
                        array("", ""),
122
                        $_SERVER['REQUEST_URI']
123
                    );
124
                }
125
126
                $start = $this->makeUrl($this->config['site_start']);
127
                if ($start == $go) {
128
                    $go = $this->config['site_url'];
129
                } else {
130
                    $go = $this->config['site_url'] . ltrim($go, '/');
131
                }
132
                $this->moveTo(array('url' => $go));
133
            } else {
134
                //Если юзер не авторизован, то показываем ему 404 ошибку
135
                $this->modx->sendErrorPage();
136
            }
137
        }
138
139
        return true;
140
    }
141
142
    /**
143
     * Генерация ссылки под кнопку выход
144
     * @return string
145
     */
146
    public function logoutUrl($params)
147
    {
148
        $LogoutName = APIHelpers::getkey($params, 'LogoutName', 'logout');
149
        $request = parse_url($_SERVER['REQUEST_URI']);
150
151
        //Во избежании XSS мы не сохраняем весь REQUEST_URI, а берем только path
152
        /*$query = (!empty($request['query'])) ? $request['query'].'&' : '';*/
153
        $query = '?' . $LogoutName;
154
155
        return $request['path'] . $query;
156
    }
157
158
    /**
159
     * Авторизация из блока
160
     *        если указан параметр authId, то данные из формы перекидываются в метод AuthPage
161
     *    В противном случае вся работа происходит внутри самого блока
162
     */
163
    public function AuthBlock($params)
164
    {
165
        $POST = array('backUrl' => $_SERVER['REQUEST_URI']);
166
167
        $error = $errorCode = '';
168
169
        $pwdField = APIHelpers::getkey($params, 'pwdField', 'password');
170
        $emailField = APIHelpers::getkey($params, 'emailField', 'email');
171
        $rememberField = APIHelpers::getkey($params, 'rememberField', 'remember');
172
173
        if ($this->UserID('web')) {
174
            $tpl = APIHelpers::getkey($params, 'tplProfile', '');
175
            if (empty($tpl)) {
176
                $tpl = $this->getTemplate('tplProfile');
177
            }
178
            $dataTPL = $this->userObj->toArray();
179
            $dataTPL['url.logout'] = $this->logoutUrl($params);
180
            $homeID = APIHelpers::getkey($params, 'homeID');
181
            if (!empty($homeID)) {
182
                $dataTPL['url.profile'] = $this->makeUrl($homeID);
183
            }
184
        } else {
185
            $tpl = APIHelpers::getkey($params, 'tplForm', '');
186
            if (empty($tpl)) {
187
                $tpl = $this->getTemplate('authForm');
188
            }
189
            $POST = $this->Auth($pwdField, $emailField, $rememberField, $POST['backUrl'], __METHOD__, $error,
190
                $errorCode, $params);
191
            $dataTPL = array(
192
                'backUrl'    => APIHelpers::getkey($POST, 'backUrl', ''),
193
                'emailValue' => APIHelpers::getkey($POST, 'email', ''),
194
                'emailField' => $emailField,
195
                'pwdField'   => $pwdField,
196
                'method'     => strtolower(__METHOD__),
197
                'error'      => $error,
198
                'errorCode'  => $errorCode
199
            );
200
            $authId = APIHelpers::getkey($params, 'authId');
201
            if (!empty($authId)) {
202
                $dataTPL['authPage'] = $this->makeUrl($authId);
203
                $dataTPL['method'] = strtolower(__CLASS__ . '::' . 'authpage');
204
            }
205
        }
206
207
        return DLTemplate::getInstance($this->modx)->parseChunk($tpl, $dataTPL);
208
    }
209
210
    /**
211
     * Авторизация на сайте со страницы авторизации
212
     * [!Auth? &login=`password` &pwdField=`password` &homeID=`72`!]
213
     */
214
    public function AuthPage($params)
215
    {
216
        $homeID = APIHelpers::getkey($params, 'homeID');
217
        $this->isAuthGoHome(array('id' => $homeID));
218
219
        $error = $errorCode = '';
220
        $POST = array('backUrl' => '');
221
222
        $pwdField = APIHelpers::getkey($params, 'pwdField', 'password');
223
        $emailField = APIHelpers::getkey($params, 'emailField', 'email');
224
        $rememberField = APIHelpers::getkey($params, 'rememberField', 'remember');
225
226
        $tpl = APIHelpers::getkey($params, 'tpl', '');
227
        if (empty($tpl)) {
228
            $tpl = $this->getTemplate('authForm');
229
        }
230
231
        $request = parse_url($_SERVER['REQUEST_URI']);
232
        if (!empty($_SERVER['HTTP_REFERER'])) {
233
            /**
234
             * Thank you for super protection against hacking in protect.inc.php:-)
235
             */
236
            $refer = htmlspecialchars_decode($_SERVER['HTTP_REFERER'], ENT_QUOTES);
237
        } else {
238
             $refer = $this->getBackUrl($request);
0 ignored issues
show
Security Bug introduced by
It seems like $request defined by parse_url($_SERVER['REQUEST_URI']) on line 231 can also be of type false; however, DLUsers\Actions::getBackUrl() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
239
        }
240
241
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
242
            $backUrl = APIHelpers::getkey($_POST, 'backUrl', $POST['backUrl']);
243
            if (!is_scalar($backUrl)) {
244
                $backUrl = $refer;
245
            } else {
246
                $backUrl = urldecode($backUrl);
247
            }
248
        } else {
249
            $backUrl = $refer;
250
        }
251
        $backUrl = parse_url($backUrl);
252
        if (!empty($backUrl['path']) && $request['path'] != $backUrl['path']) {
253
            $POST['backUrl'] = $backUrl['path'];
254
        } else {
255
            $POST['backUrl'] = $this->getBackUrl($backUrl);
0 ignored issues
show
Security Bug introduced by
It seems like $backUrl defined by parse_url($backUrl) on line 251 can also be of type false; however, DLUsers\Actions::getBackUrl() does only seem to accept array, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
256
        }
257
        if (!empty($POST['backUrl'])) {
258
            $idURL = $this->moveTo(array(
259
                'url'      => '/' . ltrim($POST['backUrl'], '/'),
260
                'validate' => true
261
            ));
262
        } else {
263
            $idURL = 0;
264
        }
265
        if (empty($idURL)) {
266
            if (empty($homeID)) {
267
                $homeID = $this->config['site_start'];
268
            }
269
            $POST['backUrl'] = $this->makeUrl($homeID);
270
        }
271
        $POST = $this->Auth($pwdField, $emailField, $rememberField, $POST['backUrl'], __METHOD__, $error, $errorCode,
272
            $params);
273
274
        return DLTemplate::getInstance($this->modx)->parseChunk($tpl, array(
275
            'backUrl'    => APIHelpers::getkey($POST, 'backUrl', ''),
276
            'emailValue' => APIHelpers::getkey($POST, 'email', ''),
277
            'emailField' => $emailField,
278
            'pwdField'   => $pwdField,
279
            'method'     => strtolower(__METHOD__),
280
            'error'      => $error,
281
            'errorCode'  => $errorCode
282
        ));
283
    }
284
285
    /**
286
     * @param array $request
287
     * @return string
288
     */
289
    protected function getBackUrl(array $request = array()){
290
        $selfHost = rtrim(str_replace("http://", "", $this->config['site_url']), '/');
291
        if (empty($request['host']) || $request['host'] == $selfHost) {
292
            $query = !empty($request['query']) ? '?' . $request['query'] : '';
293
            $out = !empty($request['path']) ? $request['path'] . $query : '';
294
        } else {
295
            $out = '';
296
        }
297
        return $out;
298
    }
299
300
    /**
301
     * @param $pwdField
302
     * @param $emailField
303
     * @param $rememberField
304
     * @param $backUrl
305
     * @param $method
306
     * @param $error
307
     * @param $errorCode
308
     * @param array $params
309
     * @return array
310
     */
311
    protected function Auth(
312
        $pwdField,
313
        $emailField,
314
        $rememberField,
315
        $backUrl,
316
        $method,
317
        &$error,
318
        &$errorCode,
319
        $params = array()
320
    ) {
321
        $POST = array(
322
            'backUrl' => urlencode($backUrl)
323
        );
324
        $userObj = &$this->userObj;
325
        if ($_SERVER['REQUEST_METHOD'] == 'POST' && APIHelpers::getkey($_POST, 'method', '') == strtolower($method)) {
326
            $POST = array_merge($POST, array(
327
                'password' => APIHelpers::getkey($_POST, $pwdField, ''),
328
                'email'    => APIHelpers::getkey($_POST, $emailField, ''),
329
                'remember' => (bool)((int)APIHelpers::getkey($_POST, $rememberField, 0))
330
            ));
331
            if (!empty($POST['email']) && is_scalar($POST['email']) && !$userObj->emailValidate($POST['email'],
332
                    false)
333
            ) {
334
                $userObj->edit($POST['email']);
335
336
                $this->modx->invokeEvent("OnBeforeWebLogin", array(
337
                    "username"     => $POST['email'],
338
                    "userpassword" => $POST['password'],
339
                    "rememberme"   => $POST['remember'],
340
                    'userObj'      => $userObj
341
                ));
342
                if ($userObj->getID() && !$userObj->checkBlock($userObj->getID())) {
343
                    $pluginFlag = $this->modx->invokeEvent("OnWebAuthentication", array(
344
                        "userid"        => $userObj->getID(),
345
                        "username"      => $userObj->get('username'),
346
                        "userpassword"  => $POST['password'],
347
                        "savedpassword" => $userObj->get('password'),
348
                        "rememberme"    => $POST['remember'],
349
                    ));
350
                    if (
351
                        ($pluginFlag === true || $userObj->testAuth($userObj->getID(), $POST['password'], 0))
352
                        &&
353
                        $userObj->authUser($userObj->getID(), $POST['remember'])
354
                    ) {
355
                        $userObj->set('logincount', (int)$userObj->get('logincount') + 1);
356
                        $userObj->set('lastlogin', time());
357
                        $userObj->set('failedlogincount', 0);
358
                        $userObj->save(false, false);
359
360
                        $this->modx->invokeEvent("OnWebLogin", array(
361
                            "userid"       => $userObj->getID(),
362
                            "username"     => $userObj->get('username'),
363
                            "userpassword" => $POST['password'],
364
                            "rememberme"   => $POST['remember'],
365
                        ));
366
                        $this->moveTo(array('url' => urldecode($POST['backUrl'])));
367
                    } else {
368
                        $userObj->set('failedlogincount', (int)$userObj->get('failedlogincount') + 1);
369
                        $userObj->save(false, false);
370
371
                        $error = 'error.incorrect_password';
372
                    }
373
                } else {
374
                    $error = 'error.no_user';
375
                }
376
            } else {
377
                $error = 'error.incorrect_mail';
378
                $POST['email'] = '';
379
            }
380
        }
381
        if (!empty($error)) {
382
            $errorCode = $error;
383
            $error = APIHelpers::getkey($params, $error, '');
384
            $error = static::getLangMsg($error, $error);
385
        }
386
387
        return $POST;
388
    }
389
390
    /**
391
     * Информация о пользователе
392
     * [!DLUsers? &action=`UserInfo` &field=`fullname` &id=`2`!]
393
     */
394
    public function UserInfo($params)
395
    {
396
        $out = '';
397
        $userID = APIHelpers::getkey($params, 'id', 0);
398
        if (empty($userID)) {
399
            $userID = $this->UserID('web');
400
        }
401
        $field = APIHelpers::getkey($params, 'field', 'username');
402
        if ($userID > 0) {
403
            $this->userObj->edit($userID);
404
            switch (true) {
405
                case ($field == $this->userObj->fieldPKName()):
406
                    $out = $this->userObj->getID();
407
                    break;
408
                case ($this->userObj->issetField($field)):
409
                    $out = $this->userObj->get($field);
410
                    break;
411
            }
412
        }
413
414
        return $out;
415
    }
416
417
    /**
418
     * ID пользователя
419
     */
420
    public function UserID($type = 'web')
421
    {
422
        return $this->modx->getLoginUserID($type);
423
    }
424
425
    /**
426
     * Если не авторизован - то отправить на страницу
427
     */
428
    public function isGuestGoHome($params)
429
    {
430
        if (!$this->UserID('web')) {
431
            /**
432
             * @see : http://modx.im/blog/triks/105.html
433
             */
434
            $this->modx->invokeEvent('OnPageUnauthorized');
435
            $id = APIHelpers::getkey($params, 'id', $this->config['unauthorized_page']);
436
            $this->moveTo(compact('id'));
437
        }
438
439
        return;
440
    }
441
442
    /**
443
     * Если авторизован - то открыть личный кабинет
444
     */
445
    public function isAuthGoHome($params)
446
    {
447
        $userID = $this->UserID('web');
448
        if ($userID > 0) {
449
            $id = APIHelpers::getkey($params, 'homeID');
450
            if (empty($id)) {
451
                $id = $this->modx->getConfig('login_home', $this->config['site_start']);
452
            }
453
            $this->moveTo(compact('id'));
454
        }
455
456
        return;
457
    }
458
459
    /**
460
     * Редирект
461
     */
462
    public function moveTo($params)
463
    {
464
        $id = (int)APIHelpers::getkey($params, 'id', 0);
465
        $uri = APIHelpers::getkey($params, 'url', '');
466
        if ((empty($uri) && !empty($id)) || !is_string($uri)) {
467
            $uri = $this->makeUrl($id);
468
        }
469
        $code = (int)APIHelpers::getkey($params, 'code', 0);
470
        $addUrl = APIHelpers::getkey($params, 'addUrl', '');
471
        if (is_scalar($addUrl) && $addUrl != '') {
472
            $uri .= "?" . $addUrl;
473
        }
474
        if (APIHelpers::getkey($params, 'validate', false)) {
475
            if (isset($this->modx->snippetCache['getPageID'])) {
476
                $out = $this->modx->runSnippet('getPageID', compact('uri'));
477
                if (empty($out)) {
478
                    $uri = '';
479
                }
480
            } else {
481
                $uri = APIhelpers::sanitarTag($uri);
482
            }
483
        } else {
484
            //$modx->sendRedirect($url, 0, 'REDIRECT_HEADER', 'HTTP/1.1 307 Temporary Redirect');
485
            header("Location: " . $uri, true, ($code > 0 ? $code : 307));
486
        }
487
488
        return $uri;
489
    }
490
491
    /**
492
     * Создание ссылки на страницу
493
     *
494
     * @param  int $id ID документа
495
     * @return string
496
     */
497
    protected function makeUrl($id = null)
498
    {
499
        $id = (int)$id;
500
        if ($id <= 0) {
501
            $id = $this->modx->documentObject['id'];
502
        }
503
        if ($this->url->containsKey($id)) {
504
            $url = $this->url->get($id);
505
        } else {
506
            $url = $this->modx->makeUrl($id);
507
            $this->url->set($id, $url);
508
        }
509
510
        return $url;
511
    }
512
513
    /**
514
     * @param $name
515
     * @return string
516
     */
517
    protected function getTemplate($name)
518
    {
519
        $out = '';
520
        $file = dirname(dirname(__FILE__)) . '/tpl/' . $name . '.html';
521
        if (FS::getInstance()->checkFile($file)) {
522
            $out = '@CODE: ' . file_get_contents($file);
523
        }
524
525
        return $out;
526
    }
527
528
    /**
529
     * @param $lang
530
     * @return bool
531
     */
532
    protected static function loadLang($lang)
533
    {
534
        $file = dirname(dirname(__FILE__)) . '/lang/' . $lang . '.php';
535
        if (!FS::getInstance()->checkFile($file)) {
536
            $file = false;
537
        }
538
        if (!empty($lang) && !isset(static::$langDic[$lang]) && !empty($file)) {
539
            static::$langDic[$lang] = include_once($file);
540
            if (is_array(static::$langDic[$lang])) {
541
                static::$langDic[$lang] = APIHelpers::renameKeyArr(static::$langDic[$lang], $lang);
542
            } else {
543
                static::$langDic[$lang] = array();
544
            }
545
        }
546
547
        return !(empty($lang) || empty(static::$langDic[$lang]));
548
    }
549
550
    /**
551
     * @param $key
552
     * @param $default
553
     * @return string
554
     */
555
    protected static function getLangMsg($key, $default)
556
    {
557
        $out = $default;
558
        $lng = static::$lang;
559
        $dic = static::$langDic;
560
        if (isset($dic[$lng], $dic[$lng][$lng . '.' . $key])) {
561
            $out = $dic[$lng][$lng . '.' . $key];
562
        }
563
        if (class_exists('evoBabel', false) && isset(self::$instance->modx->snippetCache['lang'])) {
564
            $msg = self::$instance->modx->runSnippet('lang', array('a' => 'DLUsers.' . $key));
565
            if (!empty($msg)) {
566
                $out = $msg;
567
            }
568
        }
569
570
        return $out;
571
    }
572
}
573