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:45
created

Stream::isPipe()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
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
     * This is octal as per header stat.h
24
     */
25
    const FSTAT_MODE_S_IFIFO = 0010000;
26
27
    /**
28
     * Resource modes
29
     *
30
     * @var  array
31
     * @link http://php.net/manual/function.fopen.php
32
     */
33
    protected static $modes = [
34
        'readable' => ['r', 'r+', 'w+', 'a+', 'x+', 'c+'],
35
        'writable' => ['r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+'],
36
    ];
37
38
    /**
39
     * The underlying stream resource
40
     *
41
     * @var resource
42
     */
43
    protected $stream;
44
45
    /**
46
     * Stream metadata
47
     *
48
     * @var array
49
     */
50
    protected $meta;
51
52
    /**
53
     * Is this stream readable?
54
     *
55
     * @var bool
56
     */
57
    protected $readable;
58
59
    /**
60
     * Is this stream writable?
61
     *
62
     * @var bool
63
     */
64
    protected $writable;
65
66
    /**
67
     * Is this stream seekable?
68
     *
69
     * @var bool
70
     */
71
    protected $seekable;
72
73
    /**
74
     * The size of the stream if known
75
     *
76
     * @var null|int
77
     */
78
    protected $size;
79
80
    /**
81
     * Is this stream a pipe?
82
     *
83
     * @var bool
84
     */
85
    protected $pipe;
86
87
    /**
88
     * Create a new Stream.
89
     *
90
     * @param  resource $stream A PHP resource handle.
91
     *
92
     * @throws InvalidArgumentException If argument is not a resource.
93
     */
94
    public function __construct($stream)
95
    {
96
        $this->attach($stream);
97
    }
98
99
    /**
100
     * Get stream metadata as an associative array or retrieve a specific key.
101
     *
102
     * The keys returned are identical to the keys returned from PHP's
103
     * stream_get_meta_data() function.
104
     *
105
     * @link http://php.net/manual/en/function.stream-get-meta-data.php
106
     *
107
     * @param string $key Specific metadata to retrieve.
108
     *
109
     * @return array|mixed|null Returns an associative array if no key is
110
     *     provided. Returns a specific key value if a key is provided and the
111
     *     value is found, or null if the key is not found.
112
     */
113
    public function getMetadata($key = null)
114
    {
115
        $this->meta = stream_get_meta_data($this->stream);
116
        if (is_null($key) === true) {
117
            return $this->meta;
118
        }
119
120
        return isset($this->meta[$key]) ? $this->meta[$key] : null;
121
    }
122
123
    /**
124
     * Is a resource attached to this stream?
125
     *
126
     * Note: This method is not part of the PSR-7 standard.
127
     *
128
     * @return bool
129
     */
130
    protected function isAttached()
131
    {
132
        return is_resource($this->stream);
133
    }
134
135
    /**
136
     * Attach new resource to this object.
137
     *
138
     * Note: This method is not part of the PSR-7 standard.
139
     *
140
     * @param resource $newStream A PHP resource handle.
141
     *
142
     * @throws InvalidArgumentException If argument is not a valid PHP resource.
143
     */
144
    protected function attach($newStream)
145
    {
146
        if (is_resource($newStream) === false) {
147
            throw new InvalidArgumentException(__METHOD__ . ' argument must be a valid PHP resource');
148
        }
149
150
        if ($this->isAttached() === true) {
151
            $this->detach();
152
        }
153
154
        $this->stream = $newStream;
155
    }
156
157
    /**
158
     * Separates any underlying resources from the stream.
159
     *
160
     * After the stream has been detached, the stream is in an unusable state.
161
     *
162
     * @return resource|null Underlying PHP stream, if any
163
     */
164
    public function detach()
165
    {
166
        $oldResource = $this->stream;
167
        $this->stream = null;
168
        $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...
169
        $this->readable = null;
170
        $this->writable = null;
171
        $this->seekable = null;
172
        $this->size = null;
173
        $this->pipe = null;
174
175
        return $oldResource;
176
    }
177
178
    /**
179
     * Reads all data from the stream into a string, from the beginning to end.
180
     *
181
     * This method MUST attempt to seek to the beginning of the stream before
182
     * reading data and read the stream until the end is reached.
183
     *
184
     * Warning: This could attempt to load a large amount of data into memory.
185
     *
186
     * This method MUST NOT raise an exception in order to conform with PHP's
187
     * string casting operations.
188
     *
189
     * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring
190
     * @return string
191
     */
192
    public function __toString()
193
    {
194
        if (!$this->isAttached()) {
195
            return '';
196
        }
197
198
        try {
199
            $this->rewind();
200
            return $this->getContents();
201
        } catch (RuntimeException $e) {
202
            return '';
203
        }
204
    }
205
206
    /**
207
     * Closes the stream and any underlying resources.
208
     */
209
    public function close()
210
    {
211
        if ($this->isAttached() === true) {
212
            if ($this->isPipe()) {
213
                pclose($this->stream);
214
            } else {
215
                fclose($this->stream);
216
            }
217
        }
218
219
        $this->detach();
220
    }
221
222
    /**
223
     * Get the size of the stream if known.
224
     *
225
     * @return int|null Returns the size in bytes if known, or null if unknown.
226
     */
227
    public function getSize()
228
    {
229
        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...
230
            $stats = fstat($this->stream);
231
            $this->size = isset($stats['size']) && !$this->isPipe() ? $stats['size'] : null;
232
        }
233
234
        return $this->size;
235
    }
236
237
    /**
238
     * Returns the current position of the file read/write pointer
239
     *
240
     * @return int Position of the file pointer
241
     *
242
     * @throws RuntimeException on error.
243
     */
244
    public function tell()
