PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.0.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.0.1
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / vendor / guzzlehttp / psr7 / src / AppendStream.php

AppendStream.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 11.0.1, at vendor/guzzlehttp/psr7/src/AppendStream.php

251 lines 5.8 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 GuzzleHttp\Psr7;
6
7 use Psr\Http\Message\StreamInterface;
8
9 /**
10 * Reads from multiple streams, one after the other.
11 *
12 * This is a read-only stream decorator.
13 */
14 final class AppendStream implements StreamInterface
15 {
16 /** @var StreamInterface[] Streams being decorated */
17 private $streams = [];
18
19 /** @var bool */
20 private $seekable = true;
21
22 /** @var int */
23 private $current = 0;
24
25 /** @var int */
26 private $pos = 0;
27
28 /**
29 * @param StreamInterface[] $streams Streams to decorate. Each stream must
30 * be readable.
31 */
32 public function __construct(array $streams = [])
33 {
34 foreach ($streams as $stream) {
35 $this->addStream($stream);
36 }
37 }
38
39 public function __toString(): string
40 {
41 try {
42 $this->rewind();
43
44 return $this->getContents();
45 } catch (\Throwable $e) {
46 if (\PHP_VERSION_ID >= 70400) {
47 throw $e;
48 }
49 trigger_error(sprintf('%s::__toString exception: %s', self::class, (string)$e), E_USER_ERROR);
50
51 return '';
52 }
53 }
54
55 /**
56 * Add a stream to the AppendStream
57 *
58 * @param StreamInterface $stream Stream to append. Must be readable.
59 *
60 * @throws \InvalidArgumentException if the stream is not readable
61 */
62 public function addStream(StreamInterface $stream): void
63 {
64 if (!$stream->isReadable()) {
65 throw new \InvalidArgumentException('Each stream must be readable');
66 }
67
68 // The stream is only seekable if all streams are seekable
69 if (!$stream->isSeekable()) {
70 $this->seekable = false;
71 }
72
73 $this->streams[] = $stream;
74 }
75
76 public function getContents(): string
77 {
78 return Utils::copyToString($this);
79 }
80
81 /**
82 * Closes each attached stream.
83 */
84 public function close(): void
85 {
86 $this->pos = $this->current = 0;
87 $this->seekable = true;
88
89 foreach ($this->streams as $stream) {
90 $stream->close();
91 }
92
93 $this->streams = [];
94 }
95
96 /**
97 * Detaches each attached stream.
98 *
99 * Returns null as it's not clear which underlying stream resource to return.
100 */
101 public function detach()
102 {
103 $this->pos = $this->current = 0;
104 $this->seekable = true;
105
106 foreach ($this->streams as $stream) {
107 $stream->detach();
108 }
109
110 $this->streams = [];
111
112 return null;
113 }
114
115 public function tell(): int
116 {
117 return $this->pos;
118 }
119
120 /**
121 * Tries to calculate the size by adding the size of each stream.
122 *
123 * If any of the streams do not return a valid number, then the size of the
124 * append stream cannot be determined and null is returned.
125 */
126 public function getSize(): ?int
127 {
128 $size = 0;
129
130 foreach ($this->streams as $stream) {
131 $s = $stream->getSize();
132 if ($s === null) {
133 return null;
134 }
135 $size += $s;
136 }
137
138 return $size;
139 }
140
141 public function eof(): bool
142 {
143 return !$this->streams
144 || ($this->current >= count($this->streams) - 1
145 && $this->streams[$this->current]->eof());
146 }
147
148 public function rewind(): void
149 {
150 $this->seek(0);
151 }
152
153 /**
154 * Attempts to seek to the given position. Only supports SEEK_SET.
155 */
156 public function seek($offset, $whence = SEEK_SET): void
157 {
158 if (!$this->seekable) {
159 throw new \RuntimeException('This AppendStream is not seekable');
160 } elseif ($whence !== SEEK_SET) {
161 throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
162 }
163
164 $this->pos = $this->current = 0;
165
166 // Rewind each stream
167 foreach ($this->streams as $i => $stream) {
168 try {
169 $stream->rewind();
170 } catch (\Exception $e) {
171 throw new \RuntimeException(
172 'Unable to seek stream '
173 .$i.' of the AppendStream', 0, $e
174 );
175 }
176 }
177
178 // Seek to the actual position by reading from each stream
179 while ($this->pos < $offset && !$this->eof()) {
180 $result = $this->read(min(8096, $offset - $this->pos));
181 if ($result === '') {
182 break;
183 }
184 }
185 }
186
187 /**
188 * Reads from all of the appended streams until the length is met or EOF.
189 */
190 public function read($length): string
191 {
192 $buffer = '';
193 $total = count($this->streams) - 1;
194 $remaining = $length;
195 $progressToNext = false;
196
197 while ($remaining > 0) {
198 // Progress to the next stream if needed.
199 if ($progressToNext || $this->streams[$this->current]->eof()) {
200 $progressToNext = false;
201 if ($this->current === $total) {
202 break;
203 }
204 ++$this->current;
205 }
206
207 $result = $this->streams[$this->current]->read($remaining);
208
209 if ($result === '') {
210 $progressToNext = true;
211 continue;
212 }
213
214 $buffer .= $result;
215 $remaining = $length - strlen($buffer);
216 }
217
218 $this->pos += strlen($buffer);
219
220 return $buffer;
221 }
222
223 public function isReadable(): bool
224 {
225 return true;
226 }
227
228 public function isWritable(): bool
229 {
230 return false;
231 }
232
233 public function isSeekable(): bool
234 {
235 return $this->seekable;
236 }
237
238 public function write($string): int
239 {
240 throw new \RuntimeException('Cannot write to an AppendStream');
241 }
242
243 /**
244 * @return mixed
245 */
246 public function getMetadata($key = null)
247 {
248 return $key ? null : [];
249 }
250 }
251