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.
Completed
Pull Request — 3.x (#1872)
by
unknown
02:50
created

Stream::isPipe()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 2
Metric Value
c 3
b 0
f 2
dl 0
loc 12
rs 9.4285
cc 3
eloc 7
nc 3
nop 0
1
<?php
2
/**
3
 * Slim Framework (http://slimframework.com)
4
 *
5
 * @link      https://github.com/slimphp/Slim
6
 * @copyright Copyright (c) 2011-2016 Josh Lockhart
7
 * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
8
 */
9
namespace Slim\Http;
10
11
use InvalidArgumentException;
12
use Psr\Http\Message\StreamInterface;
13
use RuntimeException;
14
15
/**
16
 * Represents a data stream as defined in PSR-7.
17
 *
18
 * @link https://github.com/php-fig/http-message/blob/master/src/StreamInterface.php
19
 */
20
class Stream implements StreamInterface
21
{
22
    /**
23
     * Bit mask to determine if the stream is a pipe
24
     *
25
     * This is octal as per header stat.h
26
     */
27
    const FSTAT_MODE_S_IFIFO = 0010000;
28
29
    /**
30
     * Resource modes
31
     *
32
     * @var  array
33
     * @link http://php.net/manual/function.fopen.php
34
     */
35
    protected static $modes = [
36
        'readable' => ['r', 'r+', 'w+', 'a+', 'x+', 'c+'],
37
        'writable' => ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+'],
38
    ];
39
40
    /**
41
     * The underlying stream resource
42
     *
43
     * @var resource
44
     */
45
    protected $stream;
46
47
    /**
48
     * Stream metadata
49
     *
50
     * @var array
51
     */
52
    protected $meta;
53
54
    /**
55
     * Is this stream readable?
56
     *
57
     * @var bool
58
     */
59
    protected $readable;
60
61
    /**
62
     * Is this stream writable?
63
     *
64
     * @var bool
65
     */
66
    protected $writable;
67
68
    /**
69
     * Is this stream seekable?
70
     *
71
     * @var bool
72
     */
73
    protected $seekable;
74
75
    /**
76
     * The size of the stream if known
77
     *
78
     * @var null|int
79
     */
80
    protected $size;
81
82
    /**
83
     * Is this stream a pipe?
84
     *
85
     * @var bool
86
     */
87
    protected $isPipe;
88
89
    /**
90
     * Create a new Stream.
91
     *
92
     * @param  resource $stream A PHP resource handle.
93
     *
94
     * @throws InvalidArgumentException If argument is not a resource.
95
     */
96
    public function __construct($stream)
97
    {
98
        $this->attach($stream);
99
    }
100
101
    /**
102
     * Get stream metadata as an associative array or retrieve a specific key.
103
     *
104
     * The keys returned are identical to the keys returned from PHP's
105
     * stream_get_meta_data() function.
106
     *
107
     * @link http://php.net/manual/en/function.stream-get-meta-data.php
108
     *
109
     * @param string $key Specific metadata to retrieve.
110
     *
111
     * @return array|mixed|null Returns an associative array if no key is
112
     *     provided. Returns a specific key value if a key is provided and the
113
     *     value is found, or null if the key is not found.
114
     */
115
    public function getMetadata($key = null)
116
    {
117
        $this->meta = stream_get_meta_data($this->stream);
118
        if (is_null($key) === true) {
119
            return $this->meta;
120
        }
121
122
        return isset($this->meta[$key]) ? $this->meta[$key] : null;
123
    }
124
125
    /**
126
     * Is a resource attached to this stream?
127
     *
128
     * Note: This method is not part of the PSR-7 standard.
129
     *
130
     * @return bool
131
     */
132
    protected function isAttached()
133
    {
134
        return is_resource($this->stream);
135
    }
136
137
    /**
138
     * Attach new resource to this object.
139
     *
140
     * Note: This method is not part of the PSR-7 standard.
141
     *
142
     * @param resource $newStream A PHP resource handle.
143
     *
144
     * @throws InvalidArgumentException If argument is not a valid PHP resource.
145
     */
146
    protected function attach($newStream)
147
    {
148
        if (is_resource($newStream) === false) {
149
            throw new InvalidArgumentException(__METHOD__ . ' argument must be a valid PHP resource');
150
        }
151
152
        if ($this->isAttached() === true) {
153
            $this->detach();
154
        }
155
156
        $this->stream = $newStream;
157
    }
158
159
    /**
160
     * Separates any underlying resources from the stream.
161
     *
162
     * After the stream has been detached, the stream is in an unusable state.
163
     *
164
     * @return resource|null Underlying PHP stream, if any
165
     */
166
    public function detach()
167
    {
168
        $oldResource = $this->stream;
169
        $this->stream = null;
170
        $this->meta = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $meta.

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...
171
        $this->readable = null;
172
        $this->writable = null;
173
        $this->seekable = null;
174
        $this->size = null;
175
        $this->isPipe = null;
176
177
        return $oldResource;
178
    }
179
180
    /**
181
     * Reads all data from the stream into a string, from the beginning to end.
182
     *
183
     * This method MUST attempt to seek to the beginning of the stream before
184
     * reading data and read the stream until the end is reached.
185
     *
186
     * Warning: This could attempt to load a large amount of data into memory.
187
     *
188
     * This method MUST NOT raise an exception in order to conform with PHP's
189
     * string casting operations.
190
     *
191
     * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
192
     * @return string
193
     */
194
    public function __toString()
195
    {
196
        if (!$this->isAttached()) {
197
            return '';
198
        }
199
200
        try {
201
            $this->rewind();
202
            return $this->getContents();
203
        } catch (RuntimeException $e) {
204
            return '';
205
        }
206
    }
207
208
    /**
209
     * Closes the stream and any underlying resources.
210
     */
211
    public function close()
212
    {
213
        if ($this->isAttached() === true) {
214
            if ($this->isPipe()) {
215
                pclose($this->stream);
216
            } else {
217
                fclose($this->stream);
218
            }
219
        }
220
221
        $this->detach();
222
    }
223
224
    /**
225
     * Get the size of the stream if known.
226
     *
227
     * @return int|null Returns the size in bytes if known, or null if unknown.
228
     */
229
    public function getSize()
230
    {
231
        if (!$this->size && $this->isAttached() === true) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->size of type null|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
232
            $stats = fstat($this->stream);
233
            $this->size = isset($stats['size']) && !$this->isPipe() ? $stats['size'] : null;
234
        }
235
236
        return $this->size;
237
    }
238
239
    /**
240
     * Returns the current position of the file read/write pointer
241
     *
242
     * @return int Position of the file pointer
243
     *
244
     * @throws RuntimeException on error.
245
     */
246
    public function tell()
247
    {
248
        if (!$this->isAttached() || ($position = ftell($this->stream)) === false || $this->isPipe()) {
249
            throw new RuntimeException('Could not get the position of the pointer in stream');
250
        }
251
252
        return $position;
253
    }
254
255
    /**
256
     * Returns true if the stream is at the end of the stream.
257
     *
258
     * @return bool
259
     */
260
    public function eof()
261
    {
262
        return $this->isAttached() ? feof($this->stream) : true;
263
    }
264
265
    /**
266
     * Returns whether or not the stream is readable.
267
     *
268
     * @return bool
269
     */
270
    public function isReadable()
271
    {
272 View Code Duplication
        if ($this->readable === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
273
            if ($this->isPipe()) {
274
                $this->readable = true;
275
            } else {
276
                $this->readable = false;
277
                if ($this->isAttached()) {
278
                    $meta = $this->getMetadata();
279
                    foreach (self::$modes['readable'] as $mode) {
280
                        if (strpos($meta['mode'], $mode) === 0) {
281
                            $this->readable = true;
282
                            break;
283
                        }
284
                    }
285
                }
286
            }
287
        }
288
289
        return $this->readable;
290
    }
291
292
    /**
293
     * Returns whether or not the stream is writable.
294
     *
295
     * @return bool
296
     */
297
    public function isWritable()
298
    {
299 View Code Duplication
        if ($this->writable === null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
300
            $this->writable = false;
301
            if ($this->isAttached()) {
302
                $meta = $this->getMetadata();
303
                foreach (self::$modes['writable'] as $mode) {
304
                    if (strpos($meta['mode'], $mode) === 0) {
305
                        $this->writable = true;
306
                        break;
307
                    }
308
                }
309
            }
310
        }
311
312
        return $this->writable;
313
    }
314
315
    /**
316
     * Returns whether or not the stream is seekable.
317
     *
318
     * @return bool
319
     */
320
    public function isSeekable()
321
    {
322
        if ($this->seekable === null) {
323
            $this->seekable = false;
324
            if ($this->isAttached()) {
325
                $meta = $this->getMetadata();
326
                $this->seekable = !$this->isPipe() && $meta['seekable'];
327
            }
328
        }
329
330
        return $this->seekable;
331
    }
332
333
    /**
334
     * Seek to a position in the stream.
335
     *
336
     * @link http://www.php.net/manual/en/function.fseek.php
337
     *
338
     * @param int $offset Stream offset
339
     * @param int $whence Specifies how the cursor position will be calculated
340
     *     based on the seek offset. Valid values are identical to the built-in
341
     *     PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to
342
     *     offset bytes SEEK_CUR: Set position to current location plus offset
343
     *     SEEK_END: Set position to end-of-stream plus offset.
344
     *
345
     * @throws RuntimeException on failure.
346
     */
347
    public function seek($offset, $whence = SEEK_SET)
348
    {
349
        // Note that fseek returns 0 on success!
350
        if (!$this->isSeekable() || fseek($this->stream, $offset, $whence) === -1) {
351
            throw new RuntimeException('Could not seek in stream');
352
        }
353
    }
354
355
    /**
356
     * Seek to the beginning of the stream.
357
     *
358
     * If the stream is not seekable, this method will raise an exception;
359
     * otherwise, it will perform a seek(0).
360
     *
361
     * @see seek()
362
     *
363
     * @link http://www.php.net/manual/en/function.fseek.php
364
     *
365
     * @throws RuntimeException on failure.
366
     */
367
    public function rewind()
368
    {
369
        if (!$this->isSeekable() || rewind($this->stream) === false) {
370
            throw new RuntimeException('Could not rewind stream');
371
        }
372
    }
373
374
    /**
375
     * Read data from the stream.
376
     *
377
     * @param int $length Read up to $length bytes from the object and return
378
     *     them. Fewer than $length bytes may be returned if underlying stream
379
     *     call returns fewer bytes.
380
     *
381
     * @return string Returns the data read from the stream, or an empty string
382
     *     if no bytes are available.
383
     *
384
     * @throws RuntimeException if an error occurs.
385
     */
386
    public function read($length)
387
    {
388
        if (!$this->isReadable() || ($data = fread($this->stream, $length)) === false) {
389
            throw new RuntimeException('Could not read from stream');
390
        }
391
392
        return $data;
393
    }
394
395
    /**
396
     * Write data to the stream.
397
     *
398
     * @param string $string The string that is to be written.
399
     *
400
     * @return int Returns the number of bytes written to the stream.
401
     *
402
     * @throws RuntimeException on failure.
403
     */
404
    public function write($string)
405
    {
406
        if (!$this->isWritable() || ($written = fwrite($this->stream, $string)) === false) {
407
            throw new RuntimeException('Could not write to stream');
408
        }
409
410
        // reset size so that it will be recalculated on next call to getSize()
411
        $this->size = null;
412
413
        return $written;
414
    }
415
416
    /**
417
     * Returns the remaining contents in a string
418
     *
419
     * @return string
420
     *
421
     * @throws RuntimeException if unable to read or an error occurs while
422
     *     reading.
423
     */
424
    public function getContents()
425
    {
426
        if (!$this->isReadable() || ($contents = stream_get_contents($this->stream)) === false) {
427
            throw new RuntimeException('Could not get contents of stream');
428
        }
429
430
        return $contents;
431
    }
432
433
    /**
434
     * Returns whether or not the stream is a pipe.
435
     *
436
     * @return bool
437
     */
438
    public function isPipe()
439
    {
440
        if ($this->isPipe === null) {
441
            $this->isPipe = false;
442
            if ($this->isAttached()) {
443
                $mode = fstat($this->stream)['mode'];
444
                $this->isPipe = ($mode & self::FSTAT_MODE_S_IFIFO) !== 0;
445
            }
446
        }
447
448
        return $this->isPipe;
449
    }
450
}
451