Passed
Push — master ( f16b47...733353 )
by
unknown
13:48
created

FrontendUserAuthentication::getNewSessionRecord()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Frontend\Authentication;
17
18
use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
19
use TYPO3\CMS\Core\Authentication\AuthenticationService;
20
use TYPO3\CMS\Core\Context\UserAspect;
21
use TYPO3\CMS\Core\Database\ConnectionPool;
22
use TYPO3\CMS\Core\Session\UserSession;
23
use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
24
use TYPO3\CMS\Core\Utility\GeneralUtility;
25
26
/**
27
 * Extension class for Front End User Authentication.
28
 */
29
class FrontendUserAuthentication extends AbstractUserAuthentication
30
{
31
    /**
32
     * Login type, used for services.
33
     * @var string
34
     */
35
    public $loginType = 'FE';
36
37
    /**
38
     * Form field with login-name
39
     * @var string
40
     */
41
    public $formfield_uname = 'user';
42
43
    /**
44
     * Form field with password
45
     * @var string
46
     */
47
    public $formfield_uident = 'pass';
48
49
    /**
50
     * Form field with status: *'login', 'logout'. If empty login is not verified.
51
     * @var string
52
     */
53
    public $formfield_status = 'logintype';
54
55
    /**
56
     * form field with 0 or 1
57
     * 1 = permanent login enabled
58
     * 0 = session is valid for a browser session only
59
     * @var string
60
     */
61
    public $formfield_permanent = 'permalogin';
62
63
    /**
64
     * Table in database with user data
65
     * @var string
66
     */
67
    public $user_table = 'fe_users';
68
69
    /**
70
     * Column for login-name
71
     * @var string
72
     */
73
    public $username_column = 'username';
74
75
    /**
76
     * Column for password
77
     * @var string
78
     */
79
    public $userident_column = 'password';
80
81
    /**
82
     * Column for user-id
83
     * @var string
84
     */
85
    public $userid_column = 'uid';
86
87
    /**
88
     * Column name for last login timestamp
89
     * @var string
90
     */
91
    public $lastLogin_column = 'lastlogin';
92
93
    /**
94
     * @var string
95
     */
96
    public $usergroup_column = 'usergroup';
97
98
    /**
99
     * @var string
100
     */
101
    public $usergroup_table = 'fe_groups';
102
103
    /**
104
     * Enable field columns of user table
105
     * @var array
106
     */
107
    public $enablecolumns = [
108
        'deleted' => 'deleted',
109
        'disabled' => 'disable',
110
        'starttime' => 'starttime',
111
        'endtime' => 'endtime'
112
    ];
113
114
    /**
115
     * @var array
116
     */
117
    public $groupData = [
118
        'title' => [],
119
        'uid' => [],
120
        'pid' => []
121
    ];
122
123
    /**
124
     * Used to accumulate the TSconfig data of the user
125
     * @var array
126
     */
127
    public $TSdataArray = [];
128
129
    /**
130
     * @var array
131
     */
132
    public $userTS = [];
133
134
    /**
135
     * @var bool
136
     */
137
    public $userTSUpdated = false;
138
139
    /**
140
     * @var bool
141
     */
142
    public $userData_change = false;
143
144
    /**
145
     * @var bool
146
     */
147
    public $is_permanent = false;
148
149
    /**
150
     * @var bool
151
     */
152
    protected $loginHidden = false;
153
154
    /**
155
     * Will prevent the setting of the session cookie (takes precedence over forceSetCookie)
156
     * Disable cookie by default, will be activated if saveSessionData() is called,
157
     * a user is logging-in or an existing session is found
158
     * @var bool
159
     */
160
    public $dontSetCookie = true;
161
162
    /**
163
     * Send no-cache headers (disabled by default, if no fixed session is there)
164
     * @var bool
165
     */
166
    public $sendNoCacheHeaders = false;
167
168
    public function __construct()
169
    {
170
        $this->name = self::getCookieName();
171
        parent::__construct();
172
        $this->checkPid = $GLOBALS['TYPO3_CONF_VARS']['FE']['checkFeUserPid'];
173
    }
174
175
    /**
176
     * Returns the configured cookie name
177
     *
178
     * @return string
179
     */
180
    public static function getCookieName()
181
    {
182
        $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['FE']['cookieName']);
183
        if (empty($configuredCookieName)) {
184
            $configuredCookieName = 'fe_typo_user';
185
        }
186
        return $configuredCookieName;
187
    }
