Issues (2563)

app/SessionDatabaseHandler.php (2 issues)

Labels
Severity
1
<?php
2
3
/**
4
 * webtrees: online genealogy
5
 * Copyright (C) 2025 webtrees development team
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
 * GNU General Public License for more details.
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
 */
17
18
declare(strict_types=1);
19
20
namespace Fisharebest\Webtrees;
21
22
use Psr\Http\Message\ServerRequestInterface;
23
use SessionHandlerInterface;
24
25
use function date;
26
use function time;
27
28
/**
29
 * Session handling - stores sessions in the database.
30
 */
31
class SessionDatabaseHandler implements SessionHandlerInterface
32
{
33
    private ServerRequestInterface $request;
34
35
    private object|null $row = null;
36
37
    public function __construct(ServerRequestInterface $request)
38
    {
39
        $this->request = $request;
40
    }
41
42
    public function open(string $path, string $name): bool
43
    {
44
        return true;
45
    }
46
47
    public function close(): bool
48
    {
49
        return true;
50
    }
51
52
    public function read(string $id): string
53
    {
54
        $this->row = DB::table('session')
0 ignored issues
show
The type Fisharebest\Webtrees\DB was not found. Did you mean DB? If so, make sure to prefix the type with \.
Loading history...
55
            ->where('session_id', '=', $id)
56
            ->first();
57
58
        return $this->row->session_data ?? '';
59
    }
60
61
    public function write(string $id, string $data): bool
62
    {
63
        $ip_address = Validator::attributes($this->request)->string('client-ip');
64
        $user_id    = (int) Auth::id();
0 ignored issues
show
The type Fisharebest\Webtrees\Auth was not found. Did you mean Auth? If so, make sure to prefix the type with \.
Loading history...
65
66
        if ($this->row === null) {
67
            DB::table('session')->insert([
68
                'session_id'   => $id,
69
                'session_time' => date('Y-m-d H:i:s'),
70
                'user_id'      => $user_id,
71
                'ip_address'   => $ip_address,
72
                'session_data' => $data,
73
            ]);
74
        } else {
75
            $updates = [];
76
77
            // The user ID can change if we masquerade as another user.
78
            if ((int) $this->row->user_id !== $user_id) {
79
                $updates['user_id'] = $user_id;
80
            }
81
82
            if ($this->row->ip_address !== $ip_address) {
83
                $updates['ip_address'] = $ip_address;
84
            }
85
86
            if ($this->row->session_data !== $data) {
87
                $updates['session_data'] = $data;
88
            }
89
90
            // Only update session once a minute to reduce contention on the session table.
91
            if (date('Y-m-d H:i:s', time() - 60) > $this->row->session_time) {
92
                $updates['session_time'] =  date('Y-m-d H:i:s');
93
            }
94
95
            if ($updates !== []) {
96
                DB::table('session')
97
                    ->where('session_id', '=', $id)
98
                    ->update($updates);
99
            }
100
        }
101
102
        return true;
103
    }
104
105
    public function destroy(string $id): bool
106
    {
107
        DB::table('session')
108
            ->where('session_id', '=', $id)
109
            ->delete();
110
111
        return true;
112
    }
113
114
    public function gc(int $max_lifetime): int
115
    {
116
        return DB::table('session')
117
            ->where('session_time', '<', date('Y-m-d H:i:s', time() - $max_lifetime))
118
            ->delete();
119
    }
120
}
121