245
    {
246
        if (!$this->isAttached() || ($position = ftell($this->stream)) === false || $this->isPipe()) {
247
            throw new RuntimeException('Could not get the position of the pointer in stream');
248
        }
249
250
        return $position;
251
    }
252
253
    /**
254
     * Returns true if the stream is at the end of the stream.
255
     *
256
     * @return bool
257
     */
258
    public function eof()
259
    {
260
        return $this->isAttached() ? feof($this->stream) : true;
261
    }
262
263
    /**
264
     * Returns whether or not the stream is readable.
265
     *
266
     * @return bool
267
     */
268
    public function isReadable()
269
    {
270 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...
271
            if ($this->isPipe()) {
272
                $this->readable = true;
273
            } else {
274
                $this->readable = false;
275
                if ($this->isAttached()) {
276
                    $meta = $this->getMetadata();
277
                    foreach (self::$modes['readable'] as $mode) {
278
                        if (strpos($meta['mode'], $mode) === 0) {
279
                            $this->readable = true;
280
                            break;
281
                        }
282
                    }
283
                }
284
            }
285
        }
286
287
        return $this->readable;
288
    }
289
290
    /**
291
     * Returns whether or not the stream is writable.
292
     *
293
     * @return bool
294
     */
295
    public function isWritable()
296
    {
297 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...
298
            $this->writable = false;
299
            if ($this->isAttached()) {
300
                $meta = $this->getMetadata();
301
                foreach (self::$modes['writable'] as $mode) {
302
                    if (strpos($meta['mode'], $mode) === 0) {
303
                        $this->writable = true;
304
                        break;
305
                    }
306
                }
307
            }
308
        }
309
310
        return $this->writable;
311
    }
312
313
    /**
314
     * Returns whether or not the stream is seekable.
315
     *
316
     * @return bool
317
     */
318
    public function isSeekable()
319
    {
320
        if ($this->seekable === null) {
321
            $this->seekable = false;
322
            if ($this->isAttached()) {
323
                $meta = $this->getMetadata();
324
                $this->seekable = !$this->isPipe() && $meta['seekable'];
325
            }
326
        }
327
328
        return $this->seekable;
329
    }
330
331
    /**
332
     * Seek to a position in the stream.
333
     *
334
     * @link http://www.php.net/manual/en/function.fseek.php
335
     *
336
     * @param int $offset Stream offset
337
     * @param int $whence Specifies how the cursor position will be calculated
338
     *     based on the seek offset. Valid values are identical to the built-in
339
     *     PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to
340
     *     offset bytes SEEK_CUR: Set position to current location plus offset
341
     *     SEEK_END: Set position to end-of-stream plus offset.
342
     *
343
     * @throws RuntimeException on failure.
344
     */
345
    public function seek($offset, $whence = SEEK_SET)
346
    {
347
        // Note that fseek returns 0 on success!
348
        if (!$this->isSeekable() || fseek($this->stream, $offset, $whence) === -1) {
349
            throw new RuntimeException('Could not seek in stream');
350
        }
351
    }
352
353
    /**
354
     * Seek to the beginning of the stream.
355
     *
356
     * If the stream is not seekable, this method will raise an exception;
357
     * otherwise, it will perform a seek(0).
358
     *
359
     * @see seek()
360
     *
361
     * @link http://www.php.net/manual/en/function.fseek.php
362
     *
363
     * @throws RuntimeException on failure.
364
     */
365
    public function rewind()
366
    {
367
        if (!$this->isSeekable() || rewind($this->stream) === false) {
368
            throw new RuntimeException('Could not rewind stream');
369
        }
370
    }
371
372
    /**
373
     * Read data from the stream.
374
     *
375
     * @param int $length Read up to $length bytes from the object and return
376
     *     them. Fewer than $length bytes may be returned if underlying stream
377
     *     call returns fewer bytes.
378
     *
379
     * @return string Returns the data read from the stream, or an empty string
380
     *     if no bytes are available.
381
     *
382
     * @throws RuntimeException if an error occurs.
383
     */
384
    public function read($length)
385
    {
386
        if (!$this->isReadable() || ($data = fread($this->stream, $length)) === false) {
387
            throw new RuntimeException('Could not read from stream');
388
        }
389
390
        return $data;
391
    }
392
393
    /**
394
     * Write data to the stream.
395
     *
396
     * @param string $string The string that is to be written.
397
     *
398
     * @return int Returns the number of bytes written to the stream.
399
     *
400
     * @throws RuntimeException on failure.
401
     */
402
    public function write($string)
403
    {
404
        if (!$this->isWritable() || ($written = fwrite($this->stream, $string)) === false) {
405
            throw new RuntimeException('Could not write to stream');
406
        }
407
408
        // reset size so that it will be recalculated on next call to getSize()
409
        $this->size = null;
410
411
        return $written;
412
    }
413
414
    /**
415
     * Returns the remaining contents in a string
416
     *
417
     * @return string
418
     *
419
     * @throws RuntimeException if unable to read or an error occurs while
420
     *     reading.
421
     */
422
    public function getContents()
423
    {
424
        if (!$this->isReadable() || ($contents = stream_get_contents($this->stream)) === false) {
425
            throw new RuntimeException('Could not get contents of stream');
426
        }
427
428
        return $contents;
429
    }
430
    
431
    /**
432
     * Returns whether or not the stream is a pipe.
433
     *
434
     * @return bool
435
     */
436
    public function isPipe()
437
    {
438
        if ($this->pipe === null) {
439
            $this->pipe = false;
440
            if ($this->isAttached()) {
441
                $mode = fstat($this->stream)['mode'];
442
                $this->pipe = ($mode & self::FSTAT_MODE_S_IFIFO) !== 0;
443
            }
444
        }
445
        
446
        return $this->pipe;
447
    }
448
}
449