188
189
    /**
190
     * Determine whether a session cookie needs to be set (lifetime=0)
191
     *
192
     * @return bool
193
     * @internal
194
     */
195
    public function isSetSessionCookie()
196
    {
197
        return ($this->userSession->isNew() || $this->forceSetCookie)
0 ignored issues
show
Bug introduced by
The method isNew() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

197
        return ($this->userSession->/** @scrutinizer ignore-call */ isNew() || $this->forceSetCookie)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
198
            && ((int)$this->lifetime === 0 || !$this->userSession->isPermanent());
199
    }
200
201
    /**
202
     * Determine whether a non-session cookie needs to be set (lifetime>0)
203
     *
204
     * @return bool
205
     * @internal
206
     */
207
    public function isRefreshTimeBasedCookie()
208
    {
209
        return $this->lifetime > 0 && $this->userSession->isPermanent();
210
    }
211
212
    /**
213
     * Returns an info array with Login/Logout data submitted by a form or params
214
     *
215
     * @return array
216
     * @see AbstractUserAuthentication::getLoginFormData()
217
     */
218
    public function getLoginFormData()
219
    {
220
        $loginData = parent::getLoginFormData();
221
        if ($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 0 || $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 1) {
222
            $isPermanent = GeneralUtility::_POST($this->formfield_permanent);
223
            if (strlen($isPermanent) != 1) {
224
                $isPermanent = $GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'];
225
            } elseif (!$isPermanent) {
226
                // To make sure the user gets a session cookie and doesn't keep a possibly existing time based cookie,
227
                // we need to force setting the session cookie here
228
                $this->forceSetCookie = true;
229
            }
230
            $isPermanent = (bool)$isPermanent;
231
        } elseif ($GLOBALS['TYPO3_CONF_VARS']['FE']['permalogin'] == 2) {
232
            $isPermanent = true;
233
        } else {
234
            $isPermanent = false;
235
        }
236
        $loginData['permanent'] = $isPermanent;
237
        $this->is_permanent = $isPermanent;
238
        return $loginData;
239
    }
240
241
    /**
242
     * Creates a user session record and returns its values.
243
     * However, as the FE user cookie is normally not set, this has to be done
244
     * before the parent class is doing the rest.
245
     *
246
     * @param array $tempuser User data array
247
     * @return UserSession The session data for the newly created session.
248
     */
249
    public function createUserSession(array $tempuser): UserSession
250
    {
251
        // At this point we do not know if we need to set a session or a permanent cookie
252
        // So we force the cookie to be set after authentication took place, which will
253
        // then call setSessionCookie(), which will set a cookie with correct settings.
254
        $this->dontSetCookie = false;
255
        $tempUserId = (int)($tempuser[$this->userid_column] ?? 0);
256
        $session = $this->userSessionManager->elevateToFixatedUserSession(
257
            $this->userSession,
0 ignored issues
show
Bug introduced by
It seems like $this->userSession can also be of type null; however, parameter $session of TYPO3\CMS\Core\Session\U...eToFixatedUserSession() does only seem to accept TYPO3\CMS\Core\Session\UserSession, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

257
            /** @scrutinizer ignore-type */ $this->userSession,
Loading history...
258
            $tempUserId,
259
            (bool)$this->is_permanent
260
        );
261
        // Updating lastLogin_column carrying information about last login.
262
        $this->updateLoginTimestamp($tempUserId);
263
        return $session;
264
    }
