ci4

Форк
0
/
DatabaseHandler.php 
307 строк · 7.3 Кб
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of CodeIgniter 4 framework.
7
 *
8
 * (c) CodeIgniter Foundation <admin@codeigniter.com>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace CodeIgniter\Session\Handlers;
15

16
use CodeIgniter\Database\BaseBuilder;
17
use CodeIgniter\Database\BaseConnection;
18
use CodeIgniter\Session\Exceptions\SessionException;
19
use Config\Database;
20
use Config\Session as SessionConfig;
21
use ReturnTypeWillChange;
22

23
/**
24
 * Base database session handler
25
 *
26
 * Do not use this class. Use database specific handler class.
27
 */
28
class DatabaseHandler extends BaseHandler
29
{
30
    /**
31
     * The database group to use for storage.
32
     *
33
     * @var string
34
     */
35
    protected $DBGroup;
36

37
    /**
38
     * The name of the table to store session info.
39
     *
40
     * @var string
41
     */
42
    protected $table;
43

44
    /**
45
     * The DB Connection instance.
46
     *
47
     * @var BaseConnection
48
     */
49
    protected $db;
50

51
    /**
52
     * The database type
53
     *
54
     * @var string
55
     */
56
    protected $platform;
57

58
    /**
59
     * Row exists flag
60
     *
61
     * @var bool
62
     */
63
    protected $rowExists = false;
64

65
    /**
66
     * ID prefix for multiple session cookies
67
     */
68
    protected string $idPrefix;
69

70
    /**
71
     * @throws SessionException
72
     */
73
    public function __construct(SessionConfig $config, string $ipAddress)
74
    {
75
        parent::__construct($config, $ipAddress);
76

77
        // Store Session configurations
78
        $this->DBGroup = $config->DBGroup ?? config(Database::class)->defaultGroup;
79
        // Add sessionCookieName for multiple session cookies.
80
        $this->idPrefix = $config->cookieName . ':';
81

82
        $this->table = $this->savePath;
83
        if (empty($this->table)) {
84
            throw SessionException::forMissingDatabaseTable();
85
        }
86

87
        $this->db       = Database::connect($this->DBGroup);
88
        $this->platform = $this->db->getPlatform();
89
    }
90

91
    /**
92
     * Re-initialize existing session, or creates a new one.
93
     *
94
     * @param string $path The path where to store/retrieve the session
95
     * @param string $name The session name
96
     */
97
    public function open($path, $name): bool
98
    {
99
        if (empty($this->db->connID)) {
100
            $this->db->initialize();
101
        }
102

103
        return true;
104
    }
105

106
    /**
107
     * Reads the session data from the session storage, and returns the results.
108
     *
109
     * @param string $id The session ID
110
     *
111
     * @return false|string Returns an encoded string of the read data.
112
     *                      If nothing was read, it must return false.
113
     */
114
    #[ReturnTypeWillChange]
115
    public function read($id)
116
    {
117
        if ($this->lockSession($id) === false) {
118
            $this->fingerprint = md5('');
119

120
            return '';
121
        }
122

123
        if (! isset($this->sessionID)) {
124
            $this->sessionID = $id;
125
        }
126

127
        $builder = $this->db->table($this->table)->where('id', $this->idPrefix . $id);
128

129
        if ($this->matchIP) {
130
            $builder = $builder->where('ip_address', $this->ipAddress);
131
        }
132

133
        $this->setSelect($builder);
134

135
        $result = $builder->get()->getRow();
136

137
        if ($result === null) {
138
            // PHP7 will reuse the same SessionHandler object after
139
            // ID regeneration, so we need to explicitly set this to
140
            // FALSE instead of relying on the default ...
141
            $this->rowExists   = false;
142
            $this->fingerprint = md5('');
143

144
            return '';
145
        }
146

147
        $result = is_bool($result) ? '' : $this->decodeData($result->data);
148

149
        $this->fingerprint = md5($result);
150
        $this->rowExists   = true;
151

152
        return $result;
153
    }
154

155
    /**
156
     * Sets SELECT clause
157
     */
158
    protected function setSelect(BaseBuilder $builder)
159
    {
160
        $builder->select('data');
161
    }
162

163
    /**
164
     * Decodes column data
165
     *
166
     * @param string $data
167
     *
168
     * @return false|string
169
     */
170
    protected function decodeData($data)
171
    {
172
        return $data;
173
    }
174

175
    /**
176
     * Writes the session data to the session storage.
177
     *
178
     * @param string $id   The session ID
179
     * @param string $data The encoded session data
180
     */
181
    public function write($id, $data): bool
182
    {
183
        if ($this->lock === false) {
184
            return $this->fail();
185
        }
186

187
        if ($this->sessionID !== $id) {
188
            $this->rowExists = false;
189
            $this->sessionID = $id;
190
        }
191

192
        if ($this->rowExists === false) {
193
            $insertData = [
194
                'id'         => $this->idPrefix . $id,
195
                'ip_address' => $this->ipAddress,
196
                'data'       => $this->prepareData($data),
197
            ];
198

199
            if (! $this->db->table($this->table)->set('timestamp', 'now()', false)->insert($insertData)) {
200
                return $this->fail();
201
            }
202

203
            $this->fingerprint = md5($data);
204
            $this->rowExists   = true;
205

206
            return true;
207
        }
208

209
        $builder = $this->db->table($this->table)->where('id', $this->idPrefix . $id);
210

211
        if ($this->matchIP) {
212
            $builder = $builder->where('ip_address', $this->ipAddress);
213
        }
214

215
        $updateData = [];
216

217
        if ($this->fingerprint !== md5($data)) {
218
            $updateData['data'] = $this->prepareData($data);
219
        }
220

221
        if (! $builder->set('timestamp', 'now()', false)->update($updateData)) {
222
            return $this->fail();
223
        }
224

225
        $this->fingerprint = md5($data);
226

227
        return true;
228
    }
229

230
    /**
231
     * Prepare data to insert/update
232
     */
233
    protected function prepareData(string $data): string
234
    {
235
        return $data;
236
    }
237

238
    /**
239
     * Closes the current session.
240
     */
241
    public function close(): bool
242
    {
243
        return ($this->lock && ! $this->releaseLock()) ? $this->fail() : true;
244
    }
245

246
    /**
247
     * Destroys a session
248
     *
249
     * @param string $id The session ID being destroyed
250
     */
251
    public function destroy($id): bool
252
    {
253
        if ($this->lock) {
254
            $builder = $this->db->table($this->table)->where('id', $this->idPrefix . $id);
255

256
            if ($this->matchIP) {
257
                $builder = $builder->where('ip_address', $this->ipAddress);
258
            }
259

260
            if (! $builder->delete()) {
261
                return $this->fail();
262
            }
263
        }
264

265
        if ($this->close()) {
266
            $this->destroyCookie();
267

268
            return true;
269
        }
270

271
        return $this->fail();
272
    }
273

274
    /**
275
     * Cleans up expired sessions.
276
     *
277
     * @param int $max_lifetime Sessions that have not updated
278
     *                          for the last max_lifetime seconds will be removed.
279
     *
280
     * @return false|int Returns the number of deleted sessions on success, or false on failure.
281
     */
282
    #[ReturnTypeWillChange]
283
    public function gc($max_lifetime)
284
    {
285
        $separator = ' ';
286
        $interval  = implode($separator, ['', "{$max_lifetime} second", '']);
287

288
        return $this->db->table($this->table)->where(
289
            'timestamp <',
290
            "now() - INTERVAL {$interval}",
291
            false
292
        )->delete() ? 1 : $this->fail();
293
    }
294

295
    /**
296
     * Releases the lock, if any.
297
     */
298
    protected function releaseLock(): bool
299
    {
300
        if (! $this->lock) {
301
            return true;
302
        }
303

304
        // Unsupported DB? Let the parent handle the simple version.
305
        return parent::releaseLock();
306
    }
307
}
308

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.