SessionDatabaseHandler   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 40
dl 0
loc 88
rs 10
c 0
b 0
f 0
wmc 13

7 Methods

Rating   Name   Duplication   Size   Complexity  
A open() 0 3 1
A destroy() 0 7 1
A __construct() 0 3 1
A gc() 0 5 1
A close() 0 3 1
A read() 0 7 1
B write() 0 42 7
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
Bug introduced by
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
Bug introduced by
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