265
266
    /**
267
     * Will select all fe_groups records that the current fe_user is member of
268
     * and which groups are also allowed in the current domain.
269
     * It also accumulates the TSconfig for the fe_user/fe_groups in ->TSdataArray
270
     *
271
     * @return int Returns the number of usergroups for the frontend users (if the internal user record exists and the usergroup field contains a value)
272
     */
273
    public function fetchGroupData()
274
    {
275
        $this->TSdataArray = [];
276
        $this->userTS = [];
277
        $this->userTSUpdated = false;
278
        $this->groupData = [
279
            'title' => [],
280
            'uid' => [],
281
            'pid' => []
282
        ];
283
        // Setting default configuration:
284
        $this->TSdataArray[] = $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultUserTSconfig'];
285
        // Get the info data for auth services
286
        $authInfo = $this->getAuthInfoArray();
287
        if (is_array($this->user)) {
288
            $this->logger->debug('Get usergroups for user', [
289
                $this->userid_column => $this->user[$this->userid_column],
290
                $this->username_column => $this->user[$this->username_column]
291
            ]);
292
        } else {
293
            $this->logger->debug('Get usergroups for "anonymous" user');
294
        }
295
        $groupDataArr = [];
296
        // Use 'auth' service to find the groups for the user
297
        $subType = 'getGroups' . $this->loginType;
298
        /** @var AuthenticationService $serviceObj */
299
        foreach ($this->getAuthServices($subType, [], $authInfo) as $serviceObj) {
300
            $groupData = $serviceObj->getGroups($this->user, $groupDataArr);
301
            if (is_array($groupData) && !empty($groupData)) {
302
                // Keys in $groupData should be unique ids of the groups (like "uid") so this function will override groups.
303
                $groupDataArr = $groupData + $groupDataArr;
304
            }
305
        }
306
        if (empty($groupDataArr)) {
307
            $this->logger->debug('No usergroups found by services');
308
        }
309
        if (!empty($groupDataArr)) {
310
            $this->logger->debug(count($groupDataArr) . ' usergroup records found by services');
311
        }
312
        // Use 'auth' service to check the usergroups if they are really valid
313
        foreach ($groupDataArr as $groupData) {
314
            // By default a group is valid
315
            $validGroup = true;
316
            $subType = 'authGroups' . $this->loginType;
317
            foreach ($this->getAuthServices($subType, [], $authInfo) as $serviceObj) {
318
                // we assume that the service defines the authGroup function
319
                if (!$serviceObj->authGroup($this->user, $groupData)) {
320
                    $validGroup = false;
321
                    $this->logger->debug($subType . ' auth service did not auth group', [
322
                        'uid ' => $groupData['uid'],
323
                        'title' => $groupData['title'],
324
                    ]);
325
                    break;
326
                }
327
            }
328
            if ($validGroup && (string)$groupData['uid'] !== '') {
329
                $this->groupData['title'][$groupData['uid']] = $groupData['title'];
330
                $this->groupData['uid'][$groupData['uid']] = $groupData['uid'];
331
                $this->groupData['pid'][$groupData['uid']] = $groupData['pid'];
332
                $this->groupData['TSconfig'][$groupData['uid']] = $groupData['TSconfig'];
333
            }
334
        }
335
        if (!empty($this->groupData) && !empty($this->groupData['TSconfig'])) {
336
            // TSconfig: collect it in the order it was collected
337
            foreach ($this->groupData['TSconfig'] as $TSdata) {
338
                $this->TSdataArray[] = $TSdata;
339
            }
340
            $this->TSdataArray[] = $this->user['TSconfig'];
341
            // Sort information
342
            ksort($this->groupData['title']);
343
            ksort($this->groupData['uid']);
344
            ksort($this->groupData['pid']);
345
        }
346
        return !empty($this->groupData['uid']) ? count($this->groupData['uid']) : 0;
347
    }
