Passed
Pull Request — master (#31)
by Anatoly
39:30
created
src/Stream/TempFileStream.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -32,32 +32,32 @@
 block discarded – undo
32 32
 final class TempFileStream extends Stream
33 33
 {
34 34
 
35
-    /**
36
-     * Constructor of the class
37
-     *
38
-     * @param string|null $prefix
39
-     *
40
-     * @throws RuntimeException
41
-     */
42
-    public function __construct(?string $prefix = null)
43
-    {
44
-        $prefix ??= 'sunrisephp';
45
-
46
-        $dirname = sys_get_temp_dir();
47
-        if (!is_writable($dirname)) {
48
-            throw new RuntimeException('Temporary files directory is not writable');
49
-        }
50
-
51
-        $filename = tempnam($dirname, $prefix);
52
-        if ($filename === false) {
53
-            throw new RuntimeException('Temporary file name cannot be generated');
54
-        }
55
-
56
-        $resource = fopen($filename, 'w+b');
57
-        if (!is_resource($resource)) {
58
-            throw new RuntimeException('Temporary file cannot be created or opened');
59
-        }
60
-
61
-        parent::__construct($resource);
62
-    }
35
+	/**
36
+	 * Constructor of the class
37
+	 *
38
+	 * @param string|null $prefix
39
+	 *
40
+	 * @throws RuntimeException
41
+	 */
42
+	public function __construct(?string $prefix = null)
43
+	{
44
+		$prefix ??= 'sunrisephp';
45
+
46
+		$dirname = sys_get_temp_dir();
47
+		if (!is_writable($dirname)) {
48
+			throw new RuntimeException('Temporary files directory is not writable');
49
+		}
50
+
51
+		$filename = tempnam($dirname, $prefix);
52
+		if ($filename === false) {
53
+			throw new RuntimeException('Temporary file name cannot be generated');
54
+		}
55
+
56
+		$resource = fopen($filename, 'w+b');
57
+		if (!is_resource($resource)) {
58
+			throw new RuntimeException('Temporary file cannot be created or opened');
59
+		}
60
+
61
+		parent::__construct($resource);
62
+	}
63 63
 }
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/Enum/CookieSameSite.php 1 patch
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -19,33 +19,33 @@
 block discarded – undo
19 19
 final class CookieSameSite
20 20
 {
21 21
 
22
-    /**
23
-     * Cookies are not sent on normal cross-site subrequests, but are
24
-     * sent when a user is navigating to the origin site.
25
-     *
26
-     * This is the default cookie value if SameSite has not been
27
-     * explicitly specified in recent browser versions.
28
-     *
29
-     * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#lax
30
-     */
31
-    public const LAX = 'Lax';
22
+	/**
23
+	 * Cookies are not sent on normal cross-site subrequests, but are
24
+	 * sent when a user is navigating to the origin site.
25
+	 *
26
+	 * This is the default cookie value if SameSite has not been
27
+	 * explicitly specified in recent browser versions.
28
+	 *
29
+	 * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#lax
30
+	 */
31
+	public const LAX = 'Lax';
32 32
 
33
-    /**
34
-     * Cookies will only be sent in a first-party context and not be
35
-     * sent along with requests initiated by third party websites.
36
-     *
37
-     * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#strict
38
-     */
39
-    public const STRICT = 'Strict';
33
+	/**
34
+	 * Cookies will only be sent in a first-party context and not be
35
+	 * sent along with requests initiated by third party websites.
36
+	 *
37
+	 * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#strict
38
+	 */
39
+	public const STRICT = 'Strict';
40 40
 
41
-    /**
42
-     * Cookies will be sent in all contexts, i.e. in responses to both
43
-     * first-party and cross-site requests.
44
-     *
45
-     * If SameSite=None is set, the cookie Secure attribute must also
46
-     * be set (or the cookie will be blocked).
47
-     *
48
-     * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#none
49
-     */
50
-    public const NONE = 'None';
41
+	/**
42
+	 * Cookies will be sent in all contexts, i.e. in responses to both
43
+	 * first-party and cross-site requests.
44
+	 *
45
+	 * If SameSite=None is set, the cookie Secure attribute must also
46
+	 * be set (or the cookie will be blocked).
47
+	 *
48
+	 * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#none
49
+	 */
50
+	public const NONE = 'None';
51 51
 }
Please login to merge, or discard this patch.
src/Enum/Encoding.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -16,9 +16,9 @@
 block discarded – undo
16 16
  */
17 17
 final class Encoding
18 18
 {
19
-    public const BR = 'br';
20
-    public const CHUNKED = 'chunked';
21
-    public const COMPRESS = 'compress';
22
-    public const DEFLATE = 'deflate';
23
-    public const GZIP = 'gzip';
19
+	public const BR = 'br';
20
+	public const CHUNKED = 'chunked';
21
+	public const COMPRESS = 'compress';
22
+	public const DEFLATE = 'deflate';
23
+	public const GZIP = 'gzip';
24 24
 }
Please login to merge, or discard this patch.
src/Enum/WarningCode.php 1 patch
Indentation   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -18,11 +18,11 @@
 block discarded – undo
18 18
  */
19 19
 final class WarningCode
20 20
 {
21
-    public const RESPONSE_IS_STALE = 110;
22
-    public const REVALIDATION_FAILED = 111;
23
-    public const DISCONNECTED_OPERATION = 112;
24
-    public const HEURISTIC_EXPIRATION = 113;
25
-    public const MISCELLANEOUS_WARNING = 199;
26
-    public const TRANSFORMATION_APPLIED = 214;
27
-    public const MISCELLANEOUS_PERSISTENT_WARNING = 299;
21
+	public const RESPONSE_IS_STALE = 110;
22
+	public const REVALIDATION_FAILED = 111;
23
+	public const DISCONNECTED_OPERATION = 112;
24
+	public const HEURISTIC_EXPIRATION = 113;
25
+	public const MISCELLANEOUS_WARNING = 199;
26
+	public const TRANSFORMATION_APPLIED = 214;
27
+	public const MISCELLANEOUS_PERSISTENT_WARNING = 299;
28 28
 }
Please login to merge, or discard this patch.
src/Enum/AuthenticationScheme.php 1 patch
Indentation   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -18,14 +18,14 @@
 block discarded – undo
18 18
  */
19 19
 final class AuthenticationScheme
20 20
 {
21
-    public const BASIC         = 'Basic';
22
-    public const BEARER        = 'Bearer';
23
-    public const DIGEST        = 'Digest';
24
-    public const HOBA          = 'HOBA';
25
-    public const MUTUAL        = 'Mutual';
26
-    public const NEGOTIATE     = 'Negotiate';
27
-    public const OAUTH         = 'OAuth';
28
-    public const SCRAM_SHA_1   = 'SCRAM-SHA-1';
29
-    public const SCRAM_SHA_256 = 'SCRAM-SHA-256';
30
-    public const VAPID         = 'vapid';
21
+	public const BASIC         = 'Basic';
22
+	public const BEARER        = 'Bearer';
23
+	public const DIGEST        = 'Digest';
24
+	public const HOBA          = 'HOBA';
25
+	public const MUTUAL        = 'Mutual';
26
+	public const NEGOTIATE     = 'Negotiate';
27
+	public const OAUTH         = 'OAuth';
28
+	public const SCRAM_SHA_1   = 'SCRAM-SHA-1';
29
+	public const SCRAM_SHA_256 = 'SCRAM-SHA-256';
30
+	public const VAPID         = 'vapid';
31 31
 }
Please login to merge, or discard this patch.
src/Message.php 1 patch
Indentation   +391 added lines, -391 removed lines patch added patch discarded remove patch
@@ -39,395 +39,395 @@
 block discarded – undo
39 39
 abstract class Message implements MessageInterface
40 40
 {
41 41
 
42
-    /**
43
-     * Default HTTP version
44
-     *
45
-     * @var string
46
-     */
47
-    public const DEFAULT_HTTP_VERSION = '1.1';
48
-
49
-    /**
50
-     * Supported HTTP versions
51
-     *
52
-     * @var list<string>
53
-     */
54
-    public const SUPPORTED_HTTP_VERSIONS = ['1.0', '1.1', '2.0', '2'];
55
-
56
-    /**
57
-     * The message HTTP version
58
-     *
59
-     * @var string
60
-     */
61
-    private string $protocolVersion = self::DEFAULT_HTTP_VERSION;
62
-
63
-    /**
64
-     * The message headers
65
-     *
66
-     * @var array<string, list<string>>
67
-     */
68
-    private array $headers = [];
69
-
70
-    /**
71
-     * Original header names (see $headers)
72
-     *
73
-     * @var array<string, string>
74
-     */
75
-    private array $headerNames = [];
76
-
77
-    /**
78
-     * The message body
79
-     *
80
-     * @var StreamInterface|null
81
-     */
82
-    private ?StreamInterface $body = null;
83
-
84
-    /**
85
-     * Gets the message HTTP version
86
-     *
87
-     * @return string
88
-     */
89
-    public function getProtocolVersion(): string
90
-    {
91
-        return $this->protocolVersion;
92
-    }
93
-
94
-    /**
95
-     * Creates a new instance of the message with the given HTTP version
96
-     *
97
-     * @param string $version
98
-     *
99
-     * @return static
100
-     *
101
-     * @throws InvalidArgumentException
102
-     *         If the HTTP version isn't valid.
103
-     */
104
-    public function withProtocolVersion($version): MessageInterface
105
-    {
106
-        $clone = clone $this;
107
-        $clone->setProtocolVersion($version);
108
-
109
-        return $clone;
110
-    }
111
-
112
-    /**
113
-     * Gets the message headers
114
-     *
115
-     * @return array<string, list<string>>
116
-     */
117
-    public function getHeaders(): array
118
-    {
119
-        return $this->headers;
120
-    }
121
-
122
-    /**
123
-     * Checks if a header exists in the message by the given name
124
-     *
125
-     * @param string $name
126
-     *
127
-     * @return bool
128
-     */
129
-    public function hasHeader($name): bool
130
-    {
131
-        $key = strtolower($name);
132
-
133
-        return isset($this->headerNames[$key]);
134
-    }
135
-
136
-    /**
137
-     * Gets a header value from the message by the given name
138
-     *
139
-     * @param string $name
140
-     *
141
-     * @return list<string>
142
-     */
143
-    public function getHeader($name): array
144
-    {
145
-        if (!$this->hasHeader($name)) {
146
-            return [];
147
-        }
148
-
149
-        $key = strtolower($name);
150
-        $originalName = $this->headerNames[$key];
151
-        $value = $this->headers[$originalName];
152
-
153
-        return $value;
154
-    }
155
-
156
-    /**
157
-     * Gets a header value as a string from the message by the given name
158
-     *
159
-     * @param string $name
160
-     *
161
-     * @return string
162
-     */
163
-    public function getHeaderLine($name): string
164
-    {
165
-        $value = $this->getHeader($name);
166
-        if ([] === $value) {
167
-            return '';
168
-        }
169
-
170
-        return implode(',', $value);
171
-    }
172
-
173
-    /**
174
-     * Creates a new instance of the message with the given header overwriting the old header
175
-     *
176
-     * @param string $name
177
-     * @param string|string[] $value
178
-     *
179
-     * @return static
180
-     *
181
-     * @throws InvalidArgumentException
182
-     *         If the header isn't valid.
183
-     */
184
-    public function withHeader($name, $value): MessageInterface
185
-    {
186
-        $clone = clone $this;
187
-        $clone->setHeader($name, $value, true);
188
-
189
-        return $clone;
190
-    }
191
-
192
-    /**
193
-     * Creates a new instance of the message with the given header NOT overwriting the old header
194
-     *
195
-     * @param string $name
196
-     * @param string|string[] $value
197
-     *
198
-     * @return static
199
-     *
200
-     * @throws InvalidArgumentException
201
-     *         If the header isn't valid.
202
-     */
203
-    public function withAddedHeader($name, $value): MessageInterface
204
-    {
205
-        $clone = clone $this;
206
-        $clone->setHeader($name, $value, false);
207
-
208
-        return $clone;
209
-    }
210
-
211
-    /**
212
-     * Creates a new instance of the message without a header by the given name
213
-     *
214
-     * @param string $name
215
-     *
216
-     * @return static
217
-     */
218
-    public function withoutHeader($name): MessageInterface
219
-    {
220
-        $clone = clone $this;
221
-        $clone->deleteHeader($name);
222
-
223
-        return $clone;
224
-    }
225
-
226
-    /**
227
-     * Gets the message body
228
-     *
229
-     * @return StreamInterface
230
-     */
231
-    public function getBody(): StreamInterface
232
-    {
233
-        return $this->body ??= new PhpTempStream();
234
-    }
235
-
236
-    /**
237
-     * Creates a new instance of the message with the given body
238
-     *
239
-     * @param StreamInterface $body
240
-     *
241
-     * @return static
242
-     */
243
-    public function withBody(StreamInterface $body): MessageInterface
244
-    {
245
-        $clone = clone $this;
246
-        $clone->setBody($body);
247
-
248
-        return $clone;
249
-    }
250
-
251
-    /**
252
-     * Sets the given HTTP version to the message
253
-     *
254
-     * @param string $protocolVersion
255
-     *
256
-     * @return void
257
-     *
258
-     * @throws InvalidArgumentException
259
-     *         If the HTTP version isn't valid.
260
-     */
261
-    final protected function setProtocolVersion($protocolVersion): void
262
-    {
263
-        $this->validateProtocolVersion($protocolVersion);
264
-
265
-        $this->protocolVersion = $protocolVersion;
266
-    }
267
-
268
-    /**
269
-     * Sets a new header to the message with the given name and value(s)
270
-     *
271
-     * @param string $name
272
-     * @param string|string[] $value
273
-     * @param bool $replace
274
-     *
275
-     * @return void
276
-     *
277
-     * @throws InvalidArgumentException
278
-     *         If the header isn't valid.
279
-     */
280
-    final protected function setHeader($name, $value, bool $replace = true): void
281
-    {
282
-        if (!is_array($value)) {
283
-            $value = [$value];
284
-        }
285
-
286
-        $this->validateHeaderName($name);
287
-        $this->validateHeaderValue($name, $value);
288
-
289
-        if ($replace) {
290
-            $this->deleteHeader($name);
291
-        }
292
-
293
-        $key = strtolower($name);
294
-
295
-        $this->headerNames[$key] ??= $name;
296
-        $this->headers[$this->headerNames[$key]] ??= [];
297
-
298
-        foreach ($value as $subvalue) {
299
-            $this->headers[$this->headerNames[$key]][] = $subvalue;
300
-        }
301
-    }
302
-
303
-    /**
304
-     * Sets the given headers to the message
305
-     *
306
-     * @param array<string, string|string[]> $headers
307
-     *
308
-     * @return void
309
-     *
310
-     * @throws InvalidArgumentException
311
-     *         If one of the headers isn't valid.
312
-     */
313
-    final protected function setHeaders(array $headers): void
314
-    {
315
-        foreach ($headers as $name => $value) {
316
-            $this->setHeader($name, $value, false);
317
-        }
318
-    }
319
-
320
-    /**
321
-     * Deletes a header from the message by the given name
322
-     *
323
-     * @param string $name
324
-     *
325
-     * @return void
326
-     */
327
-    final protected function deleteHeader($name): void
328
-    {
329
-        $key = strtolower($name);
330
-
331
-        if (isset($this->headerNames[$key])) {
332
-            unset($this->headers[$this->headerNames[$key]]);
333
-            unset($this->headerNames[$key]);
334
-        }
335
-    }
336
-
337
-    /**
338
-     * Sets the given body to the message
339
-     *
340
-     * @param StreamInterface $body
341
-     *
342
-     * @return void
343
-     */
344
-    final protected function setBody(StreamInterface $body): void
345
-    {
346
-        $this->body = $body;
347
-    }
348
-
349
-    /**
350
-     * Validates the given HTTP version
351
-     *
352
-     * @param mixed $protocolVersion
353
-     *
354
-     * @return void
355
-     *
356
-     * @throws InvalidArgumentException
357
-     *         If the HTTP version isn't valid.
358
-     */
359
-    private function validateProtocolVersion($protocolVersion): void
360
-    {
361
-        if (!in_array($protocolVersion, self::SUPPORTED_HTTP_VERSIONS, true)) {
362
-            throw new InvalidArgumentException('Invalid or unsupported HTTP version');
363
-        }
364
-    }
365
-
366
-    /**
367
-     * Validates the given header name
368
-     *
369
-     * @param mixed $name
370
-     *
371
-     * @return void
372
-     *
373
-     * @throws InvalidArgumentException
374
-     *         If the header name isn't valid.
375
-     */
376
-    private function validateHeaderName($name): void
377
-    {
378
-        if ($name === '') {
379
-            throw new InvalidArgumentException('HTTP header name cannot be an empty');
380
-        }
381
-
382
-        if (!is_string($name)) {
383
-            throw new InvalidArgumentException('HTTP header name must be a string');
384
-        }
385
-
386
-        if (!preg_match(Header::RFC7230_VALID_TOKEN, $name)) {
387
-            throw new InvalidArgumentException('HTTP header name is invalid');
388
-        }
389
-    }
390
-
391
-    /**
392
-     * Validates the given header value
393
-     *
394
-     * @param string $validName
395
-     * @param array $value
396
-     *
397
-     * @return void
398
-     *
399
-     * @throws InvalidArgumentException
400
-     *         If the header value isn't valid.
401
-     */
402
-    private function validateHeaderValue(string $validName, array $value): void
403
-    {
404
-        if ([] === $value) {
405
-            throw new InvalidArgumentException(sprintf(
406
-                'The "%s" HTTP header value cannot be an empty array',
407
-                $validName,
408
-            ));
409
-        }
410
-
411
-        foreach ($value as $key => $item) {
412
-            if ('' === $item) {
413
-                continue;
414
-            }
415
-
416
-            if (!is_string($item)) {
417
-                throw new InvalidArgumentException(sprintf(
418
-                    'The "%s[%s]" HTTP header value must be a string',
419
-                    $validName,
420
-                    $key
421
-                ));
422
-            }
423
-
424
-            if (!preg_match(Header::RFC7230_VALID_FIELD_VALUE, $item)) {
425
-                throw new InvalidArgumentException(sprintf(
426
-                    'The "%s[%s]" HTTP header value is invalid',
427
-                    $validName,
428
-                    $key
429
-                ));
430
-            }
431
-        }
432
-    }
42
+	/**
43
+	 * Default HTTP version
44
+	 *
45
+	 * @var string
46
+	 */
47
+	public const DEFAULT_HTTP_VERSION = '1.1';
48
+
49
+	/**
50
+	 * Supported HTTP versions
51
+	 *
52
+	 * @var list<string>
53
+	 */
54
+	public const SUPPORTED_HTTP_VERSIONS = ['1.0', '1.1', '2.0', '2'];
55
+
56
+	/**
57
+	 * The message HTTP version
58
+	 *
59
+	 * @var string
60
+	 */
61
+	private string $protocolVersion = self::DEFAULT_HTTP_VERSION;
62
+
63
+	/**
64
+	 * The message headers
65
+	 *
66
+	 * @var array<string, list<string>>
67
+	 */
68
+	private array $headers = [];
69
+
70
+	/**
71
+	 * Original header names (see $headers)
72
+	 *
73
+	 * @var array<string, string>
74
+	 */
75
+	private array $headerNames = [];
76
+
77
+	/**
78
+	 * The message body
79
+	 *
80
+	 * @var StreamInterface|null
81
+	 */
82
+	private ?StreamInterface $body = null;
83
+
84
+	/**
85
+	 * Gets the message HTTP version
86
+	 *
87
+	 * @return string
88
+	 */
89
+	public function getProtocolVersion(): string
90
+	{
91
+		return $this->protocolVersion;
92
+	}
93
+
94
+	/**
95
+	 * Creates a new instance of the message with the given HTTP version
96
+	 *
97
+	 * @param string $version
98
+	 *
99
+	 * @return static
100
+	 *
101
+	 * @throws InvalidArgumentException
102
+	 *         If the HTTP version isn't valid.
103
+	 */
104
+	public function withProtocolVersion($version): MessageInterface
105
+	{
106
+		$clone = clone $this;
107
+		$clone->setProtocolVersion($version);
108
+
109
+		return $clone;
110
+	}
111
+
112
+	/**
113
+	 * Gets the message headers
114
+	 *
115
+	 * @return array<string, list<string>>
116
+	 */
117
+	public function getHeaders(): array
118
+	{
119
+		return $this->headers;
120
+	}
121
+
122
+	/**
123
+	 * Checks if a header exists in the message by the given name
124
+	 *
125
+	 * @param string $name
126
+	 *
127
+	 * @return bool
128
+	 */
129
+	public function hasHeader($name): bool
130
+	{
131
+		$key = strtolower($name);
132
+
133
+		return isset($this->headerNames[$key]);
134
+	}
135
+
136
+	/**
137
+	 * Gets a header value from the message by the given name
138
+	 *
139
+	 * @param string $name
140
+	 *
141
+	 * @return list<string>
142
+	 */
143
+	public function getHeader($name): array
144
+	{
145
+		if (!$this->hasHeader($name)) {
146
+			return [];
147
+		}
148
+
149
+		$key = strtolower($name);
150
+		$originalName = $this->headerNames[$key];
151
+		$value = $this->headers[$originalName];
152
+
153
+		return $value;
154
+	}
155
+
156
+	/**
157
+	 * Gets a header value as a string from the message by the given name
158
+	 *
159
+	 * @param string $name
160
+	 *
161
+	 * @return string
162
+	 */
163
+	public function getHeaderLine($name): string
164
+	{
165
+		$value = $this->getHeader($name);
166
+		if ([] === $value) {
167
+			return '';
168
+		}
169
+
170
+		return implode(',', $value);
171
+	}
172
+
173
+	/**
174
+	 * Creates a new instance of the message with the given header overwriting the old header
175
+	 *
176
+	 * @param string $name
177
+	 * @param string|string[] $value
178
+	 *
179
+	 * @return static
180
+	 *
181
+	 * @throws InvalidArgumentException
182
+	 *         If the header isn't valid.
183
+	 */
184
+	public function withHeader($name, $value): MessageInterface
185
+	{
186
+		$clone = clone $this;
187
+		$clone->setHeader($name, $value, true);
188
+
189
+		return $clone;
190
+	}
191
+
192
+	/**
193
+	 * Creates a new instance of the message with the given header NOT overwriting the old header
194
+	 *
195
+	 * @param string $name
196
+	 * @param string|string[] $value
197
+	 *
198
+	 * @return static
199
+	 *
200
+	 * @throws InvalidArgumentException
201
+	 *         If the header isn't valid.
202
+	 */
203
+	public function withAddedHeader($name, $value): MessageInterface
204
+	{
205
+		$clone = clone $this;
206
+		$clone->setHeader($name, $value, false);
207
+
208
+		return $clone;
209
+	}
210
+
211
+	/**
212
+	 * Creates a new instance of the message without a header by the given name
213
+	 *
214
+	 * @param string $name
215
+	 *
216
+	 * @return static
217
+	 */
218
+	public function withoutHeader($name): MessageInterface
219
+	{
220
+		$clone = clone $this;
221
+		$clone->deleteHeader($name);
222
+
223
+		return $clone;
224
+	}
225
+
226
+	/**
227
+	 * Gets the message body
228
+	 *
229
+	 * @return StreamInterface
230
+	 */
231
+	public function getBody(): StreamInterface
232
+	{
233
+		return $this->body ??= new PhpTempStream();
234
+	}
235
+
236
+	/**
237
+	 * Creates a new instance of the message with the given body
238
+	 *
239
+	 * @param StreamInterface $body
240
+	 *
241
+	 * @return static
242
+	 */
243
+	public function withBody(StreamInterface $body): MessageInterface
244
+	{
245
+		$clone = clone $this;
246
+		$clone->setBody($body);
247
+
248
+		return $clone;
249
+	}
250
+
251
+	/**
252
+	 * Sets the given HTTP version to the message
253
+	 *
254
+	 * @param string $protocolVersion
255
+	 *
256
+	 * @return void
257
+	 *
258
+	 * @throws InvalidArgumentException
259
+	 *         If the HTTP version isn't valid.
260
+	 */
261
+	final protected function setProtocolVersion($protocolVersion): void
262
+	{
263
+		$this->validateProtocolVersion($protocolVersion);
264
+
265
+		$this->protocolVersion = $protocolVersion;
266
+	}
267
+
268
+	/**
269
+	 * Sets a new header to the message with the given name and value(s)
270
+	 *
271
+	 * @param string $name
272
+	 * @param string|string[] $value
273
+	 * @param bool $replace
274
+	 *
275
+	 * @return void
276
+	 *
277
+	 * @throws InvalidArgumentException
278
+	 *         If the header isn't valid.
279
+	 */
280
+	final protected function setHeader($name, $value, bool $replace = true): void
281
+	{
282
+		if (!is_array($value)) {
283
+			$value = [$value];
284
+		}
285
+
286
+		$this->validateHeaderName($name);
287
+		$this->validateHeaderValue($name, $value);
288
+
289
+		if ($replace) {
290
+			$this->deleteHeader($name);
291
+		}
292
+
293
+		$key = strtolower($name);
294
+
295
+		$this->headerNames[$key] ??= $name;
296
+		$this->headers[$this->headerNames[$key]] ??= [];
297
+
298
+		foreach ($value as $subvalue) {
299
+			$this->headers[$this->headerNames[$key]][] = $subvalue;
300
+		}
301
+	}
302
+
303
+	/**
304
+	 * Sets the given headers to the message
305
+	 *
306
+	 * @param array<string, string|string[]> $headers
307
+	 *
308
+	 * @return void
309
+	 *
310
+	 * @throws InvalidArgumentException
311
+	 *         If one of the headers isn't valid.
312
+	 */
313
+	final protected function setHeaders(array $headers): void
314
+	{
315
+		foreach ($headers as $name => $value) {
316
+			$this->setHeader($name, $value, false);
317
+		}
318
+	}
319
+
320
+	/**
321
+	 * Deletes a header from the message by the given name
322
+	 *
323
+	 * @param string $name
324
+	 *
325
+	 * @return void
326
+	 */
327
+	final protected function deleteHeader($name): void
328
+	{
329
+		$key = strtolower($name);
330
+
331
+		if (isset($this->headerNames[$key])) {
332
+			unset($this->headers[$this->headerNames[$key]]);
333
+			unset($this->headerNames[$key]);
334
+		}
335
+	}
336
+
337
+	/**
338
+	 * Sets the given body to the message
339
+	 *
340
+	 * @param StreamInterface $body
341
+	 *
342
+	 * @return void
343
+	 */
344
+	final protected function setBody(StreamInterface $body): void
345
+	{
346
+		$this->body = $body;
347
+	}
348
+
349
+	/**
350
+	 * Validates the given HTTP version
351
+	 *
352
+	 * @param mixed $protocolVersion
353
+	 *
354
+	 * @return void
355
+	 *
356
+	 * @throws InvalidArgumentException
357
+	 *         If the HTTP version isn't valid.
358
+	 */
359
+	private function validateProtocolVersion($protocolVersion): void
360
+	{
361
+		if (!in_array($protocolVersion, self::SUPPORTED_HTTP_VERSIONS, true)) {
362
+			throw new InvalidArgumentException('Invalid or unsupported HTTP version');
363
+		}
364
+	}
365
+
366
+	/**
367
+	 * Validates the given header name
368
+	 *
369
+	 * @param mixed $name
370
+	 *
371
+	 * @return void
372
+	 *
373
+	 * @throws InvalidArgumentException
374
+	 *         If the header name isn't valid.
375
+	 */
376
+	private function validateHeaderName($name): void
377
+	{
378
+		if ($name === '') {
379
+			throw new InvalidArgumentException('HTTP header name cannot be an empty');
380
+		}
381
+
382
+		if (!is_string($name)) {
383
+			throw new InvalidArgumentException('HTTP header name must be a string');
384
+		}
385
+
386
+		if (!preg_match(Header::RFC7230_VALID_TOKEN, $name)) {
387
+			throw new InvalidArgumentException('HTTP header name is invalid');
388
+		}
389
+	}
390
+
391
+	/**
392
+	 * Validates the given header value
393
+	 *
394
+	 * @param string $validName
395
+	 * @param array $value
396
+	 *
397
+	 * @return void
398
+	 *
399
+	 * @throws InvalidArgumentException
400
+	 *         If the header value isn't valid.
401
+	 */
402
+	private function validateHeaderValue(string $validName, array $value): void
403
+	{
404
+		if ([] === $value) {
405
+			throw new InvalidArgumentException(sprintf(
406
+				'The "%s" HTTP header value cannot be an empty array',
407
+				$validName,
408
+			));
409
+		}
410
+
411
+		foreach ($value as $key => $item) {
412
+			if ('' === $item) {
413
+				continue;
414
+			}
415
+
416
+			if (!is_string($item)) {
417
+				throw new InvalidArgumentException(sprintf(
418
+					'The "%s[%s]" HTTP header value must be a string',
419
+					$validName,
420
+					$key
421
+				));
422
+			}
423
+
424
+			if (!preg_match(Header::RFC7230_VALID_FIELD_VALUE, $item)) {
425
+				throw new InvalidArgumentException(sprintf(
426
+					'The "%s[%s]" HTTP header value is invalid',
427
+					$validName,
428
+					$key
429
+				));
430
+			}
431
+		}
432
+	}
433 433
 }
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.
src/Header/ContentEncodingHeader.php 1 patch
Indentation   +49 added lines, -49 removed lines patch added patch discarded remove patch
@@ -29,61 +29,61 @@
 block discarded – undo
29 29
 class ContentEncodingHeader extends Header
30 30
 {
31 31
 
32
-    /**
33
-     * @deprecated Use the {@see Encoding} enum.
34
-     */
35
-    public const BR = Encoding::BR;
32
+	/**
33
+	 * @deprecated Use the {@see Encoding} enum.
34
+	 */
35
+	public const BR = Encoding::BR;
36 36
 
37
-    /**
38
-     * @deprecated Use the {@see Encoding} enum.
39
-     */
40
-    public const COMPRESS = Encoding::COMPRESS;
37
+	/**
38
+	 * @deprecated Use the {@see Encoding} enum.
39
+	 */
40
+	public const COMPRESS = Encoding::COMPRESS;
41 41
 
42
-    /**
43
-     * @deprecated Use the {@see Encoding} enum.
44
-     */
45
-    public const DEFLATE = Encoding::DEFLATE;
42
+	/**
43
+	 * @deprecated Use the {@see Encoding} enum.
44
+	 */
45
+	public const DEFLATE = Encoding::DEFLATE;
46 46
 
47
-    /**
48
-     * @deprecated Use the {@see Encoding} enum.
49
-     */
50
-    public const GZIP = Encoding::GZIP;
47
+	/**
48
+	 * @deprecated Use the {@see Encoding} enum.
49
+	 */
50
+	public const GZIP = Encoding::GZIP;
51 51
 
52
-    /**
53
-     * @var list<string>
54
-     */
55
-    private array $directives = [];
52
+	/**
53
+	 * @var list<string>
54
+	 */
55
+	private array $directives = [];
56 56
 
57
-    /**
58
-     * Constructor of the class
59
-     *
60
-     * @param string ...$directives
61
-     *
62
-     * @throws InvalidHeaderException
63
-     *         If one of the directives isn't valid.
64
-     */
65
-    public function __construct(string ...$directives)
66
-    {
67
-        $this->validateToken(...$directives);
57
+	/**
58
+	 * Constructor of the class
59
+	 *
60
+	 * @param string ...$directives
61
+	 *
62
+	 * @throws InvalidHeaderException
63
+	 *         If one of the directives isn't valid.
64
+	 */
65
+	public function __construct(string ...$directives)
66
+	{
67
+		$this->validateToken(...$directives);
68 68
 
69
-        foreach ($directives as $directive) {
70
-            $this->directives[] = $directive;
71
-        }
72
-    }
69
+		foreach ($directives as $directive) {
70
+			$this->directives[] = $directive;
71
+		}
72
+	}
73 73
 
74
-    /**
75
-     * {@inheritdoc}
76
-     */
77
-    public function getFieldName(): string
78
-    {
79
-        return 'Content-Encoding';
80
-    }
74
+	/**
75
+	 * {@inheritdoc}
76
+	 */
77
+	public function getFieldName(): string
78
+	{
79
+		return 'Content-Encoding';
80
+	}
81 81
 
82
-    /**
83
-     * {@inheritdoc}
84
-     */
85
-    public function getFieldValue(): string
86
-    {
87
-        return implode(', ', $this->directives);
88
-    }
82
+	/**
83
+	 * {@inheritdoc}
84
+	 */
85
+	public function getFieldValue(): string
86
+	{
87
+		return implode(', ', $this->directives);
88
+	}
89 89
 }
Please login to merge, or discard this patch.