SessionDatabaseHandler::close()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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