348
349
    /**
350
     * Initializes the front-end user groups for the context API,
351
     * based on the user groups and the logged-in state.
352
     *
353
     * @param bool $respectUserGroups used with the $TSFE->loginAllowedInBranch flag to disable the inclusion of the users' groups
354
     * @return UserAspect
355
     */
356
    public function createUserAspect(bool $respectUserGroups = true): UserAspect
357
    {
358
        $userGroups = [0];
359
        $isUserAndGroupSet = is_array($this->user) && !empty($this->groupData['uid']);
360
        if ($isUserAndGroupSet) {
361
            // group -2 is not an existing group, but denotes a 'default' group when a user IS logged in.
362
            // This is used to let elements be shown for all logged in users!
363
            $userGroups[] = -2;
364
            $groupsFromUserRecord = $this->groupData['uid'];
365
        } else {
366
            // group -1 is not an existing group, but denotes a 'default' group when not logged in.
367
            // This is used to let elements be hidden, when a user is logged in!
368
            $userGroups[] = -1;
369
            if ($respectUserGroups) {
370
                // For cases where logins are not banned from a branch usergroups can be set based on IP masks so we should add the usergroups uids.
371
                $groupsFromUserRecord = $this->groupData['uid'];
372
            } else {
373
                // Set to blank since we will NOT risk any groups being set when no logins are allowed!
374
                $groupsFromUserRecord = [];
375
            }
376
        }
377
        // Make unique and sort the groups
378
        $groupsFromUserRecord = array_unique($groupsFromUserRecord);
379
        if ($respectUserGroups && !empty($groupsFromUserRecord)) {
380
            sort($groupsFromUserRecord);
381
            $userGroups = array_merge($userGroups, array_map('intval', $groupsFromUserRecord));
382
        }
383
384
        // For every 60 seconds the is_online timestamp for a logged-in user is updated
385
        if ($isUserAndGroupSet) {
386
            $this->updateOnlineTimestamp();
387
        }
388
389
        $this->logger->debug('Valid frontend usergroups: ' . implode(',', $userGroups));
390
        return GeneralUtility::makeInstance(UserAspect::class, $this, $userGroups);
391
    }
392
    /**
393
     * Returns the parsed TSconfig for the fe_user
394
     * The TSconfig will be cached in $this->userTS.
395
     *
396
     * @return array TSconfig array for the fe_user
397
     */
398
    public function getUserTSconf()
399
    {
400
        if (!$this->userTSUpdated) {
401
            // Parsing the user TS (or getting from cache)
402
            $this->TSdataArray = TypoScriptParser::checkIncludeLines_array($this->TSdataArray);
403
            $userTS = implode(LF . '[GLOBAL]' . LF, $this->TSdataArray);
404
            $parseObj = GeneralUtility::makeInstance(TypoScriptParser::class);
405
            $parseObj->parse($userTS);
406
            $this->userTS = $parseObj->setup;
407
            $this->userTSUpdated = true;
408
        }
409
        return $this->userTS;
410
    }
411
412
    /*****************************************
413
     *
414
     * Session data management functions
415
     *
416
     ****************************************/
417
    /**
418
     * Will write UC and session data.
419
     * If the flag $this->userData_change has been set, the function ->writeUC is called (which will save persistent user session data)
420
     *
421
     * @see getKey()
422
     * @see setKey()
423
     */
424
    public function storeSessionData()
