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.

FileHandler::isSupported()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 10
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
21
/**
22
 * Class FileHandler
23
 *
24
 * @package O2System\Session\Handlers
25
 */
26
class FileHandler extends AbstractHandler
27
{
28
    /**
29
     * Platform Name
30
     *
31
     * @var string
32
     */
33
    protected $platform = 'file';
34
35
    /**
36
     * File Handle
37
     *
38
     * @var resource
39
     */
40
    protected $file;
41
42
    /**
43
     * File write path
44
     *
45
     * @var string
46
     */
47
    protected $path;
48
49
    /**
50
     * File Name and Path
51
     *
52
     * @var resource
53
     */
54
    protected $filePath;
55
56
    /**
57
     * Is New File Flag
58
     *
59
     * @var bool
60
     */
61
    protected $isNewFile;
62
63
    // ------------------------------------------------------------------------
64
65
    /**
66
     * FileHandler::open
67
     *
68
     * Initialize session
69
     *
70
     * @link  http://php.net/manual/en/sessionhandlerinterface.open.php
71
     *
72
     * @param string $save_path The path where to store/retrieve the session.
73
     * @param string $name      The session name.
74
     *
75
     * @return bool <p>
76
     * The return value (usually TRUE on success, FALSE on failure).
77
     * Note this value is returned internally to PHP for processing.
78
     * </p>
79
     * @since 5.4.0
80
     */
81
    public function open($save_path, $name)
82
    {
83
        $this->path = $this->config[ 'filePath' ];
84
85
        if ($this->isSupported() === false) {
86
            if ($this->logger instanceof LoggerInterface) {
0 ignored issues
show
introduced by
$this->logger is always a sub-type of Psr\Log\LoggerInterface.
Loading history...
87
                $this->logger->error('SESSION_E_FILE_UNSUPPORTED', [$this->path]);
88
            }
89
90
            return $this->failure;
91
        }
92
93
        $this->filePath = $this->path
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->path . $name . '-...MOTE_ADDR']) . '-' : '' of type string is incompatible with the declared type resource of property $filePath.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
94
            . $name . '-' // we'll use the session cookie name as a prefix to avoid collisions
95
            . ($this->config[ 'match' ]->ip ? md5($_SERVER[ 'REMOTE_ADDR' ]) . '-' : '');
96
97
        return $this->success;
98
    }
99
100
    // ------------------------------------------------------------------------
101
102
    /**
103
     * FileHandler::isSupported
104
     *
105
     * Checks if this platform is supported on this system.
106
     *
107
     * @return bool Returns FALSE if unsupported.
108
     */
109
    public function isSupported()
