xref: /webtrees/app/SessionDatabaseHandler.php (revision dfc849d226fb4bd64f14664478a941ef05c27b61)
1<?php
2
3/**
4 * webtrees: online genealogy
5 * Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
16 */
17
18declare(strict_types=1);
19
20namespace Fisharebest\Webtrees;
21
22use Illuminate\Database\Capsule\Manager as DB;
23use Psr\Http\Message\ServerRequestInterface;
24use SessionHandlerInterface;
25use stdClass;
26
27/**
28 * Session handling - stores sessions in the database.
29 */
30class SessionDatabaseHandler implements SessionHandlerInterface
31{
32    /** @var ServerRequestInterface */
33    private $request;
34
35    /** @var stdClass|null The row from the session table */
36    private $row;
37
38    public function __construct(ServerRequestInterface $request)
39    {
40        $this->request = $request;
41    }
42
43    /**
44     * @param string $save_path
45     * @param string $name
46     *
47     * @return bool
48     */
49    public function open($save_path, $name): bool
50    {
51        return true;
52    }
53
54    /**
55     * @return bool
56     */
57    public function close(): bool
58    {
59        return true;
60    }
61
62    /**
63     * @param string $id
64     *
65     * @return string
66     */
67    public function read($id): string
68    {
69        $this->row = DB::table('session')
70            ->where('session_id', '=', $id)
71            ->first();
72
73
74        return $this->row->session_data ?? '';
75    }
76
77    /**
78     * @param string $id
79     * @param string $data
80     *
81     * @return bool
82     */
83    public function write($id, $data): bool
84    {
85        if ($this->row === null) {
86            DB::table('session')->insert([
87                'session_id' => $id,
88                'session_time' => Carbon::now(),
89                'user_id'      => (int) Auth::id(),
90                'ip_address'   => $this->request->getAttribute('client-ip'),
91                'session_data' => $data,
92            ]);
93        } else {
94            $updates = [];
95
96            // The user ID can change if we masquerade as another user.
97            if ((int) $this->row->user_id !== (int) Auth::id()) {
98                $updates['user_id'] = (int) Auth::id();
99            }
100
101            if ($this->row->ip_address !== $this->request->getAttribute('client-ip')) {
102                $updates['ip_address'] = $this->request->getAttribute('client-ip');
103            }
104
105            if ($this->row->session_data !== $data) {
106                $updates['session_data'] = $data;
107            }
108
109            if (Carbon::now()->subMinute()->gt($this->row->session_time)) {
110                $updates['session_time'] = Carbon::now();
111            }
112
113            if ($updates !== []) {
114                DB::table('session')
115                    ->where('session_id', '=', $id)
116                    ->update($updates);
117            }
118        }
119
120        return true;
121    }
122
123    /**
124     * @param string $id
125     *
126     * @return bool
127     */
128    public function destroy($id): bool
129    {
130        DB::table('session')
131            ->where('session_id', '=', $id)
132            ->delete();
133
134        return true;
135    }
136
137    /**
138     * @param int $maxlifetime
139     *
140     * @return bool
141     */
142    public function gc($maxlifetime): bool
143    {
144        DB::table('session')
145            ->where('session_time', '<', Carbon::now()->subSeconds($maxlifetime))
146            ->delete();
147
148        return true;
149    }
150}
151