425
    {
426
        // Saves UC and SesData if changed.
427
        if ($this->userData_change) {
428
            $this->writeUC();
429
        }
430
431
        if ($this->userSession->dataWasUpdated()) {
432
            if (!$this->userSession->hasData()) {
433
                // Remove session-data
434
                $this->removeSessionData();
435
                // Remove cookie if not logged in as the session data is removed as well
436
                if (empty($this->user['uid']) && !$this->loginHidden && $this->isCookieSet()) {
437
                    $this->removeCookie($this->name);
438
                }
439
            } elseif (!$this->userSessionManager->isSessionPersisted($this->userSession)) {
0 ignored issues
show
Bug introduced by
It seems like $this->userSession can also be of type null; however, parameter $session of TYPO3\CMS\Core\Session\U...r::isSessionPersisted() does only seem to accept TYPO3\CMS\Core\Session\UserSession, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

439
            } elseif (!$this->userSessionManager->isSessionPersisted(/** @scrutinizer ignore-type */ $this->userSession)) {
Loading history...
440
                // Create a new session entry in the backend
441
                $this->userSessionManager->fixateAnonymousSession($this->userSession, (bool)$this->is_permanent);
0 ignored issues
show
Bug introduced by
It seems like $this->userSession can also be of type null; however, parameter $session of TYPO3\CMS\Core\Session\U...ixateAnonymousSession() does only seem to accept TYPO3\CMS\Core\Session\UserSession, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

441
                $this->userSessionManager->fixateAnonymousSession(/** @scrutinizer ignore-type */ $this->userSession, (bool)$this->is_permanent);
Loading history...
442
                // Now set the cookie (= fix the session)
443
                $this->setSessionCookie();
444
            } else {
445
                // Update session data of an already fixated session
446
                $this->userSessionManager->updateSession($this->userSession);
0 ignored issues
show
Bug introduced by
It seems like $this->userSession can also be of type null; however, parameter $session of TYPO3\CMS\Core\Session\U...anager::updateSession() does only seem to accept TYPO3\CMS\Core\Session\UserSession, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

446
                $this->userSessionManager->updateSession(/** @scrutinizer ignore-type */ $this->userSession);
Loading history...
447
            }
448
        }
449
    }
450
451
    /**
452
     * Removes data of the current session.
453
     */
454
    public function removeSessionData()
