Test Failed
Push — master ( 87e790...e9a009 )
by Alexey
04:35
created

Users::cuntinueSession()   D

Complexity

Conditions 18
Paths 72

Size

Total Lines 47
Code Lines 35

Duplication

Lines 25
Ratio 53.19 %

Code Coverage

Tests 0
CRAP Score 342

Importance

Changes 0
Metric Value
cc 18
eloc 35
nc 72
nop 2
dl 25
loc 47
rs 4.9205
c 0
b 0
f 0
ccs 0
cts 41
cp 0
crap 342

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * Users module
5
 *
6
 * @author Alexey Krupskiy <[email protected]>
7
 * @link http://inji.ru/
8
 * @copyright 2015 Alexey Krupskiy
9
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
10
 */
11
class Users extends Module {
12
13
    public $cookiePrefix = '';
14
15
    public function init() {
16
        if (!empty($this->config['cookieSplit'])) {
17
            $this->cookiePrefix = \App::$cur->type;
18
        }
19
        \Users\User::$cur = new Users\User(array('group_id' => 1, 'role_id' => 1));
20
        if (!App::$cur->db->connect) {
21
            return false;
22
        }
23
        if (isset($_GET['logout'])) {
24
            return $this->logOut();
25
        }
26
        if (isset($_GET['passre']) && filter_input(INPUT_GET, 'user_mail')) {
27
            $this->passre(trim(filter_input(INPUT_GET, 'user_mail')));
28
        }
29
        if (!empty($_GET['passrecont']) && filter_input(INPUT_GET, 'hash')) {
30
            $this->passrecont(filter_input(INPUT_GET, 'hash'));
31
        }
32
        if (isset($_POST['autorization']) && trim(filter_input(INPUT_POST, 'user_login')) && trim(filter_input(INPUT_POST, 'user_pass'))) {
33
            unset($_POST['autorization']);
34
            return $this->autorization(trim(filter_input(INPUT_POST, 'user_login')), trim(filter_input(INPUT_POST, 'user_pass')), strpos(filter_input(INPUT_POST, 'user_login'), '@') ? 'mail' : 'login', false, false, trim(filter_input(INPUT_POST, 'ref')));
35
        }
36
        if (!empty($_COOKIE[$this->cookiePrefix . '_user_session_hash']) && is_string($_COOKIE[$this->cookiePrefix . '_user_session_hash']) && !empty($_COOKIE[$this->cookiePrefix . '_user_id']) && is_string($_COOKIE[$this->cookiePrefix . '_user_id'])) {
37
            return $this->cuntinueSession($_COOKIE[$this->cookiePrefix . '_user_session_hash'], $_COOKIE[$this->cookiePrefix . '_user_id']);
38
        }
39
    }
40
41
    public function logOut($redirect = true) {
42
        if (!empty($_COOKIE[$this->cookiePrefix . "_user_session_hash"]) && !empty($_COOKIE[$this->cookiePrefix . "_user_id"])) {
43
            $session = Users\Session::get([
44
                ['user_id', $_COOKIE[$this->cookiePrefix . "_user_id"]],
45
                ['hash', $_COOKIE[$this->cookiePrefix . "_user_session_hash"]]
46
            ]);
47
            if ($session) {
48
                $session->delete();
49
            }
50
        }
51 View Code Duplication
        if (!headers_sent()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
52
            setcookie($this->cookiePrefix . "_user_session_hash", '', 0, "/");
53
            setcookie($this->cookiePrefix . "_user_id", '', 0, "/");
54
        }
55
        if ($redirect) {
56
            if (!empty($this->config['logoutUrl'][$this->app->type])) {
57
                Tools::redirect($this->config['logoutUrl'][$this->app->type]);
58
            }
59
            Tools::redirect('/', 'Вы вышли из своего профиля', 'success');
60
        }
61
    }
62
63
    public function cuntinueSession($hash, $userId) {
64
        $session = Users\Session::get([
65
            ['user_id', $userId],
66
            ['hash', $hash]
67
        ]);
68 View Code Duplication
        if(!$session){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
69
            if (!headers_sent()) {
70
                setcookie($this->cookiePrefix . "_user_session_hash", '', 0, "/");
71
                setcookie($this->cookiePrefix . "_user_id", '', 0, "/");
72
            }
73
            Tools::redirect('/', 'Произошла непредвиденная ошибка при авторизации сессии');
74
        }
75
        if ($session->user->id != $userId) {
76
            Tools::redirect('/', 'Произошла непредвиденная ошибка при авторизации сессии');
77
        }
78
        if ($session && $session->user && $session->user->blocked) {
79 View Code Duplication
            if (!headers_sent()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
80
                setcookie($this->cookiePrefix . "_user_session_hash", '', 0, "/");
81
                setcookie($this->cookiePrefix . "_user_id", '', 0, "/");
82
            }
83
            Msg::add('Ваш аккаунт заблокирован', 'info');
84
            return;
85
        }
86
        if ($session && $session->user && !$session->user->blocked) {
87
            if (!empty($this->config['needActivation']) && $session->user->activation) {
88 View Code Duplication
                if (!headers_sent()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
89
                    setcookie($this->cookiePrefix . "_user_session_hash", '', 0, "/");
90
                    setcookie($this->cookiePrefix . "_user_id", '', 0, "/");
91
                }
92
                Tools::redirect('/', 'Этот аккаунт ещё не активирован. <br />Если вы не получали письмо с ссылкой для активации, нажмите на - <a href = "/users/resendActivation/' . $session->user->id . '"><b>повторно выслать ссылку активации</b></a>');
93
            } elseif ($session->user->activation) {
94
                Msg::add('Этот аккаунт ещё не активирован, не все функции могут быть доступны. <br />Если вы не получали письмо с ссылкой для активации, нажмите на - <a href = "/users/resendActivation/' . $session->user->id . '"><b>повторно выслать ссылку активации</b></a>');
95
            }
96 View Code Duplication
            if (!$session->user->mail && !empty($this->config['noMailNotify'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
97
                Msg::add($this->config['noMailNotify']);
98
            }
99
            Users\User::$cur = $session->user;
100
            Users\User::$cur->date_last_active = 'CURRENT_TIMESTAMP';
101
            Users\User::$cur->save();
102 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
103
            if (!headers_sent()) {
104
                setcookie($this->cookiePrefix . "_user_session_hash", '', 0, "/");
105
                setcookie($this->cookiePrefix . "_user_id", '', 0, "/");
106
            }
107
            Msg::add('Ваша сессия устарела или более недействительна, вам необходимо пройти <a href = "/users/login">авторизацию</a> заново', 'info');
108
        }
109
    }
110
111
    /**
112
     * @param string $user_mail
113
     */
114
    public function passre($user_mail) {
115
        $user = $this->get($user_mail, 'mail');
116
        if (!$user) {
117
            Msg::add('Пользователь ' . $user_mail . ' не найден, проверьте првильность ввода e-mail или зарегистрируйтесь', 'danger');
118
            return false;
119
        }
120
        $passre = Users\Passre::get([['user_id', $user->id], ['status', 1]]);
121
        if ($passre) {
122
            $passre->status = 2;
123
            $passre->save();
124
        }
125
        $hash = $user->id . '_' . Tools::randomString(50);
126
        $passre = new Users\Passre(['user_id' => $user->id, 'status' => 1, 'hash' => $hash]);
127
        $passre->save();
128
        Tools::sendMail('noreply@' . INJI_DOMAIN_NAME, $user_mail, 'Восстановление пароля на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME), 'Было запрошено восстановление пароля на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME) . '<br />для продолжения восстановления пароля перейдите по ссылке: <a href = "http://' . idn_to_utf8(INJI_DOMAIN_NAME) . '/?passrecont=1&hash=' . $hash . '">' . idn_to_utf8(INJI_DOMAIN_NAME) . '/?passrecont=1&hash=' . $hash . '</a>');
129
        Tools::redirect('/', 'На указанный почтовый ящик была выслана инструкция по восстановлению пароля', 'success');
130
    }
131
132
    public function passrecont($hash) {
133
        $passre = Users\Passre::get([['hash', $hash]]);
134
        if ($passre) {
135
            if ($passre->status != 1) {
136
                Tools::redirect('/', 'Этот код восстановление более недействителен', 'danger');
137
            }
138
            $passre->status = 3;
139
            $passre->save();
140
            $pass = Tools::randomString(10);
141
            $user = Users\User::get($passre->user_id);
142
            $user->pass = $this->hashpass($pass);
143
            $user->save();
144
            $this->autorization($user->id, $pass, 'id', true, true);
145
            Tools::sendMail('noreply@' . INJI_DOMAIN_NAME, $user->mail, 'Новый пароль на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME), 'Было запрошено восстановление пароля на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME) . '<br />Ваш новый пароль: ' . $pass);
146
            Tools::redirect('/', 'Вы успешно сбросили пароль и были авторизованы на сайте. На ваш почтовый ящик был выслан новый пароль', 'success');
147
        }
148
    }
149
150
    public function autorization($login, $pass, $ltype = 'login', $noMsg = true, $skipErrorCheck = false, $redirect = '') {
151
        $user = $this->get($login, $ltype);
152
        if ($user && !$skipErrorCheck) {
153
            $lastSuccessLogin = \Users\User\LoginHistory::lastSuccessLogin($user->id);
154
            $where = [['user_id', $user->id]];
155
            if ($lastSuccessLogin) {
156
                $where[] = ['date_create', $lastSuccessLogin->date_create, '>'];
157
            }
158
            $loginHistoryErrorCount = \Users\User\LoginHistory::getCount(['where' => $where]);
159
            if ($loginHistoryErrorCount > 5) {
160
                Msg::add('Было совершено более 5ти попыток подбора пароля к вашему аккаунту, для вашей безопасности мы были вынуждены заблокировать к нему доступ.<br />
161
Для разблокировки аккаунта, воспользуйтесь <a href = "?passre=1&user_mail=' . $user->mail . '">Сбросом пароля</a>', 'danger');
162
                return false;
163
            }
164
        }
165
        if ($user && $this->verifypass($pass, $user->pass) && !$user->blocked) {
166
            $loginHistory = new \Users\User\LoginHistory([
167
                'user_id' => $user->id,
168
                'ip' => $_SERVER['REMOTE_ADDR'],
169
                'success' => true
170
            ]);
171
            $loginHistory->save();
172
            if (!empty($this->config['needActivation']) && $user->activation) {
173
                Tools::redirect('/', 'Этот аккаунт ещё не активирован. <br />Если вы не получали письмо с ссылкой для активации, нажмите на - <a href = "/users/resendActivation/' . $user->id . '"><b>повторно выслать ссылку активации</b></a>');
174
            } elseif ($user->activation) {
175
                Msg::add('Этот аккаунт ещё не активирован, не все функции могут быть доступны. <br />Если вы не получали письмо с ссылкой для активации, нажмите на - <a href = "/users/resendActivation/' . $user->id . '"><b>повторно выслать ссылку активации</b></a>');
176
            }
177 View Code Duplication
            if (!$user->mail && !empty($this->config['noMailNotify'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
178
                Msg::add($this->config['noMailNotify']);
179
            }
180
            $this->newSession($user);
181
182
            Users\User::$cur = $user;
183
            Users\User::$cur->date_last_active = 'CURRENT_TIMESTAMP';
184
            Users\User::$cur->save();
185
            if (!$noMsg) {
186
                if (!empty($this->config['loginUrl'][$this->app->type]) && !$redirect) {
187
                    $redirect = $this->config['loginUrl'][$this->app->type];
188
                }
189
                Tools::redirect($redirect);
190
            }
191
192
            return true;
193
        }
194
        if (!$noMsg) {
195
            if ($user && $user->blocked) {
196
                Msg::add('Вы заблокированы', 'danger');
197
            } elseif ($user) {
198
                $loginHistory = new \Users\User\LoginHistory([
199
                    'user_id' => $user->id,
200
                    'ip' => $_SERVER['REMOTE_ADDR'],
201
                    'success' => false
202
                ]);
203
                $loginHistory->save();
204
                Msg::add('Вы ошиблись при наборе пароля или логина, попробуйте ещё раз или воспользуйтесь <a href = "?passre=1&user_mail=' . $user->mail . '">Восстановлением пароля</a>', 'danger');
205
            } else {
206
                Msg::add('Данный почтовый ящик не зарегистрирован в системе', 'danger');
207
            }
208
        }
209
210
        return false;
211
    }
212
213
    public function newSession($user) {
214
        $session = $this->createSession($user);
215
        if (!headers_sent()) {
216
            setcookie($this->cookiePrefix . "_user_session_hash", $session->hash, time() + 360000, "/");
217
            setcookie($this->cookiePrefix . "_user_id", $user->id, time() + 360000, "/");
218
        } else {
219
            Msg::add('Не удалось провести авторизацию. Попробуйте позже', 'info');
220
        }
221
    }
222
223
    public function createSession($user) {
224
        do {
225
            $hash = Tools::randomString(255);
226
        } while (Users\Session::get($hash, 'hash'));
227
228
        $session = new Users\Session([
229
            'user_id' => $user->id,
230
            'agent' => $_SERVER['HTTP_USER_AGENT'],
231
            'ip' => $_SERVER['REMOTE_ADDR'],
232
            'hash' => $hash
233
        ]);
234
        $session->save();
235
        return $session;
236
    }
237
238
    /**
239
     * Return user
240
     *
241
     * @param integer|string $idn
242
     * @param string $ltype
243
     * @return boolean|\Users\User
244
     */
245
    public function get($idn, $ltype = 'id') {
246
        if (!$idn)
247
            return false;
248
249
        if (is_numeric($idn) && $ltype != 'login')
250
            $user = Users\User::get($idn, 'id');
251
        elseif ($ltype == 'login')
252
            $user = Users\User::get($idn, 'login');
253
        else
254
            $user = Users\User::get($idn, 'mail');
255
        if (!$user)
256
            return [];
257
258
        return $user;
259
    }
260
261
    public function registration($data, $autorization = false) {
262
263
        if (empty($data['user_mail'])) {
264
            Msg::add('Вы не ввели E-mail', 'danger');
265
            return false;
266
        }
267
        $data['user_mail'] = trim($data['user_mail']);
268
        if (!filter_var($data['user_mail'], FILTER_VALIDATE_EMAIL)) {
269
            Msg::add('Вы ввели не корректный E-mail', 'danger');
270
            return false;
271
        }
272
273
        $user = $this->get($data['user_mail'], 'mail');
274
        if ($user) {
275
            Msg::add('Введенный вами E-mail зарегистрирован в нашей системе, войдите или введите другой E-mail', 'danger');
276
            return false;
277
        }
278
        if (empty($data['user_login'])) {
279
            $data['user_login'] = $data['user_mail'];
280
        }
281
        $data['user_login'] = trim($data['user_login']);
282
        $user = $this->get($data['user_login'], 'login');
283
        if ($user) {
284
            Msg::add('Введенный вами логин зарегистрирован в нашей системе, войдите или введите другой логин', 'danger');
285
            return false;
286
        }
287
        if (empty($data['first_name'])) {
288
            $data['first_name'] = '';
289
        }
290
        if (empty($data['last_name'])) {
291
            $data['last_name'] = '';
292
        }
293
        if (!empty($data['user_name'])) {
294
            $data['first_name'] = $data['user_name'];
295
        }
296
        if (empty($data['user_city'])) {
297
            $data['user_city'] = '';
298
        }
299
        if (empty($data['user_birthday'])) {
300
            $data['user_birthday'] = '';
301
        }
302
        if (empty($data['user_phone'])) {
303
            $data['user_phone'] = '';
304
        }
305
        $invite_code = (!empty($data['invite_code']) ? $data['invite_code'] : (!empty($_POST['invite_code']) ? $_POST['invite_code'] : ((!empty($_COOKIE['invite_code']) ? $_COOKIE['invite_code'] : ((!empty($_GET['invite_code']) ? $_GET['invite_code'] : ''))))));
306
        if (!empty($invite_code)) {
307
            $invite = Users\User\Invite::get($invite_code, 'code');
308
            if (!$invite) {
309
                Msg::add('Такой код приглашения не найден', 'danger');
310
                return false;
311
            }
312
            if ($invite->limit && !($invite->limit - $invite->count)) {
313
                Msg::add('Лимит приглашений для данного кода исчерпан', 'danger');
314
                return false;
315
            }
316
            $data['parent_id'] = $invite->user_id;
317
            $inviter = $data['parent_id'];
318
            $invite->count++;
319
            $invite->save();
320
        }
321
        if (empty($data['parent_id']) && !empty($this->config['defaultPartner'])) {
322
            $data['parent_id'] = $this->config['defaultPartner'];
323
        }
324
        if (!empty($data['user_pass'])) {
325
            if (empty($data['user_pass'][0])) {
326
                Msg::add('Введите пароль', 'danger');
327
                return false;
328
            }
329
            if (empty($data['user_pass'][1])) {
330
                Msg::add('Повторите ввод пароля', 'danger');
331
                return false;
332
            }
333
            if ($data['user_pass'][0] != $data['user_pass'][1]) {
334
                Msg::add('Введенные пароли несовпадают', 'danger');
335
                return false;
336
            }
337
            $pass = $data['user_pass'][0];
338
        } else {
339
            $pass = Tools::randomString(10);
340
        }
341
342
        $user = new Users\User([
343
            'pass' => $this->hashpass($pass),
344
            'mail' => $data['user_mail'],
345
            'login' => htmlspecialchars($data['user_login']),
346
            'role_id' => 2,
347
            'group_id' => 2,
348
            'parent_id' => !empty($data['parent_id']) ? $data['parent_id'] : 0
349
        ]);
350
        if (!empty($this->config['needActivation'])) {
351
            $user->activation = Tools::randomString();
352
        }
353
        $user->save();
354
        if (!$user->id) {
355
            Msg::add('Не удалось зарегистрировать', 'danger');
356
            return false;
357
        }
358
        $info = new \Users\User\Info([
359
            'user_id' => $user->id,
360
            'first_name' => htmlspecialchars($data['first_name']),
361
            'last_name' => htmlspecialchars($data['last_name']),
362
            'city' => htmlspecialchars($data['user_city']),
363
            'bday' => htmlspecialchars($data['user_birthday']),
364
            'phone' => htmlspecialchars($data['user_phone']),
365
            'photo_file_id' => !empty($_FILES['user_photo']['tmp_name']) ? $this->files->upload($_FILES['user_photo']) : 0
366
        ]);
367
        $info->save();
368
        if (isset($inviter)) {
369
            $this->AddUserActivity($inviter, 2, "У вас зарегистрировался новый партнер, {$info->first_name} {$info->last_name} (id: {$user->id}, email: {$user->mail})");
370
        }
371
        if ($autorization) {
372
            $this->autorization($data['user_mail'], $pass, 'mail');
373
        }
374
        if (!empty($this->config['needActivation'])) {
375
            $from = 'noreply@' . INJI_DOMAIN_NAME;
376
            $to = $data['user_mail'];
377
            $subject = 'Регистрация на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME);
378
            $text = 'Вы были зарегистрированы на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME) . '<br />для входа используйте ваш почтовый ящик в качестве логина и пароль: ' . $pass;
379
            $text .= '<br />';
380
            $text .= '<br />';
381
            $text .= 'Для активации вашего аккаунта перейдите по ссылке <a href = "http://' . INJI_DOMAIN_NAME . '/users/activation/' . $user->id . '/' . $user->activation . '">http://' . idn_to_utf8(INJI_DOMAIN_NAME) . '/users/activation/' . $user->id . '/' . $user->activation . '</a>';
382
            Tools::sendMail($from, $to, $subject, $text);
383
            Msg::add('Вы были зарегистрированы. На указанный почтовый ящик был выслан ваш пароль и ссылка для активации', 'success');
384
        } else {
385
            $from = 'noreply@' . INJI_DOMAIN_NAME;
386
            $to = $data['user_mail'];
387
            $subject = 'Регистрация на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME);
388
            $text = 'Вы были зарегистрированы на сайте ' . idn_to_utf8(INJI_DOMAIN_NAME) . '<br />для входа используйте ваш почтовый ящик в качестве логина и пароль: ' . $pass;
389
            Tools::sendMail($from, $to, $subject, $text);
390
            Msg::add('Вы были зарегистрированы. На указанный почтовый ящик был выслан ваш пароль', 'success');
391
        }
392
        return $user->id;
393
    }
394
395
    public function hashpass($pass) {
396
        return password_hash($pass, PASSWORD_DEFAULT);
397
    }
398
399
    public function verifypass($pass, $hash) {
400
        return password_verify($pass, $hash);
401
    }
402
403
    public function getUserPartners($user, $levelsCount = 0) {
404
        $return = [
405
            'users' => [],
406
            'levels' => [],
407
            'count' => 0,
408
            'lastLevel' => 0
409
        ];
410
        $userIds = $user->user_id;
411
        for ($i = 1; $i <= $levelsCount || !$levelsCount; $i++) {
412
            if (!$userIds && $levelsCount) {
413
                $return['levels'][$i] = [];
414
                continue;
415
            } elseif (!$userIds && !$levelsCount) {
416
                break;
417
            }
418
            $usersLevel = \Users\User::getList(['where' => [['parent_id', $userIds, 'IN']]]);
419
            $return['users'] += $usersLevel;
420
            $return['levels'][$i] = array_keys($usersLevel);
421
            $userIds = implode(',', $return['levels'][$i]);
422
            $return['lastLevel'] = $i;
423
        }
424
        $return['count'] = count($return['users']);
425
        return $return;
426
    }
427
428
    /**
429
     * @param integer $cat_id
430
     */
431
    public function addUserActivity($user_id, $cat_id, $text = '') {
432
        $ua = new Users\Activity([
433
            'user_id' => $user_id,
434
            'category_id' => $cat_id,
435
            'text' => $text,
436
        ]);
437
        $ua->save();
438
    }
439
}