PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.18.0
GiveWP – Donation Plugin and Fundraising Platform v4.18.0
4.18.0 4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 All 257 releases
give / vendor / vendor-prefixed / nyholm / psr7 / src / Stream.php

Stream.php in GiveWP – Donation Plugin and Fundraising Platform 4.18.0, at vendor/vendor-prefixed/nyholm/psr7/src/Stream.php

400 lines 11.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Give\Vendors\Nyholm\Psr7;
6
7 use Give\Vendors\Psr\Http\Message\StreamInterface;
8
9 /**
10 * @author Michael Dowling and contributors to guzzlehttp/psr7
11 * @author Tobias Nyholm <[email protected]>
12 * @author Martijn van der Ven <[email protected]>
13 *
14 * @final This class should never be extended. See https://github.com/Nyholm/psr7/blob/master/doc/final.md
15 */
16 class Stream implements StreamInterface
17 {
18 use StreamTrait;
19
20 /** @var resource|null A resource reference */
21 private $stream;
22
23 /** @var bool */
24 private $seekable;
25
26 /** @var bool */
27 private $readable;
28
29 /** @var bool */
30 private $writable;
31
32 /** @var array|mixed|void|bool|null */
33 private $uri;
34
35 /** @var int|null */
36 private $size;
37
38 /** @var array Hash of readable and writable stream types */
39 private const READ_WRITE_HASH = [
40 'read' => [
41 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
42 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
43 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
44 'x+t' => true, 'c+t' => true, 'a+' => true,
45 ],
46 'write' => [
47 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
48 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
49 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
50 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true,
51 ],
52 ];
53
54 /**
55 * @param resource $body
56 */
57 public function __construct($body)
58 {
59 if (!\is_resource($body)) {
60 throw new \InvalidArgumentException('First argument to Stream::__construct() must be resource');
61 }
62
63 $this->stream = $body;
64 $meta = \stream_get_meta_data($this->stream);
65 $this->seekable = $meta['seekable'] && 0 === \fseek($this->stream, 0, \SEEK_CUR);
66 $this->readable = isset(self::READ_WRITE_HASH['read'][$meta['mode']]);
67 $this->writable = isset(self::READ_WRITE_HASH['write'][$meta['mode']]);
68 }
69
70 /**
71 * Creates a new PSR-7 stream.
72 *
73 * @param string|resource|StreamInterface $body
74 *
75 * @throws \InvalidArgumentException
76 */
77 public static function create($body = ''): StreamInterface
78 {
79 if ($body instanceof StreamInterface) {
80 return $body;
81 }
82
83 if (\is_string($body)) {
84 if (200000 <= \strlen($body)) {
85 $body = self::openZvalStream($body);
86 } else {
87 $resource = \fopen('php://memory', 'r+');
88 \fwrite($resource, $body);
89 \fseek($resource, 0);
90 $body = $resource;
91 }
92 }
93
94 if (!\is_resource($body)) {
95 throw new \InvalidArgumentException('First argument to Stream::create() must be a string, resource or StreamInterface');
96 }
97
98 return new self($body);
99 }
100
101 /**
102 * Closes the stream when the destructed.
103 */
104 public function __destruct()
105 {
106 $this->close();
107 }
108
109 public function close(): void
110 {
111 if (isset($this->stream)) {
112 if (\is_resource($this->stream)) {
113 \fclose($this->stream);
114 }
115 $this->detach();
116 }
117 }
118
119 public function detach()
120 {
121 if (!isset($this->stream)) {
122 return null;
123 }
124
125 $result = $this->stream;
126 unset($this->stream);
127 $this->size = $this->uri = null;
128 $this->readable = $this->writable = $this->seekable = false;
129
130 return $result;
131 }
132
133 private function getUri()
134 {
135 if (false !== $this->uri) {
136 $this->uri = $this->getMetadata('uri') ?? false;
137 }
138
139 return $this->uri;
140 }
141
142 public function getSize(): ?int
143 {
144 if (null !== $this->size) {
145 return $this->size;
146 }
147
148 if (!isset($this->stream)) {
149 return null;
150 }
151
152 // Clear the stat cache if the stream has a URI
153 if ($uri = $this->getUri()) {
154 \clearstatcache(true, $uri);
155 }
156
157 $stats = \fstat($this->stream);
158 if (isset($stats['size'])) {
159 $this->size = $stats['size'];
160
161 return $this->size;
162 }
163
164 return null;
165 }
166
167 public function tell(): int
168 {
169 if (!isset($this->stream)) {
170 throw new \RuntimeException('Stream is detached');
171 }
172
173 if (false === $result = @\ftell($this->stream)) {
174 throw new \RuntimeException('Unable to determine stream position: ' . (\error_get_last()['message'] ?? ''));
175 }
176
177 return $result;
178 }
179
180 public function eof(): bool
181 {
182 return !isset($this->stream) || \feof($this->stream);
183 }
184
185 public function isSeekable(): bool
186 {
187 return $this->seekable;
188 }
189
190 public function seek($offset, $whence = \SEEK_SET): void
191 {
192 if (!isset($this->stream)) {
193 throw new \RuntimeException('Stream is detached');
194 }
195
196 if (!$this->seekable) {
197 throw new \RuntimeException('Stream is not seekable');
198 }
199
200 if (-1 === \fseek($this->stream, $offset, $whence)) {
201 throw new \RuntimeException('Unable to seek to stream position "' . $offset . '" with whence ' . \var_export($whence, true));
202 }
203 }
204
205 public function rewind(): void
206 {
207 $this->seek(0);
208 }
209
210 public function isWritable(): bool
211 {
212 return $this->writable;
213 }
214
215 public function write($string): int
216 {
217 if (!isset($this->stream)) {
218 throw new \RuntimeException('Stream is detached');
219 }
220
221 if (!$this->writable) {
222 throw new \RuntimeException('Cannot write to a non-writable stream');
223 }
224
225 // We can't know the size after writing anything
226 $this->size = null;
227
228 if (false === $result = @\fwrite($this->stream, $string)) {
229 throw new \RuntimeException('Unable to write to stream: ' . (\error_get_last()['message'] ?? ''));
230 }
231
232 return $result;
233 }
234
235 public function isReadable(): bool
236 {
237 return $this->readable;
238 }
239
240 public function read($length): string
241 {
242 if (!isset($this->stream)) {
243 throw new \RuntimeException('Stream is detached');
244 }
245
246 if (!$this->readable) {
247 throw new \RuntimeException('Cannot read from non-readable stream');
248 }
249
250 if (false === $result = @\fread($this->stream, $length)) {
251 throw new \RuntimeException('Unable to read from stream: ' . (\error_get_last()['message'] ?? ''));
252 }
253
254 return $result;
255 }
256
257 public function getContents(): string
258 {
259 if (!isset($this->stream)) {
260 throw new \RuntimeException('Stream is detached');
261 }
262
263 $exception = null;
264
265 \set_error_handler(static function ($type, $message) use (&$exception) {
266 throw $exception = new \RuntimeException('Unable to read stream contents: ' . $message);
267 });
268
269 try {
270 return \stream_get_contents($this->stream);
271 } catch (\Throwable $e) {
272 throw $e === $exception ? $e : new \RuntimeException('Unable to read stream contents: ' . $e->getMessage(), 0, $e);
273 } finally {
274 \restore_error_handler();
275 }
276 }
277
278 /**
279 * @return mixed
280 */
281 public function getMetadata($key = null)
282 {
283 if (null !== $key && !\is_string($key)) {
284 throw new \InvalidArgumentException('Metadata key must be a string');
285 }
286
287 if (!isset($this->stream)) {
288 return $key ? null : [];
289 }
290
291 $meta = \stream_get_meta_data($this->stream);
292
293 if (null === $key) {
294 return $meta;
295 }
296
297 return $meta[$key] ?? null;
298 }
299
300 private static function openZvalStream(string $body)
301 {
302 static $wrapper;
303
304 $wrapper ?? \stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper = \get_class(new class() {
305 public $context;
306
307 private $data;
308 private $position = 0;
309
310 public function stream_open(): bool
311 {
312 $this->data = \stream_context_get_options($this->context)['Nyholm-Psr7-Zval']['data'];
313 \stream_context_set_option($this->context, 'Nyholm-Psr7-Zval', 'data', null);
314
315 return true;
316 }
317
318 public function stream_read(int $count): string
319 {
320 $result = \substr($this->data, $this->position, $count);
321 $this->position += \strlen($result);
322
323 return $result;
324 }
325
326 public function stream_write(string $data): int
327 {
328 $this->data = \substr_replace($this->data, $data, $this->position, \strlen($data));
329 $this->position += \strlen($data);
330
331 return \strlen($data);
332 }
333
334 public function stream_tell(): int
335 {
336 return $this->position;
337 }
338
339 public function stream_eof(): bool
340 {
341 return \strlen($this->data) <= $this->position;
342 }
343
344 public function stream_stat(): array
345 {
346 return [
347 'mode' => 33206, // POSIX_S_IFREG | 0666
348 'nlink' => 1,
349 'rdev' => -1,
350 'size' => \strlen($this->data),
351 'blksize' => -1,
352 'blocks' => -1,
353 ];
354 }
355
356 public function stream_seek(int $offset, int $whence): bool
357 {
358 if (\SEEK_SET === $whence && (0 <= $offset && \strlen($this->data) >= $offset)) {
359 $this->position = $offset;
360 } elseif (\SEEK_CUR === $whence && 0 <= $offset) {
361 $this->position += $offset;
362 } elseif (\SEEK_END === $whence && (0 > $offset && 0 <= $offset = \strlen($this->data) + $offset)) {
363 $this->position = $offset;
364 } else {
365 return false;
366 }
367
368 return true;
369 }
370
371 public function stream_set_option(): bool
372 {
373 return true;
374 }
375
376 public function stream_truncate(int $new_size): bool
377 {
378 if ($new_size) {
379 $this->data = \substr($this->data, 0, $new_size);
380 $this->position = \min($this->position, $new_size);
381 } else {
382 $this->data = '';
383 $this->position = 0;
384 }
385
386 return true;
387 }
388 }));
389
390 $context = \stream_context_create(['Nyholm-Psr7-Zval' => ['data' => $body]]);
391
392 if (!$stream = @\fopen('Nyholm-Psr7-Zval://', 'r+', false, $context)) {
393 \stream_wrapper_register('Nyholm-Psr7-Zval', $wrapper);
394 $stream = \fopen('Nyholm-Psr7-Zval://', 'r+', false, $context);
395 }
396
397 return $stream;
398 }
399 }
400