455
    {
456
        $this->userSession->overrideData([]);
457
        if ($this->userSessionManager->isSessionPersisted($this->userSession)) {
0 ignored issues
show
Bug introduced by
It seems like $this->userSession can also be of type null; however, parameter $session of TYPO3\CMS\Core\Session\U...r::isSessionPersisted() does only seem to accept TYPO3\CMS\Core\Session\UserSession, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

457
        if ($this->userSessionManager->isSessionPersisted(/** @scrutinizer ignore-type */ $this->userSession)) {
Loading history...
458
            // Remove session record if $this->user is empty is if session is anonymous
459
            if ((empty($this->user) && !$this->loginHidden) || $this->userSession->isAnonymous()) {
460
                $this->userSessionManager->removeSession($this->userSession);
0 ignored issues
show
Bug introduced by
It seems like $this->userSession can also be of type null; however, parameter $session of TYPO3\CMS\Core\Session\U...anager::removeSession() does only seem to accept TYPO3\CMS\Core\Session\UserSession, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

460
                $this->userSessionManager->removeSession(/** @scrutinizer ignore-type */ $this->userSession);
Loading history...
461
            } else {
462
                $this->userSessionManager->updateSession($this->userSession);
0 ignored issues
show
Bug introduced by
It seems like $this->userSession can also be of type null; however, parameter $session of TYPO3\CMS\Core\Session\U...anager::updateSession() does only seem to accept TYPO3\CMS\Core\Session\UserSession, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

462
                $this->userSessionManager->updateSession(/** @scrutinizer ignore-type */ $this->userSession);
Loading history...
463
            }
464
        }
465
    }
466
467
    /**
468
     * Regenerate the session ID and transfer the session to new ID
469
     * Call this method whenever a user proceeds to a higher authorization level
470
     * e.g. when an anonymous session is now authenticated.
471
     * Forces cookie to be set
472
     */
473
    protected function regenerateSessionId()
474
    {
475
        parent::regenerateSessionId();
476
        // We force the cookie to be set later in the authentication process
477
        $this->dontSetCookie = false;
478
    }
479
480
    /**
481
     * Returns session data for the fe_user; Either persistent data following the fe_users uid/profile (requires login)
482
     * or current-session based (not available when browse is closed, but does not require login)
483
     *
484
     * @param string $type Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
485
     * @param string $key Key from the data array to return; The session data (in either case) is an array ($this->uc / $this->sessionData) and this value determines which key to return the value for.
486
     * @return mixed Returns whatever value there was in the array for the key, $key
487
     * @see setKey()
488
     */
489
    public function getKey($type, $key)
490
    {
491
        if (!$key) {
492
            return null;
493
        }
494
        $value = null;
495
        switch ($type) {
496
            case 'user':
497
                $value = $this->uc[$key];
498
                break;
499
            case 'ses':
500
                $value = $this->getSessionData($key);
501
                break;
502
        }
503
        return $value;
504
    }
505
506
    /**
507
     * Saves session data, either persistent or bound to current session cookie. Please see getKey() for more details.
508
     * When a value is set the flag $this->userData_change will be set so that the final call to ->storeSessionData() will know if a change has occurred and needs to be saved to the database.
509
     * Notice: Simply calling this function will not save the data to the database! The actual saving is done in storeSessionData() which is called as some of the last things in \TYPO3\CMS\Frontend\Http\RequestHandler. So if you exit before this point, nothing gets saved of course! And the solution is to call $GLOBALS['TSFE']->storeSessionData(); before you exit.
510
     *
511
     * @param string $type Session data type; Either "user" (persistent, bound to fe_users profile) or "ses" (temporary, bound to current session cookie)
512
     * @param string $key Key from the data array to store incoming data in; The session data (in either case) is an array ($this->uc / $this->sessionData) and this value determines in which key the $data value will be stored.
513
     * @param mixed $data The data value to store in $key
514
     * @see setKey()
515
     * @see storeSessionData()
516
     */
517
    public function setKey($type, $key, $data)
518
    {
519
        if (!$key) {
520
            return;
521
        }
522
        switch ($type) {
523
            case 'user':
524
                if ($this->user['uid']) {
525
                    if ($data === null) {
526
                        unset($this->uc[$key]);
527
                    } else {
528
                        $this->uc[$key] = $data;
529
                    }
530
                    $this->userData_change = true;
531
                }
532
                break;
533
            case 'ses':
534
                $this->setSessionData($key, $data);
535
                break;
536
        }
537
    }
538
539
    /**
540
     * Saves the tokens so that they can be used by a later incarnation of this class.
541
     *
542
     * @param string $key
543
     * @param mixed $data
544
     */
545
    public function setAndSaveSessionData($key, $data)
546
    {
547
        $this->setSessionData($key, $data);
548
        $this->storeSessionData();
549
    }
550
551
    /**
552
     * Hide the current login
553
     *
554
     * This is used by the fe_login_mode feature for pages.
555
     * A current login is unset, but we remember that there has been one.
556
     */
557
    public function hideActiveLogin()
558
    {
559
        $this->user = null;
560
        $this->loginHidden = true;
561
    }
562
563
    /**
564
     * Update the field "is_online" every 60 seconds of a logged-in user
565
     *
566
     * @internal
567
     */
568
    public function updateOnlineTimestamp()
569
    {
570
        if (!is_array($this->user) || !$this->user['uid']
571
            || $this->user['is_online'] >= $GLOBALS['EXEC_TIME'] - 60) {
572
            return;
573
        }
574
        $dbConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->user_table);
575
        $dbConnection->update(
576
            $this->user_table,
577
            ['is_online' => $GLOBALS['EXEC_TIME']],
578
            ['uid' => (int)$this->user['uid']]
579
        );
580
        $this->user['is_online'] = $GLOBALS['EXEC_TIME'];
581
    }
582
}
583