Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.76% covered (success)
87.76%
43 / 49
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
CurrentUserSessionLookupTrait
87.76% covered (success)
87.76%
43 / 49
50.00% covered (danger)
50.00%
2 / 4
19.66
0.00% covered (danger)
0.00%
0 / 1
 getCurrentUser
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 getCurrentUserGroupId
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 getFromSession
77.27% covered (warning)
77.27%
17 / 22
0.00% covered (danger)
0.00%
0 / 1
9.95
 getFromCookie
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
3.01
1<?php
2
3/**
4 * Trait for looking up the current user from session or cookie
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public License,
7 * v. 2.0. If a copy of the MPL was not distributed with this file, You can
8 * obtain one at https://mozilla.org/MPL/2.0/.
9 *
10 * @package   phpMyFAQ
11 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
12 * @copyright 2026 phpMyFAQ Team
13 * @license   https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14 * @link      https://www.phpmyfaq.de
15 * @since     2026-02-24
16 */
17
18declare(strict_types=1);
19
20namespace phpMyFAQ\User;
21
22use phpMyFAQ\Configuration;
23use phpMyFAQ\Core\Exception;
24use phpMyFAQ\Permission\MediumPermission;
25use phpMyFAQ\Session\SessionWrapper;
26use Symfony\Component\HttpFoundation\Request;
27
28trait CurrentUserSessionLookupTrait
29{
30    /**
31     * Returns the current user object from cookie or session
32     *
33     * @throws Exception
34     */
35    public static function getCurrentUser(Configuration $configuration): CurrentUser
36    {
37        $user = self::getFromCookie($configuration);
38
39        if (!$user instanceof CurrentUser) {
40            $user = self::getFromSession($configuration);
41        }
42
43        if (!$user instanceof CurrentUser) {
44            return new CurrentUser($configuration);
45        }
46
47        $user->setLoggedIn(true);
48        return $user;
49    }
50
51    /**
52     * Returns the current user ID and group IDs as an array, default values are -1
53     *
54     * @return array{0: int, 1: int[]}
55     */
56    public static function getCurrentUserGroupId(?CurrentUser $user = null): array
57    {
58        if ($user === null) {
59            return [-1, [-1]];
60        }
61
62        $currentUser = $user->getUserId();
63        $currentGroups = [-1];
64        if ($user->perm instanceof MediumPermission) {
65            $currentGroups = $user->perm->getUserGroups($currentUser);
66        }
67
68        if ($currentGroups === []) {
69            $currentGroups = [-1];
70        }
71
72        return [$currentUser, $currentGroups];
73    }
74
75    /**
76     * This static method returns a valid CurrentUser object if there is one
77     * in the session that is not timed out. The session-ID is updated if
78     * necessary. The CurrentUser will be removed from the session if it is
79     * timed out. If there is no valid CurrentUser in the session or the
80     * session is timed out, null will be returned. If the session data is
81     * correct, but there is no user found in the user table, false will be
82     * returned. On success, a valid CurrentUser object is returned.
83     */
84    public static function getFromSession(Configuration $configuration): ?CurrentUser
85    {
86        $sessionWrapper = new SessionWrapper();
87        // there is no valid user object in the session
88        if (
89            !$sessionWrapper->has(CurrentUser::SESSION_CURRENT_USER)
90            || !$sessionWrapper->has(CurrentUser::SESSION_ID_TIMESTAMP)
91        ) {
92            return null;
93        }
94
95        // create a new CurrentUser object
96        $user = new CurrentUser($configuration);
97        $user->getUserById((int) $sessionWrapper->get(CurrentUser::SESSION_CURRENT_USER));
98
99        // user object is timed out
100        if ($user->sessionIsTimedOut()) {
101            $user->deleteFromSession();
102            $user->errors[] = 'Session timed out.';
103
104            return null;
105        }
106
107        // session-id isn't found in the user table
108        $sessionInfo = $user->getSessionInfo();
109        $sessionId = $sessionInfo['session_id'] ?? '';
110        if ($sessionId === '' || $sessionId !== session_id()) {
111            return null;
112        }
113
114        // check ip
115        if (
116            (bool) $configuration->get('security.ipCheck')
117            && $sessionInfo['ip'] !== Request::createFromGlobals()->getClientIp()
118        ) {
119            return null;
120        }
121
122        // session-id needs to be updated
123        if ($user->sessionIdIsTimedOut()) {
124            $user->updateSessionId();
125        }
126
127        // user is now logged in
128        $user->loggedIn = true;
129        // save the current user to the session and return the instance
130        $user->saveToSession();
131
132        return $user;
133    }
134
135    /**
136     * This static method returns a valid CurrentUser object if there is one
137     * in the cookie that is not timed out. The session-ID is updated then.
138     * The CurrentUser will be removed from the session if it is
139     * timed out. If there is no valid CurrentUser in the cookie or the
140     * cookie is timed out, null will be returned. If the cookie is correct,
141     * but there is no user found in the user table, false will be returned.
142     * On success, a valid CurrentUser object is returned.
143     *
144     * @throws Exception
145     */
146    public static function getFromCookie(Configuration $configuration): ?CurrentUser
147    {
148        $request = Request::createFromGlobals();
149        if ($request->cookies->get(UserSession::COOKIE_NAME_REMEMBER_ME) === null) {
150            return null;
151        }
152
153        // create a new CurrentUser object
154        $user = new CurrentUser($configuration);
155        $user->getUserByCookie((string) $request->cookies->get(UserSession::COOKIE_NAME_REMEMBER_ME, ''));
156
157        if (-1 === $user->getUserId()) {
158            return null;
159        }
160
161        // sessionId needs to be updated
162        $user->updateSessionId(true);
163        // user is now logged in
164        $user->loggedIn = true;
165        // save current user to session and return the instance
166        $user->saveToSession();
167
168        return $user;
169    }
170}