PluginProbe
Depicter — Popup & Slider Builder / 1.3.2
Depicter — Popup & Slider Builder v1.3.2
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / modules / GuzzleHttp / Psr7 / AppendStream.php

AppendStream.php in Depicter — Popup & Slider Builder 1.3.2, at modules/GuzzleHttp/Psr7/AppendStream.php

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