Passed
Pull Request — master (#31)
by Anatoly
39:16
created
functions/server_request_method.php 1 patch
Indentation   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -23,7 +23,7 @@
 block discarded – undo
23 23
  */
24 24
 function server_request_method(?array $serverParams = null): string
25 25
 {
26
-    $serverParams ??= $_SERVER;
26
+	$serverParams ??= $_SERVER;
27 27
 
28
-    return $serverParams['REQUEST_METHOD'] ?? Request::METHOD_GET;
28
+	return $serverParams['REQUEST_METHOD'] ?? Request::METHOD_GET;
29 29
 }
Please login to merge, or discard this patch.
functions/server_request_protocol_version.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -29,24 +29,24 @@
 block discarded – undo
29 29
  */
30 30
 function server_request_protocol_version(?array $serverParams = null): string
31 31
 {
32
-    $serverParams ??= $_SERVER;
32
+	$serverParams ??= $_SERVER;
33 33
 
34
-    if (!isset($serverParams['SERVER_PROTOCOL'])) {
35
-        return '1.1';
36
-    }
34
+	if (!isset($serverParams['SERVER_PROTOCOL'])) {
35
+		return '1.1';
36
+	}
37 37
 
38
-    // "HTTP" "/" 1*digit "." 1*digit
39
-    sscanf($serverParams['SERVER_PROTOCOL'], 'HTTP/%d.%d', $major, $minor);
38
+	// "HTTP" "/" 1*digit "." 1*digit
39
+	sscanf($serverParams['SERVER_PROTOCOL'], 'HTTP/%d.%d', $major, $minor);
40 40
 
41
-    // e.g.: HTTP/1.1
42
-    if (isset($minor)) {
43
-        return sprintf('%d.%d', $major, $minor);
44
-    }
41
+	// e.g.: HTTP/1.1
42
+	if (isset($minor)) {
43
+		return sprintf('%d.%d', $major, $minor);
44
+	}
45 45
 
46
-    // e.g.: HTTP/2
47
-    if (isset($major)) {
48
-        return sprintf('%d', $major);
49
-    }
46
+	// e.g.: HTTP/2
47
+	if (isset($major)) {
48
+		return sprintf('%d', $major);
49
+	}
50 50
 
51
-    return '1.1';
51
+	return '1.1';
52 52
 }
Please login to merge, or discard this patch.
functions/server_request_uri.php 2 patches
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -32,35 +32,35 @@
 block discarded – undo
32 32
  */
33 33
 function server_request_uri(?array $serverParams = null): UriInterface
34 34
 {
35
-    $serverParams ??= $_SERVER;
35
+	$serverParams ??= $_SERVER;
36 36
 
37
-    if (array_key_exists('HTTPS', $serverParams)) {
38
-        if (! ('off' === $serverParams['HTTPS'])) {
39
-            $scheme = 'https://';
40
-        }
41
-    }
37
+	if (array_key_exists('HTTPS', $serverParams)) {
38
+		if (! ('off' === $serverParams['HTTPS'])) {
39
+			$scheme = 'https://';
40
+		}
41
+	}
42 42
 
43
-    if (array_key_exists('HTTP_HOST', $serverParams)) {
44
-        $host = $serverParams['HTTP_HOST'];
45
-    } elseif (array_key_exists('SERVER_NAME', $serverParams)) {
46
-        $host = $serverParams['SERVER_NAME'];
47
-        if (array_key_exists('SERVER_PORT', $serverParams)) {
48
-            $host .= ':' . $serverParams['SERVER_PORT'];
49
-        }
50
-    }
43
+	if (array_key_exists('HTTP_HOST', $serverParams)) {
44
+		$host = $serverParams['HTTP_HOST'];
45
+	} elseif (array_key_exists('SERVER_NAME', $serverParams)) {
46
+		$host = $serverParams['SERVER_NAME'];
47
+		if (array_key_exists('SERVER_PORT', $serverParams)) {
48
+			$host .= ':' . $serverParams['SERVER_PORT'];
49
+		}
50
+	}
51 51
 
52
-    if (array_key_exists('REQUEST_URI', $serverParams)) {
53
-        $target = $serverParams['REQUEST_URI'];
54
-    } elseif (array_key_exists('PHP_SELF', $serverParams)) {
55
-        $target = $serverParams['PHP_SELF'];
56
-        if (array_key_exists('QUERY_STRING', $serverParams)) {
57
-            $target .= '?' . $serverParams['QUERY_STRING'];
58
-        }
59
-    }
52
+	if (array_key_exists('REQUEST_URI', $serverParams)) {
53
+		$target = $serverParams['REQUEST_URI'];
54
+	} elseif (array_key_exists('PHP_SELF', $serverParams)) {
55
+		$target = $serverParams['PHP_SELF'];
56
+		if (array_key_exists('QUERY_STRING', $serverParams)) {
57
+			$target .= '?' . $serverParams['QUERY_STRING'];
58
+		}
59
+	}
60 60
 
61
-    return new Uri(
62
-        ($scheme ?? 'http://') .
63
-        ($host ?? 'localhost') .
64
-        ($target ?? '/')
65
-    );
61
+	return new Uri(
62
+		($scheme ?? 'http://') .
63
+		($host ?? 'localhost') .
64
+		($target ?? '/')
65
+	);
66 66
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -35,7 +35,7 @@
 block discarded – undo
35 35
     $serverParams ??= $_SERVER;
36 36
 
37 37
     if (array_key_exists('HTTPS', $serverParams)) {
38
-        if (! ('off' === $serverParams['HTTPS'])) {
38
+        if (!('off' === $serverParams['HTTPS'])) {
39 39
             $scheme = 'https://';
40 40
         }
41 41
     }
Please login to merge, or discard this patch.
src/Response/JsonResponse.php 1 patch
Indentation   +46 added lines, -46 removed lines patch added patch discarded remove patch
@@ -36,57 +36,57 @@
 block discarded – undo
36 36
 final class JsonResponse extends Response
37 37
 {
38 38
 
39
-    /**
40
-     * Constructor of the class
41
-     *
42
-     * @param int $statusCode
43
-     * @param mixed $data
44
-     * @param int $flags
45
-     * @param int $depth
46
-     *
47
-     * @throws InvalidArgumentException
48
-     */
49
-    public function __construct(int $statusCode, $data, int $flags = 0, int $depth = 512)
50
-    {
51
-        parent::__construct($statusCode);
39
+	/**
40
+	 * Constructor of the class
41
+	 *
42
+	 * @param int $statusCode
43
+	 * @param mixed $data
44
+	 * @param int $flags
45
+	 * @param int $depth
46
+	 *
47
+	 * @throws InvalidArgumentException
48
+	 */
49
+	public function __construct(int $statusCode, $data, int $flags = 0, int $depth = 512)
50
+	{
51
+		parent::__construct($statusCode);
52 52
 
53
-        $this->setBody($this->createBody($data, $flags, $depth));
53
+		$this->setBody($this->createBody($data, $flags, $depth));
54 54
 
55
-        $this->setHeader('Content-Type', 'application/json; charset=utf-8');
56
-    }
55
+		$this->setHeader('Content-Type', 'application/json; charset=utf-8');
56
+	}
57 57
 
58
-    /**
59
-     * Creates the response body from the given JSON data
60
-     *
61
-     * @param mixed $data
62
-     * @param int $flags
63
-     * @param int $depth
64
-     *
65
-     * @return StreamInterface
66
-     *
67
-     * @throws InvalidArgumentException
68
-     */
69
-    private function createBody($data, int $flags, int $depth): StreamInterface
70
-    {
71
-        if ($data instanceof StreamInterface) {
72
-            return $data;
73
-        }
58
+	/**
59
+	 * Creates the response body from the given JSON data
60
+	 *
61
+	 * @param mixed $data
62
+	 * @param int $flags
63
+	 * @param int $depth
64
+	 *
65
+	 * @return StreamInterface
66
+	 *
67
+	 * @throws InvalidArgumentException
68
+	 */
69
+	private function createBody($data, int $flags, int $depth): StreamInterface
70
+	{
71
+		if ($data instanceof StreamInterface) {
72
+			return $data;
73
+		}
74 74
 
75
-        $flags |= JSON_THROW_ON_ERROR;
75
+		$flags |= JSON_THROW_ON_ERROR;
76 76
 
77
-        try {
78
-            $payload = json_encode($data, $flags, $depth);
79
-        } catch (JsonException $e) {
80
-            throw new InvalidArgumentException(sprintf(
81
-                'Unable to create JSON response due to invalid JSON data: %s',
82
-                $e->getMessage()
83
-            ), 0, $e);
84
-        }
77
+		try {
78
+			$payload = json_encode($data, $flags, $depth);
79
+		} catch (JsonException $e) {
80
+			throw new InvalidArgumentException(sprintf(
81
+				'Unable to create JSON response due to invalid JSON data: %s',
82
+				$e->getMessage()
83
+			), 0, $e);
84
+		}
85 85
 
86
-        $stream = new PhpTempStream('r+b');
87
-        $stream->write($payload);
88
-        $stream->rewind();
86
+		$stream = new PhpTempStream('r+b');
87
+		$stream->write($payload);
88
+		$stream->rewind();
89 89
 
90
-        return $stream;
91
-    }
90
+		return $stream;
91
+	}
92 92
 }
Please login to merge, or discard this patch.
src/Stream/PhpMemoryStream.php 1 patch
Indentation   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -27,13 +27,13 @@
 block discarded – undo
27 27
 final class PhpMemoryStream extends Stream
28 28
 {
29 29
 
30
-    /**
31
-     * Constructor of the class
32
-     *
33
-     * @param string $mode
34
-     */
35
-    public function __construct(string $mode = 'r+b')
36
-    {
37
-        parent::__construct(fopen('php://memory', $mode));
38
-    }
30
+	/**
31
+	 * Constructor of the class
32
+	 *
33
+	 * @param string $mode
34
+	 */
35
+	public function __construct(string $mode = 'r+b')
36
+	{
37
+		parent::__construct(fopen('php://memory', $mode));
38
+	}
39 39
 }
Please login to merge, or discard this patch.
src/Stream/PhpInputStream.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -28,18 +28,18 @@
 block discarded – undo
28 28
 final class PhpInputStream extends Stream
29 29
 {
30 30
 
31
-    /**
32
-     * Constructor of the class
33
-     */
34
-    public function __construct()
35
-    {
36
-        $input = fopen('php://input', 'rb');
37
-        $resource = fopen('php://temp', 'r+b');
31
+	/**
32
+	 * Constructor of the class
33
+	 */
34
+	public function __construct()
35
+	{
36
+		$input = fopen('php://input', 'rb');
37
+		$resource = fopen('php://temp', 'r+b');
38 38
 
39
-        stream_copy_to_stream($input, $resource);
39
+		stream_copy_to_stream($input, $resource);
40 40
 
41
-        parent::__construct($resource);
41
+		parent::__construct($resource);
42 42
 
43
-        $this->rewind();
44
-    }
43
+		$this->rewind();
44
+	}
45 45
 }
Please login to merge, or discard this patch.
src/Stream/FileStream.php 1 patch
Indentation   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -31,30 +31,30 @@
 block discarded – undo
31 31
 final class FileStream extends Stream
32 32
 {
33 33
 
34
-    /**
35
-     * Constructor of the class
36
-     *
37
-     * @param string $filename
38
-     * @param string $mode
39
-     *
40
-     * @throws RuntimeException
41
-     */
42
-    public function __construct(string $filename, string $mode)
43
-    {
44
-        try {
45
-            $resource = fopen($filename, $mode);
46
-        } catch (Throwable $e) {
47
-            $resource = false;
48
-        }
49
-
50
-        if (!is_resource($resource)) {
51
-            throw new RuntimeException(sprintf(
52
-                'Unable to open the file "%s" in the mode "%s"',
53
-                $filename,
54
-                $mode
55
-            ));
56
-        }
57
-
58
-        parent::__construct($resource);
59
-    }
34
+	/**
35
+	 * Constructor of the class
36
+	 *
37
+	 * @param string $filename
38
+	 * @param string $mode
39
+	 *
40
+	 * @throws RuntimeException
41
+	 */
42
+	public function __construct(string $filename, string $mode)
43
+	{
44
+		try {
45
+			$resource = fopen($filename, $mode);
46
+		} catch (Throwable $e) {
47
+			$resource = false;
48
+		}
49
+
50
+		if (!is_resource($resource)) {
51
+			throw new RuntimeException(sprintf(
52
+				'Unable to open the file "%s" in the mode "%s"',
53
+				$filename,
54
+				$mode
55
+			));
56
+		}
57
+
58
+		parent::__construct($resource);
59
+	}
60 60
 }
Please login to merge, or discard this patch.
src/Stream/TmpfileStream.php 1 patch
Indentation   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -35,23 +35,23 @@
 block discarded – undo
35 35
 final class TmpfileStream extends Stream
36 36
 {
37 37
 
38
-    /**
39
-     * Constructor of the class
40
-     *
41
-     * @throws RuntimeException
42
-     */
43
-    public function __construct()
44
-    {
45
-        $dirname = sys_get_temp_dir();
46
-        if (!is_writable($dirname)) {
47
-            throw new RuntimeException('Temporary files directory is not writable');
48
-        }
49
-
50
-        $resource = tmpfile();
51
-        if (!is_resource($resource)) {
52
-            throw new RuntimeException('Temporary file cannot be created or opened');
53
-        }
54
-
55
-        parent::__construct($resource);
56
-    }
38
+	/**
39
+	 * Constructor of the class
40
+	 *
41
+	 * @throws RuntimeException
42
+	 */
43
+	public function __construct()
44
+	{
45
+		$dirname = sys_get_temp_dir();
46
+		if (!is_writable($dirname)) {
47
+			throw new RuntimeException('Temporary files directory is not writable');
48
+		}
49
+
50
+		$resource = tmpfile();
51
+		if (!is_resource($resource)) {
52
+			throw new RuntimeException('Temporary file cannot be created or opened');
53
+		}
54
+
55
+		parent::__construct($resource);
56
+	}
57 57
 }
Please login to merge, or discard this patch.
src/Stream.php 1 patch
Indentation   +382 added lines, -382 removed lines patch added patch discarded remove patch
@@ -47,386 +47,386 @@
 block discarded – undo
47 47
 class Stream implements StreamInterface
48 48
 {
49 49
 
50
-    /**
51
-     * The stream resource
52
-     *
53
-     * @var resource|null
54
-     */
55
-    private $resource;
56
-
57
-    /**
58
-     * Signals to close the stream on destruction
59
-     *
60
-     * @var bool
61
-     */
62
-    private $autoClose;
63
-
64
-    /**
65
-     * Constructor of the class
66
-     *
67
-     * @param mixed $resource
68
-     * @param bool $autoClose
69
-     *
70
-     * @throws InvalidArgumentException
71
-     *         If the stream cannot be initialized with the resource.
72
-     */
73
-    public function __construct($resource, bool $autoClose = true)
74
-    {
75
-        if (!is_resource($resource)) {
76
-            throw new InvalidArgumentException('Unexpected stream resource');
77
-        }
78
-
79
-        $this->resource = $resource;
80
-        $this->autoClose = $autoClose;
81
-    }
82
-
83
-    /**
84
-     * Creates a stream
85
-     *
86
-     * @param mixed $resource
87
-     *
88
-     * @return StreamInterface
89
-     *
90
-     * @throws InvalidArgumentException
91
-     *         If the stream cannot be initialized with the resource.
92
-     */
93
-    public static function create($resource): StreamInterface
94
-    {
95
-        if ($resource instanceof StreamInterface) {
96
-            return $resource;
97
-        }
98
-
99
-        return new self($resource);
100
-    }
101
-
102
-    /**
103
-     * Destructor of the class
104
-     */
105
-    public function __destruct()
106
-    {
107
-        if ($this->autoClose) {
108
-            $this->close();
109
-        }
110
-    }
111
-
112
-    /**
113
-     * Detaches a resource from the stream
114
-     *
115
-     * Returns NULL if the stream already without a resource.
116
-     *
117
-     * @return resource|null
118
-     */
119
-    public function detach()
120
-    {
121
-        $resource = $this->resource;
122
-        $this->resource = null;
123
-
124
-        return $resource;
125
-    }
126
-
127
-    /**
128
-     * Closes the stream
129
-     *
130
-     * @link http://php.net/manual/en/function.fclose.php
131
-     *
132
-     * @return void
133
-     */
134
-    public function close(): void
135
-    {
136
-        $resource = $this->detach();
137
-        if (!is_resource($resource)) {
138
-            return;
139
-        }
140
-
141
-        fclose($resource);
142
-    }
143
-
144
-    /**
145
-     * Checks if the end of the stream is reached
146
-     *
147
-     * @link http://php.net/manual/en/function.feof.php
148
-     *
149
-     * @return bool
150
-     */
151
-    public function eof(): bool
152
-    {
153
-        if (!is_resource($this->resource)) {
154
-            return true;
155
-        }
156
-
157
-        return feof($this->resource);
158
-    }
159
-
160
-    /**
161
-     * Gets the stream pointer position
162
-     *
163
-     * @link http://php.net/manual/en/function.ftell.php
164
-     *
165
-     * @return int
166
-     *
167
-     * @throws RuntimeException
168
-     */
169
-    public function tell(): int
170
-    {
171
-        if (!is_resource($this->resource)) {
172
-            throw new RuntimeException('The stream without a resource so the operation is not possible');
173
-        }
174
-
175
-        $result = ftell($this->resource);
176
-        if ($result === false) {
177
-            throw new RuntimeException('Unable to get the stream pointer position');
178
-        }
179
-
180
-        return $result;
181
-    }
182
-
183
-    /**
184
-     * Checks if the stream is seekable
185
-     *
186
-     * @return bool
187
-     */
188
-    public function isSeekable(): bool
189
-    {
190
-        if (!is_resource($this->resource)) {
191
-            return false;
192
-        }
193
-
194
-        /** @var array{seekable: bool} */
195
-        $metadata = stream_get_meta_data($this->resource);
196
-
197
-        return $metadata['seekable'];
198
-    }
199
-
200
-    /**
201
-     * Moves the stream pointer to the beginning
202
-     *
203
-     * @return void
204
-     *
205
-     * @throws RuntimeException
206
-     */
207
-    public function rewind(): void
208
-    {
209
-        $this->seek(0);
210
-    }
211
-
212
-    /**
213
-     * Moves the stream pointer to the given position
214
-     *
215
-     * @link http://php.net/manual/en/function.fseek.php
216
-     *
217
-     * @param int $offset
218
-     * @param int $whence
219
-     *
220
-     * @return void
221
-     *
222
-     * @throws RuntimeException
223
-     */
224
-    public function seek($offset, $whence = SEEK_SET): void
225
-    {
226
-        if (!is_resource($this->resource)) {
227
-            throw new RuntimeException('The stream without a resource so the operation is not possible');
228
-        }
229
-
230
-        if (!$this->isSeekable()) {
231
-            throw new RuntimeException('Stream is not seekable');
232
-        }
233
-
234
-        $result = fseek($this->resource, $offset, $whence);
235
-        if ($result !== 0) {
236
-            throw new RuntimeException('Unable to move the stream pointer position');
237
-        }
238
-    }
239
-
240
-    /**
241
-     * Checks if the stream is writable
242
-     *
243
-     * @return bool
244
-     */
245
-    public function isWritable(): bool
246
-    {
247
-        if (!is_resource($this->resource)) {
248
-            return false;
249
-        }
250
-
251
-        /** @var array{mode: string} */
252
-        $metadata = stream_get_meta_data($this->resource);
253
-
254
-        return strpbrk($metadata['mode'], '+acwx') !== false;
255
-    }
256
-
257
-    /**
258
-     * Writes the given string to the stream
259
-     *
260
-     * Returns the number of bytes written to the stream.
261
-     *
262
-     * @link http://php.net/manual/en/function.fwrite.php
263
-     *
264
-     * @param string $string
265
-     *
266
-     * @return int
267
-     *
268
-     * @throws RuntimeException
269
-     */
270
-    public function write($string): int
271
-    {
272
-        if (!is_resource($this->resource)) {
273
-            throw new RuntimeException('The stream without a resource so the operation is not possible');
274
-        }
275
-
276
-        if (!$this->isWritable()) {
277
-            throw new RuntimeException('Stream is not writable');
278
-        }
279
-
280
-        $result = fwrite($this->resource, $string);
281
-        if ($result === false) {
282
-            throw new RuntimeException('Unable to write to the stream');
283
-        }
284
-
285
-        return $result;
286
-    }
287
-
288
-    /**
289
-     * Checks if the stream is readable
290
-     *
291
-     * @return bool
292
-     */
293
-    public function isReadable(): bool
294
-    {
295
-        if (!is_resource($this->resource)) {
296
-            return false;
297
-        }
298
-
299
-        /** @var array{mode: string} */
300
-        $metadata = stream_get_meta_data($this->resource);
301
-
302
-        return strpbrk($metadata['mode'], '+r') !== false;
303
-    }
304
-
305
-    /**
306
-     * Reads the given number of bytes from the stream
307
-     *
308
-     * @link http://php.net/manual/en/function.fread.php
309
-     *
310
-     * @param int $length
311
-     *
312
-     * @return string
313
-     *
314
-     * @throws RuntimeException
315
-     */
316
-    public function read($length): string
317
-    {
318
-        if (!is_resource($this->resource)) {
319
-            throw new RuntimeException('The stream without a resource so the operation is not possible');
320
-        }
321
-
322
-        if (!$this->isReadable()) {
323
-            throw new RuntimeException('Stream is not readable');
324
-        }
325
-
326
-        $result = fread($this->resource, $length);
327
-        if ($result === false) {
328
-            throw new RuntimeException('Unable to read from the stream');
329
-        }
330
-
331
-        return $result;
332
-    }
333
-
334
-    /**
335
-     * Reads the remainder of the stream
336
-     *
337
-     * @link http://php.net/manual/en/function.stream-get-contents.php
338
-     *
339
-     * @return string
340
-     *
341
-     * @throws RuntimeException
342
-     */
343
-    public function getContents(): string
344
-    {
345
-        if (!is_resource($this->resource)) {
346
-            throw new RuntimeException('The stream without a resource so the operation is not possible');
347
-        }
348
-
349
-        if (!$this->isReadable()) {
350
-            throw new RuntimeException('Stream is not readable');
351
-        }
352
-
353
-        $result = stream_get_contents($this->resource);
354
-        if ($result === false) {
355
-            throw new RuntimeException('Unable to read the remainder of the stream');
356
-        }
357
-
358
-        return $result;
359
-    }
360
-
361
-    /**
362
-     * Gets the stream metadata
363
-     *
364
-     * @link http://php.net/manual/en/function.stream-get-meta-data.php
365
-     *
366
-     * @param string|null $key
367
-     *
368
-     * @return mixed
369
-     */
370
-    public function getMetadata($key = null)
371
-    {
372
-        if (!is_resource($this->resource)) {
373
-            return null;
374
-        }
375
-
376
-        $metadata = stream_get_meta_data($this->resource);
377
-        if ($key === null) {
378
-            return $metadata;
379
-        }
380
-
381
-        return $metadata[$key] ?? null;
382
-    }
383
-
384
-    /**
385
-     * Gets the stream size
386
-     *
387
-     * Returns NULL if the stream without a resource,
388
-     * or if the stream size cannot be determined.
389
-     *
390
-     * @link http://php.net/manual/en/function.fstat.php
391
-     *
392
-     * @return int|null
393
-     */
394
-    public function getSize(): ?int
395
-    {
396
-        if (!is_resource($this->resource)) {
397
-            return null;
398
-        }
399
-
400
-        /** @var array{size: int}|false */
401
-        $stats = fstat($this->resource);
402
-        if ($stats === false) {
403
-            return null;
404
-        }
405
-
406
-        return $stats['size'];
407
-    }
408
-
409
-    /**
410
-     * Converts the stream to a string
411
-     *
412
-     * @link http://php.net/manual/en/language.oop5.magic.php#object.tostring
413
-     *
414
-     * @return string
415
-     */
416
-    public function __toString(): string
417
-    {
418
-        if (!$this->isReadable()) {
419
-            return '';
420
-        }
421
-
422
-        try {
423
-            if ($this->isSeekable()) {
424
-                $this->rewind();
425
-            }
426
-
427
-            return $this->getContents();
428
-        } catch (Throwable $e) {
429
-            return '';
430
-        }
431
-    }
50
+	/**
51
+	 * The stream resource
52
+	 *
53
+	 * @var resource|null
54
+	 */
55
+	private $resource;
56
+
57
+	/**
58
+	 * Signals to close the stream on destruction
59
+	 *
60
+	 * @var bool
61
+	 */
62
+	private $autoClose;
63
+
64
+	/**
65
+	 * Constructor of the class
66
+	 *
67
+	 * @param mixed $resource
68
+	 * @param bool $autoClose
69
+	 *
70
+	 * @throws InvalidArgumentException
71
+	 *         If the stream cannot be initialized with the resource.
72
+	 */
73
+	public function __construct($resource, bool $autoClose = true)
74
+	{
75
+		if (!is_resource($resource)) {
76
+			throw new InvalidArgumentException('Unexpected stream resource');
77
+		}
78
+
79
+		$this->resource = $resource;
80
+		$this->autoClose = $autoClose;
81
+	}
82
+
83
+	/**
84
+	 * Creates a stream
85
+	 *
86
+	 * @param mixed $resource
87
+	 *
88
+	 * @return StreamInterface
89
+	 *
90
+	 * @throws InvalidArgumentException
91
+	 *         If the stream cannot be initialized with the resource.
92
+	 */
93
+	public static function create($resource): StreamInterface
94
+	{
95
+		if ($resource instanceof StreamInterface) {
96
+			return $resource;
97
+		}
98
+
99
+		return new self($resource);
100
+	}
101
+
102
+	/**
103
+	 * Destructor of the class
104
+	 */
105
+	public function __destruct()
106
+	{
107
+		if ($this->autoClose) {
108
+			$this->close();
109
+		}
110
+	}
111
+
112
+	/**
113
+	 * Detaches a resource from the stream
114
+	 *
115
+	 * Returns NULL if the stream already without a resource.
116
+	 *
117
+	 * @return resource|null
118
+	 */
119
+	public function detach()
120
+	{
121
+		$resource = $this->resource;
122
+		$this->resource = null;
123
+
124
+		return $resource;
125
+	}
126
+
127
+	/**
128
+	 * Closes the stream
129
+	 *
130
+	 * @link http://php.net/manual/en/function.fclose.php
131
+	 *
132
+	 * @return void
133
+	 */
134
+	public function close(): void
135
+	{
136
+		$resource = $this->detach();
137
+		if (!is_resource($resource)) {
138
+			return;
139
+		}
140
+
141
+		fclose($resource);
142
+	}
143
+
144
+	/**
145
+	 * Checks if the end of the stream is reached
146
+	 *
147
+	 * @link http://php.net/manual/en/function.feof.php
148
+	 *
149
+	 * @return bool
150
+	 */
151
+	public function eof(): bool
152
+	{
153
+		if (!is_resource($this->resource)) {
154
+			return true;
155
+		}
156
+
157
+		return feof($this->resource);
158
+	}
159
+
160
+	/**
161
+	 * Gets the stream pointer position
162
+	 *
163
+	 * @link http://php.net/manual/en/function.ftell.php
164
+	 *
165
+	 * @return int
166
+	 *
167
+	 * @throws RuntimeException
168
+	 */
169
+	public function tell(): int
170
+	{
171
+		if (!is_resource($this->resource)) {
172
+			throw new RuntimeException('The stream without a resource so the operation is not possible');
173
+		}
174
+
175
+		$result = ftell($this->resource);
176
+		if ($result === false) {
177
+			throw new RuntimeException('Unable to get the stream pointer position');
178
+		}
179
+
180
+		return $result;
181
+	}
182
+
183
+	/**
184
+	 * Checks if the stream is seekable
185
+	 *
186
+	 * @return bool
187
+	 */
188
+	public function isSeekable(): bool
189
+	{
190
+		if (!is_resource($this->resource)) {
191
+			return false;
192
+		}
193
+
194
+		/** @var array{seekable: bool} */
195
+		$metadata = stream_get_meta_data($this->resource);
196
+
197
+		return $metadata['seekable'];
198
+	}
199
+
200
+	/**
201
+	 * Moves the stream pointer to the beginning
202
+	 *
203
+	 * @return void
204
+	 *
205
+	 * @throws RuntimeException
206
+	 */
207
+	public function rewind(): void
208
+	{
209
+		$this->seek(0);
210
+	}
211
+
212
+	/**
213
+	 * Moves the stream pointer to the given position
214
+	 *
215
+	 * @link http://php.net/manual/en/function.fseek.php
216
+	 *
217
+	 * @param int $offset
218
+	 * @param int $whence
219
+	 *
220
+	 * @return void
221
+	 *
222
+	 * @throws RuntimeException
223
+	 */
224
+	public function seek($offset, $whence = SEEK_SET): void
225
+	{
226
+		if (!is_resource($this->resource)) {
227
+			throw new RuntimeException('The stream without a resource so the operation is not possible');
228
+		}
229
+
230
+		if (!$this->isSeekable()) {
231
+			throw new RuntimeException('Stream is not seekable');
232
+		}
233
+
234
+		$result = fseek($this->resource, $offset, $whence);
235
+		if ($result !== 0) {
236
+			throw new RuntimeException('Unable to move the stream pointer position');
237
+		}
238
+	}
239
+
240
+	/**
241
+	 * Checks if the stream is writable
242
+	 *
243
+	 * @return bool
244
+	 */
245
+	public function isWritable(): bool
246
+	{
247
+		if (!is_resource($this->resource)) {
248
+			return false;
249
+		}
250
+
251
+		/** @var array{mode: string} */
252
+		$metadata = stream_get_meta_data($this->resource);
253
+
254
+		return strpbrk($metadata['mode'], '+acwx') !== false;
255
+	}
256
+
257
+	/**
258
+	 * Writes the given string to the stream
259
+	 *
260
+	 * Returns the number of bytes written to the stream.
261
+	 *
262
+	 * @link http://php.net/manual/en/function.fwrite.php
263
+	 *
264
+	 * @param string $string
265
+	 *
266
+	 * @return int
267
+	 *
268
+	 * @throws RuntimeException
269
+	 */
270
+	public function write($string): int
271
+	{
272
+		if (!is_resource($this->resource)) {
273
+			throw new RuntimeException('The stream without a resource so the operation is not possible');
274
+		}
275
+
276
+		if (!$this->isWritable()) {
277
+			throw new RuntimeException('Stream is not writable');
278
+		}
279
+
280
+		$result = fwrite($this->resource, $string);
281
+		if ($result === false) {
282
+			throw new RuntimeException('Unable to write to the stream');
283
+		}
284
+
285
+		return $result;
286
+	}
287
+
288
+	/**
289
+	 * Checks if the stream is readable
290
+	 *
291
+	 * @return bool
292
+	 */
293
+	public function isReadable(): bool
294
+	{
295
+		if (!is_resource($this->resource)) {
296
+			return false;
297
+		}
298
+
299
+		/** @var array{mode: string} */
300
+		$metadata = stream_get_meta_data($this->resource);
301
+
302
+		return strpbrk($metadata['mode'], '+r') !== false;
303
+	}
304
+
305
+	/**
306
+	 * Reads the given number of bytes from the stream
307
+	 *
308
+	 * @link http://php.net/manual/en/function.fread.php
309
+	 *
310
+	 * @param int $length
311
+	 *
312
+	 * @return string
313
+	 *
314
+	 * @throws RuntimeException
315
+	 */
316
+	public function read($length): string
317
+	{
318
+		if (!is_resource($this->resource)) {
319
+			throw new RuntimeException('The stream without a resource so the operation is not possible');
320
+		}
321
+
322
+		if (!$this->isReadable()) {
323
+			throw new RuntimeException('Stream is not readable');
324
+		}
325
+
326
+		$result = fread($this->resource, $length);
327
+		if ($result === false) {
328
+			throw new RuntimeException('Unable to read from the stream');
329
+		}
330
+
331
+		return $result;
332
+	}
333
+
334
+	/**
335
+	 * Reads the remainder of the stream
336
+	 *
337
+	 * @link http://php.net/manual/en/function.stream-get-contents.php
338
+	 *
339
+	 * @return string
340
+	 *
341
+	 * @throws RuntimeException
342
+	 */
343
+	public function getContents(): string
344
+	{
345
+		if (!is_resource($this->resource)) {
346
+			throw new RuntimeException('The stream without a resource so the operation is not possible');
347
+		}
348
+
349
+		if (!$this->isReadable()) {
350
+			throw new RuntimeException('Stream is not readable');
351
+		}
352
+
353
+		$result = stream_get_contents($this->resource);
354
+		if ($result === false) {
355
+			throw new RuntimeException('Unable to read the remainder of the stream');
356
+		}
357
+
358
+		return $result;
359
+	}
360
+
361
+	/**
362
+	 * Gets the stream metadata
363
+	 *
364
+	 * @link http://php.net/manual/en/function.stream-get-meta-data.php
365
+	 *
366
+	 * @param string|null $key
367
+	 *
368
+	 * @return mixed
369
+	 */
370
+	public function getMetadata($key = null)
371
+	{
372
+		if (!is_resource($this->resource)) {
373
+			return null;
374
+		}
375
+
376
+		$metadata = stream_get_meta_data($this->resource);
377
+		if ($key === null) {
378
+			return $metadata;
379
+		}
380
+
381
+		return $metadata[$key] ?? null;
382
+	}
383
+
384
+	/**
385
+	 * Gets the stream size
386
+	 *
387
+	 * Returns NULL if the stream without a resource,
388
+	 * or if the stream size cannot be determined.
389
+	 *
390
+	 * @link http://php.net/manual/en/function.fstat.php
391
+	 *
392
+	 * @return int|null
393
+	 */
394
+	public function getSize(): ?int
395
+	{
396
+		if (!is_resource($this->resource)) {
397
+			return null;
398
+		}
399
+
400
+		/** @var array{size: int}|false */
401
+		$stats = fstat($this->resource);
402
+		if ($stats === false) {
403
+			return null;
404
+		}
405
+
406
+		return $stats['size'];
407
+	}
408
+
409
+	/**
410
+	 * Converts the stream to a string
411
+	 *
412
+	 * @link http://php.net/manual/en/language.oop5.magic.php#object.tostring
413
+	 *
414
+	 * @return string
415
+	 */
416
+	public function __toString(): string
417
+	{
418
+		if (!$this->isReadable()) {
419
+			return '';
420
+		}
421
+
422
+		try {
423
+			if ($this->isSeekable()) {
424
+				$this->rewind();
425
+			}
426
+
427
+			return $this->getContents();
428
+		} catch (Throwable $e) {
429
+			return '';
430
+		}
431
+	}
432 432
 }
Please login to merge, or discard this patch.