Open Journal Systems  3.3.0
AppendStream.php
1 <?php
2 namespace GuzzleHttp\Psr7;
3 
5 
11 class AppendStream implements StreamInterface
12 {
14  private $streams = [];
15 
16  private $seekable = true;
17  private $current = 0;
18  private $pos = 0;
19 
24  public function __construct(array $streams = [])
25  {
26  foreach ($streams as $stream) {
27  $this->addStream($stream);
28  }
29  }
30 
31  public function __toString()
32  {
33  try {
34  $this->rewind();
35  return $this->getContents();
36  } catch (\Exception $e) {
37  return '';
38  }
39  }
40 
48  public function addStream(StreamInterface $stream)
49  {
50  if (!$stream->isReadable()) {
51  throw new \InvalidArgumentException('Each stream must be readable');
52  }
53 
54  // The stream is only seekable if all streams are seekable
55  if (!$stream->isSeekable()) {
56  $this->seekable = false;
57  }
58 
59  $this->streams[] = $stream;
60  }
61 
62  public function getContents()
63  {
64  return copy_to_string($this);
65  }
66 
72  public function close()
73  {
74  $this->pos = $this->current = 0;
75  $this->seekable = true;
76 
77  foreach ($this->streams as $stream) {
78  $stream->close();
79  }
80 
81  $this->streams = [];
82  }
83 
91  public function detach()
92  {
93  $this->pos = $this->current = 0;
94  $this->seekable = true;
95 
96  foreach ($this->streams as $stream) {
97  $stream->detach();
98  }
99 
100  $this->streams = [];
101  }
102 
103  public function tell()
104  {
105  return $this->pos;
106  }
107 
116  public function getSize()
117  {
118  $size = 0;
119 
120  foreach ($this->streams as $stream) {
121  $s = $stream->getSize();
122  if ($s === null) {
123  return null;
124  }
125  $size += $s;
126  }
127 
128  return $size;
129  }
130 
131  public function eof()
132  {
133  return !$this->streams ||
134  ($this->current >= count($this->streams) - 1 &&
135  $this->streams[$this->current]->eof());
136  }
137 
138  public function rewind()
139  {
140  $this->seek(0);
141  }
142 
148  public function seek($offset, $whence = SEEK_SET)
149  {
150  if (!$this->seekable) {
151  throw new \RuntimeException('This AppendStream is not seekable');
152  } elseif ($whence !== SEEK_SET) {
153  throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
154  }
155 
156  $this->pos = $this->current = 0;
157 
158  // Rewind each stream
159  foreach ($this->streams as $i => $stream) {
160  try {
161  $stream->rewind();
162  } catch (\Exception $e) {
163  throw new \RuntimeException('Unable to seek stream '
164  . $i . ' of the AppendStream', 0, $e);
165  }
166  }
167 
168  // Seek to the actual position by reading from each stream
169  while ($this->pos < $offset && !$this->eof()) {
170  $result = $this->read(min(8096, $offset - $this->pos));
171  if ($result === '') {
172  break;
173  }
174  }
175  }
176 
182  public function read($length)
183  {
184  $buffer = '';
185  $total = count($this->streams) - 1;
186  $remaining = $length;
187  $progressToNext = false;
188 
189  while ($remaining > 0) {
190 
191  // Progress to the next stream if needed.
192  if ($progressToNext || $this->streams[$this->current]->eof()) {
193  $progressToNext = false;
194  if ($this->current === $total) {
195  break;
196  }
197  $this->current++;
198  }
199 
200  $result = $this->streams[$this->current]->read($remaining);
201 
202  // Using a loose comparison here to match on '', false, and null
203  if ($result == null) {
204  $progressToNext = true;
205  continue;
206  }
207 
208  $buffer .= $result;
209  $remaining = $length - strlen($buffer);
210  }
211 
212  $this->pos += strlen($buffer);
213 
214  return $buffer;
215  }
216 
217  public function isReadable()
218  {
219  return true;
220  }
221 
222  public function isWritable()
223  {
224  return false;
225  }
226 
227  public function isSeekable()
228  {
229  return $this->seekable;
230  }
231 
232  public function write($string)
233  {
234  throw new \RuntimeException('Cannot write to an AppendStream');
235  }
236 
237  public function getMetadata($key = null)
238  {
239  return $key ? null : [];
240  }
241 }
GuzzleHttp\Psr7\AppendStream\isSeekable
isSeekable()
Definition: AppendStream.php:230
Psr\Http\Message\StreamInterface
Definition: vendor/psr/http-message/src/StreamInterface.php:12
GuzzleHttp\Psr7\AppendStream\read
read($length)
Definition: AppendStream.php:185
GuzzleHttp\Psr7\AppendStream\__construct
__construct(array $streams=[])
Definition: AppendStream.php:27
GuzzleHttp\Psr7\AppendStream\close
close()
Definition: AppendStream.php:75
GuzzleHttp\Psr7\AppendStream\detach
detach()
Definition: AppendStream.php:94
GuzzleHttp\Psr7\AppendStream\isWritable
isWritable()
Definition: AppendStream.php:225
GuzzleHttp\Psr7\AppendStream\tell
tell()
Definition: AppendStream.php:106
GuzzleHttp\Psr7
Definition: AppendStream.php:2
GuzzleHttp\Psr7\AppendStream\getMetadata
getMetadata($key=null)
Definition: AppendStream.php:240
GuzzleHttp\Psr7\AppendStream\seek
seek($offset, $whence=SEEK_SET)
Definition: AppendStream.php:151
GuzzleHttp\Psr7\AppendStream\getSize
getSize()
Definition: AppendStream.php:119
GuzzleHttp\Psr7\AppendStream\__toString
__toString()
Definition: AppendStream.php:34
GuzzleHttp\Psr7\AppendStream\rewind
rewind()
Definition: AppendStream.php:141
GuzzleHttp\Psr7\AppendStream
Definition: AppendStream.php:11
GuzzleHttp\Psr7\AppendStream\write
write($string)
Definition: AppendStream.php:235
GuzzleHttp\Psr7\AppendStream\isReadable
isReadable()
Definition: AppendStream.php:220
GuzzleHttp\Psr7\AppendStream\getContents
getContents()
Definition: AppendStream.php:65
GuzzleHttp\Psr7\AppendStream\eof
eof()
Definition: AppendStream.php:134
GuzzleHttp\Psr7\copy_to_string
copy_to_string(StreamInterface $stream, $maxLen=-1)
Definition: guzzlehttp/psr7/src/functions.php:332
GuzzleHttp\Psr7\AppendStream\addStream
addStream(StreamInterface $stream)
Definition: AppendStream.php:51