GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 49f2af...1d893d )
by Steeven
02:27
created

RedisHandler::close()   B

Complexity

Conditions 7
Paths 15

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 12
nc 15
nop 0
dl 0
loc 23
rs 8.8333
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Session\Handlers;
15
16
// ------------------------------------------------------------------------
17
18
use Psr\Log\LoggerInterface;
19
use O2System\Session\Abstracts\AbstractHandler;
20
use O2System\Session\DataStructures\Config;
21
22
/**
23
 * Class RedisHandler
24
 *
25
 * @package O2System\Session\Handlers
26
 */
27
class RedisHandler extends AbstractHandler
28
{
29
    /**
30
     * Platform Name
31
     *
32
     * @access  protected
33
     * @var string
34
     */
35
    protected $platform = 'redis';
36
37
    /**
38
     * Redis Object
39
     *
40
     * @var \Redis
41
     */
42
    protected $redis;
43
44
    // ------------------------------------------------------------------------
45
46
    /**
47
     * RedisHandler::__construct
48
     *
49
     * @param Config $config
50
     */
51
    public function __construct(Config $config)
52
    {
53
        $config->merge(
54
            [
55
                'socket'   => 'tcp', // 'tcp' or 'unix'
56
                'host'     => 'localhost', // '103.219.249.198', //
57
                'port'     => 6379, // 17883, //
58
                'password' => null, // (optional)
59
                'timeout'  => 5,
60
            ]
61
        );
62
63
        parent::__construct($config);
64
    }
65
66
    /**
67
     * RedisHandler::open
68
     *
69
     * Initialize session
70
     *
71
     * @link  http://php.net/manual/en/sessionhandlerinterface.open.php
72
     *
73
     * @param string $save_path The path where to store/retrieve the session.
74
     * @param string $name      The session name.
75
     *
76
     * @return bool <p>
77
     * The return value (usually TRUE on success, FALSE on failure).
78
     * Note this value is returned internally to PHP for processing.
79
     * </p>
80
     * @since 5.4.0
81
     */
82
    public function open($save_path, $name)
83
    {
84
        if (class_exists('Redis', false)) {
85
            $this->redis = new \Redis();
86
        } else {
87
            if ($this->logger instanceof LoggerInterface) {
88
                $this->logger->error('SESSION_E_PLATFORM_UNSUPPORTED', ['Redis']);
89
            }
90
91
           z
92
        }
93
94
        try {
95
            if ( ! $this->redis->connect(
96
                $this->config[ 'host' ],
97
                ($this->config[ 'host' ][ 0 ] === '/' ? 0
98
                    : $this->config[ 'port' ]),
99
                $this->config[ 'timeout' ]
100
            )
101
            ) {
102
                if ($this->logger instanceof LoggerInterface) {
103
                    $this->logger->error('SESSION_E_REDIS_CONNECTION_FAILED', ['Redis']);
104
                }
105
106
                return false;
107
            }
108
109
            if (isset($this->config[ 'password' ]) AND ! $this->redis->auth($this->config[ 'password' ])) {
110
                if ($this->logger instanceof LoggerInterface) {
111
                    $this->logger->error('SESSION_E_REDIS_AUTHENTICATION_FAILED', ['Redis']);
112
                }
113
114
                return false;
115
            }
116
117
            return true;
118
        } catch (\RedisException $e) {
119
            if ($this->logger instanceof LoggerInterface) {
120
                $this->logger->error('SESSION_E_REDIS_CONNECTION_REFUSED', $e->getMessage());
121
            }
122
123
            return false;
124
        }
125
    }
126
127
    // ------------------------------------------------------------------------
128
129
    /**
130
     * RedisHandler::close
131
     *
132
     * Close the session
133
     *
134
     * @link  http://php.net/manual/en/sessionhandlerinterface.close.php
135
     * @return bool <p>
136
     *        The return value (usually TRUE on success, FALSE on failure).
137
     *        Note this value is returned internally to PHP for processing.
138
     *        </p>
139
     * @since 5.4.0
140
     */
141
    public function close()
142
    {
143
        if (isset($this->redis)) {
144
            try {
145
                if ($this->redis->ping() === '+PONG') {
146
                    isset($this->lockKey) AND $this->redis->delete($this->lockKey);
147
148
                    if ( ! $this->redis->close()) {
149
                        return false;
150
                    }
151
                }
152
            } catch (\RedisException $e) {
153
                if ($this->logger instanceof LoggerInterface) {
154
                    $this->logger->error('SESSION_E_REDIS_ON_CLOSE', $e->getMessage());
155
                }
156
            }
157
158
            $this->redis = null;
159
160
            return true;
161
        }
162
163
        return true;
164
    }
165
166
    // ------------------------------------------------------------------------
167
168
    /**
169
     * RedisHandler::destroy
170
     *
171
     * Destroy a session
172
     *
173
     * @link  http://php.net/manual/en/sessionhandlerinterface.destroy.php
174
     *
175
     * @param string $session_id The session ID being destroyed.
176
     *
177
     * @return bool <p>
178
     * The return value (usually TRUE on success, FALSE on failure).
179
     * Note this value is returned internally to PHP for processing.
180
     * </p>
181
     * @since 5.4.0
182
     */
183
    public function destroy($session_id)
184
    {
185
        if (isset($this->redis, $this->isLocked)) {
186
            if (($result = $this->redis->delete($this->prefixKey . $session_id)) !== 1) {
187
                if ($this->logger instanceof LoggerInterface) {
188
                    $this->logger->error('SESSION_E_REDIS_ON_DELETE', var_export($result, true));
189
                }
190
            }
191
192
            return $this->destroyCookie();
193
        }
194
195
        return false;
196
    }
197
198
    // ------------------------------------------------------------------------
199
200
    /**
201
     * RedisHandler::gc
202
     *
203
     * Cleanup old sessions
204
     *
205
     * @link  http://php.net/manual/en/sessionhandlerinterface.gc.php
206
     *
207
     * @param int $maxlifetime <p>
208
     *                         Sessions that have not updated for
209
     *                         the last maxlifetime seconds will be removed.
210
     *                         </p>
211
     *
212
     * @return bool <p>
213
     * The return value (usually TRUE on success, FALSE on failure).
214
     * Note this value is returned internally to PHP for processing.
215
     * </p>
216
     * @since 5.4.0
217
     */
218
    public function gc($maxlifetime)
219
    {
220
        // Not necessary, Redis takes care of that.
221
        return true;
222
    }
223
224
    /**
225
     * RedisHandler::read
226
     *
227
     * Read session data
228
     *
229
     * @link  http://php.net/manual/en/sessionhandlerinterface.read.php
230
     *
231
     * @param string $session_id The session id to read data for.
232
     *
233
     * @return string <p>
234
     * Returns an encoded string of the read data.
235
     * If nothing was read, it must return an empty string.
236
     * Note this value is returned internally to PHP for processing.
237
     * </p>
238
     * @since 5.4.0
239
     */
240
    public function read($session_id)
241
    {
242
        if (isset($this->redis) AND $this->lockSession($session_id)) {
243
            // Needed by write() to detect session_regenerate_id() calls
244
            $this->sessionId = $session_id;
245
246
            $sessionData = (string)$this->redis->get($this->prefixKey . $session_id);
247
            $this->fingerprint = md5($sessionData);
248
249
            return $sessionData;
250
        }
251
252
        return '';
253
    }
254
255
    // ------------------------------------------------------------------------
256
257
    /**
258
     * RedisHandler::_lockSession
259
     *
260
     * Acquires an (emulated) lock.
261
     *
262
     * @param    string $session_id Session ID
263
     *
264
     * @return    bool
265
     */
266
    protected function lockSession($session_id)
267
    {
268
        if (isset($this->lockKey)) {
269
            return $this->redis->setTimeout($this->lockKey, 300);
270
        }
271
272
        // 30 attempts to obtain a lock, in case another request already has it
273
        $lockKey = $this->prefixKey . $session_id . ':lock';
274
        $attempt = 0;
275
276
        do {
277
            if (($ttl = $this->redis->ttl($lockKey)) > 0) {
278
                sleep(1);
279
                continue;
280
            }
281
282
            if ( ! $this->redis->setex($lockKey, 300, time())) {
283
                if ($this->logger instanceof LoggerInterface) {
284
                    $this->logger->error('SESSION_E_OBTAIN_LOCK', [$this->prefixKey . $session_id]);
285
                }
286
287
                return false;
288
            }
289
290
            $this->lockKey = $lockKey;
291
            break;
292
        } while (++$attempt < 30);
293
294
        if ($attempt === 30) {
295
            if ($this->logger instanceof LoggerInterface) {
296
                $this->logger->error('SESSION_E_OBTAIN_LOCK_30', [$this->prefixKey . $session_id]);
297
            }
298
299
            return false;
300
        } elseif ($ttl === -1) {
301
            if ($this->logger instanceof LoggerInterface) {
302
                $this->logger->error('SESSION_E_OBTAIN_LOCK_TTL', [$this->prefixKey . $session_id]);
303
            }
304
        }
305
306
        $this->isLocked = true;
307
308
        return true;
309
    }
310
311
    // ------------------------------------------------------------------------
312
313
    /**
314
     * RedisHandler::write
315
     *
316
     * Write session data
317
     *
318
     * @link  http://php.net/manual/en/sessionhandlerinterface.write.php
319
     *
320
     * @param string $session_id   The session id.
321
     * @param string $session_data <p>
322
     *                             The encoded session data. This data is the
323
     *                             result of the PHP internally encoding
324
     *                             the $_SESSION superglobal to a serialized
325
     *                             string and passing it as this parameter.
326
     *                             Please note sessions use an alternative serialization method.
327
     *                             </p>
328
     *
329
     * @return bool <p>
330
     * The return value (usually TRUE on success, FALSE on failure).
331
     * Note this value is returned internally to PHP for processing.
332
     * </p>
333
     * @since 5.4.0
334
     */
335
    public function write($session_id, $session_data)
336
    {
337
        if ( ! isset($this->redis)) {
338
            return false;
339
        } // Was the ID regenerated?
340
        elseif ($session_id !== $this->sessionId) {
341
            if ( ! $this->lockRelease() OR ! $this->lockSession($session_id)) {
342
                return false;
343
            }
344
345
            $this->fingerprint = md5('');
346
            $this->sessionId = $session_id;
347
        }
348
349
        if (isset($this->lockKey)) {
350
            $this->redis->setTimeout($this->lockKey, 300);
351
352
            if ($this->fingerprint !== ($fingerprint = md5($session_data))) {
353
                if ($this->redis->set($this->prefixKey . $session_id, $session_data, $this->config[ 'lifetime' ])) {
354
                    $this->fingerprint = $fingerprint;
355
356
                    return true;
357
                }
358
359
                return false;
360
            }
361
362
            return $this->redis->setTimeout($this->prefixKey . $session_id, $this->config[ 'lifetime' ]);
363
        }
364
365
        return false;
366
    }
367
368
    //--------------------------------------------------------------------
369
370
    /**
371
     * RedisHandler::_lockRelease
372
     *
373
     * Releases a previously acquired lock
374
     *
375
     * @return bool
376
     */
377
    protected function lockRelease()
378
    {
379
        if (isset($this->redis, $this->lockKey) && $this->isLocked) {
380
            if ( ! $this->redis->delete($this->lockKey)) {
381
                if ($this->logger instanceof LoggerInterface) {
382
                    $this->logger->error('SESSION_E_FREE_LOCK', [$this->lockKey]);
383
                }
384
385
                return false;
386
            }
387
388
            $this->lockKey = null;
389
            $this->isLocked = false;
390
        }
391
392
        return true;
393
    }
394
395
    //--------------------------------------------------------------------
396
397
    /**
398
     * RedisHandler::isSupported
399
     *
400
     * Checks if this platform is supported on this system.
401
     *
402
     * @return bool Returns FALSE if unsupported.
403
     */
404
    public function isSupported()
405
    {
406
        return (bool)extension_loaded('redis');
407
    }
408
}