110
    {
111
        if ( ! is_writable($this->path)) {
112
            @mkdir($this->path, 0777, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

112
            /** @scrutinizer ignore-unhandled */ @mkdir($this->path, 0777, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
113
        }
114
115
        return (bool)is_writable($this->path);
116
    }
117
118
    // ------------------------------------------------------------------------
119
120
    /**
121
     * FileHandler::destroy
122
     *
123
     * Destroy a session
124
     *
125
     * @link  http://php.net/manual/en/sessionhandlerinterface.destroy.php
126
     *
127
     * @param string $session_id The session ID being destroyed.
128
     *
129
     * @return bool <p>
130
     * The return value (usually TRUE on success, FALSE on failure).
131
     * Note this value is returned internally to PHP for processing.
132
     * </p>
133
     * @since 5.4.0
134
     */
135
    public function destroy($session_id)
136
    {
137
        if ($this->close()) {
138
            return file_exists($this->filePath . $session_id)
0 ignored issues
show
Bug introduced by
Are you sure $this->filePath of type resource can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

138
            return file_exists(/** @scrutinizer ignore-type */ $this->filePath . $session_id)
Loading history...
139
                ? (unlink($this->filePath . $session_id) && $this->destroyCookie())
140
                : true;
141
        } elseif ($this->filePath !== null) {
142
            clearstatcache();
143
144
            return file_exists($this->filePath . $session_id)
145
                ? (unlink($this->filePath . $session_id) && $this->destroyCookie())
146
                : true;
147
        }
148
149
        return false;
150
    }
151
152
    // ------------------------------------------------------------------------
153
154
    /**
155
     * FileHandler::close
156
     *
157
     * Close the session
158
     *
159
     * @link  http://php.net/manual/en/sessionhandlerinterface.close.php
160
     * @return bool <p>
161
     *        The return value (usually TRUE on success, FALSE on failure).
162
     *        Note this value is returned internally to PHP for processing.
163
     *        </p>
164
     * @since 5.4.0
165
     */
166
    public function close()
167
    {
168
        if (is_resource($this->file)) {
169
            flock($this->file, LOCK_UN);
170
            fclose($this->file);
171
172
            $this->file = $this->isNewFile = $this->sessionId = null;
173
174
            return true;
175
        }
176
177
        return true;
178
    }
179
180
    // ------------------------------------------------------------------------
181
182
    /**
183
     * FileHandler::gc
184
     *
185
     * Cleanup old sessions
186
     *
187
     * @link  http://php.net/manual/en/sessionhandlerinterface.gc.php
188
     *
189
     * @param int $maxlifetime <p>
190
     *                         Sessions that have not updated for
191
     *                         the last maxlifetime seconds will be removed.
192
     *                         </p>
193
     *
194
     * @return bool <p>
195
     * The return value (usually TRUE on success, FALSE on failure).
196
     * Note this value is returned internally to PHP for processing.
197
     * </p>
198
     * @since 5.4.0
199
     */
200
    public function gc($maxlifetime)
201
    {
202
        if ( ! is_dir($this->path) || ($directory = opendir($this->path)) === false) {
203
            if ($this->logger instanceof LoggerInterface) {
0 ignored issues
show
introduced by
$this->logger is always a sub-type of Psr\Log\LoggerInterface.
Loading history...
204
                $this->logger->error('SESSION_E_FILE_ON_GC', [$this->path]);
205
            }
206
207
            return false;
208
        }
209
210
        $ts = time() - $maxlifetime;
211
212
        while (($file = readdir($directory)) !== false) {
213
            // If the filename doesn't match this pattern, it's either not a session file or is not ours
214
            if ( ! preg_match('/[' . $this->config[ 'name' ] . '-]+[0-9-a-f]+/', $file)
215
                || ! is_file($this->path . '/' . $file)
216
                || ($mtime = filemtime($this->path . '/' . $file)) === false
217
                || $mtime > $ts
218
            ) {
219
                continue;
220
            }
221
222
            unlink($this->path . '/' . $file);
223
        }
224
225
        closedir($directory);
226
227
        return true;
228
    }
229
230
    // ------------------------------------------------------------------------
231
232
    /**
233
     * FileHandler::write
234
     *
235
     * Write session data
236
     *
237
     * @link  http://php.net/manual/en/sessionhandlerinterface.write.php
238
     *
239
     * @param string $session_id   The session id.
240
     * @param string $session_data <p>
241
     *                             The encoded session data. This data is the
242
     *                             result of the PHP internally encoding
243
     *                             the $_SESSION superglobal to a serialized
244
     *                             string and passing it as this parameter.
245
     *                             Please note sessions use an alternative serialization method.
246
     *                             </p>
247
     *
248
     * @return bool <p>
249
     * The return value (usually TRUE on success, FALSE on failure).
250
     * Note this value is returned internally to PHP for processing.
251
     * </p>
252
     * @since 5.4.0
253
     */
254
    public function write($session_id, $session_data)
255
    {
256
        // If the two IDs don't match, we have a session_regenerate_id() call
257
        // and we need to close the old handle and open a new one
258
        if ($session_id !== $this->sessionId && ( ! $this->close() || $this->read($session_id) === false)) {
259
            return false;
260
        }
261
262
        if ( ! is_resource($this->file)) {
263
            return false;
264
        } elseif ($this->fingerprint === md5($session_data)) {
265
            return ($this->isNewFile)
266
                ? true
267
                : touch($this->filePath . $session_id);
0 ignored issues
show
Bug introduced by
Are you sure $this->filePath of type resource can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

267
                : touch(/** @scrutinizer ignore-type */ $this->filePath . $session_id);
Loading history...
268
        }
269
270
        if ( ! $this->isNewFile) {
271
            ftruncate($this->file, 0);
272
            rewind($this->file);
273
        }
274
275
        if (($length = strlen($session_data)) > 0) {
276
            for ($written = 0; $written < $length; $written += $result) {
277
                if (($result = fwrite($this->file, substr($session_data, $written))) === false) {
278
                    break;
279
                }
280
            }
281
282
            if ( ! is_int($result)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
283
                $this->fingerprint = md5(substr($session_data, 0, $written));
0 ignored issues
show
Documentation Bug introduced by
The property $fingerprint was declared of type boolean, but md5(substr($session_data, 0, $written)) is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
284
285
                if ($this->logger instanceof LoggerInterface) {
0 ignored issues
show
introduced by
$this->logger is always a sub-type of Psr\Log\LoggerInterface.
Loading history...
286
                    $this->logger->error('SESSION_E_FILE_ON_WRITE');
287
                }
288
289
                return false;
290
            }
291
        }
292
293
        $this->fingerprint = md5($session_data);
294
295
        return true;
296
    }
297
298
    // ------------------------------------------------------------------------
299
300
    /**
301
     * FileHandler::read
302
     *
303
     * Read session data
304
     *
305
     * @link  http://php.net/manual/en/sessionhandlerinterface.read.php
306
     *
307
     * @param string $session_id The session id to read data for.
308
     *
309
     * @return string <p>
310
     * Returns an encoded string of the read data.
311
     * If nothing was read, it must return an empty string.
312
     * Note this value is returned internally to PHP for processing.
313
     * </p>
314
     * @since 5.4.0
315
     */
316
    public function read($session_id)
317
    {
318
        // This might seem weird, but PHP 5.6 introduced session_reset(),
319
        // which re-reads session data
320
        if ($this->file === null) {
321
            if (($this->file = fopen($this->filePath . $session_id, 'c+b')) === false) {
0 ignored issues
show
Documentation Bug introduced by
It seems like fopen($this->filePath . $session_id, 'c+b') can also be of type false. However, the property $file is declared as type resource. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
Bug introduced by
Are you sure $this->filePath of type resource can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

321
            if (($this->file = fopen(/** @scrutinizer ignore-type */ $this->filePath . $session_id, 'c+b')) === false) {
Loading history...
322
                if ($this->logger instanceof LoggerInterface) {
0 ignored issues
show
introduced by
$this->logger is always a sub-type of Psr\Log\LoggerInterface.
Loading history...
323
                    $this->logger->error('SESSION_E_FILE_ON_READ', [$this->filePath . $session_id]);
324
                }
325
326
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
327
            }
328
329
            if (flock($this->file, LOCK_EX) === false) {
330
                fclose($this->file);
331
                $this->file = null;
332
333
                if ($this->logger instanceof LoggerInterface) {
0 ignored issues
show
introduced by
$this->logger is always a sub-type of Psr\Log\LoggerInterface.
Loading history...
334
                    $this->logger->error('SESSION_E_ON_LOCK', [$this->filePath . $session_id]);
335
                }
336
337
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
338
            }
339
340
            // Needed by write() to detect session_regenerate_id() calls
341
            $this->sessionId = $session_id;
342
343
            if ($this->isNewFile) {
344
                chmod($this->filePath . $session_id, 0600);
345
                $this->fingerprint = md5('');
0 ignored issues
show
Documentation Bug introduced by
The property $fingerprint was declared of type boolean, but md5('') is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
346
347
                return '';
348
            }
349
        } else {
350
            rewind($this->file);
351
        }
352
353
        $sessionData = '';
354
        for ($read = 0, $length = filesize($this->filePath . $session_id); $read < $length; $read += strlen(
355
            $buffer
356
        )
357
        ) {
358
            if (($buffer = fread($this->file, $length - $read)) === false) {
359
                break;
360
            }
361
362
            $sessionData .= $buffer;
363
        }
364
365
        $this->fingerprint = md5($sessionData);
366
367
        return $sessionData;
368
    }
369
}