GuzzleHttpPsr7AppendStream

Reads from multiple streams, one after the other.

Defined (1)

The class is defined in the following location(s).

/lib/Azure/GuzzleHttp/Psr7/AppendStream.php  
  1. class AppendStream implements StreamInterface 
  2. /** @var StreamInterface[] Streams being decorated */ 
  3. private $streams = []; 
  4.  
  5. private $seekable = true; 
  6. private $current = 0; 
  7. private $pos = 0; 
  8. private $detached = false; 
  9.  
  10. /** 
  11. * @param StreamInterface[] $streams Streams to decorate. Each stream must 
  12. * be readable. 
  13. */ 
  14. public function __construct(array $streams = []) 
  15. foreach ($streams as $stream) { 
  16. $this->addStream($stream); 
  17.  
  18. public function __toString() 
  19. try { 
  20. $this->rewind(); 
  21. return $this->getContents(); 
  22. } catch (\Exception $e) { 
  23. return ''; 
  24.  
  25. /** 
  26. * Add a stream to the AppendStream 
  27. * @param StreamInterface $stream Stream to append. Must be readable. 
  28. * @throws \InvalidArgumentException if the stream is not readable 
  29. */ 
  30. public function addStream(StreamInterface $stream) 
  31. if (!$stream->isReadable()) { 
  32. throw new \InvalidArgumentException('Each stream must be readable'); 
  33.  
  34. // The stream is only seekable if all streams are seekable 
  35. if (!$stream->isSeekable()) { 
  36. $this->seekable = false; 
  37.  
  38. $this->streams[] = $stream; 
  39.  
  40. public function getContents() 
  41. return copy_to_string($this); 
  42.  
  43. /** 
  44. * Closes each attached stream. 
  45. * {@inheritdoc} 
  46. */ 
  47. public function close() 
  48. $this->pos = $this->current = 0; 
  49.  
  50. foreach ($this->streams as $stream) { 
  51. $stream->close(); 
  52.  
  53. $this->streams = []; 
  54.  
  55. /** 
  56. * Detaches each attached stream 
  57. * {@inheritdoc} 
  58. */ 
  59. public function detach() 
  60. $this->close(); 
  61. $this->detached = true; 
  62.  
  63. public function tell() 
  64. return $this->pos; 
  65.  
  66. /** 
  67. * Tries to calculate the size by adding the size of each stream. 
  68. * If any of the streams do not return a valid number, then the size of the 
  69. * append stream cannot be determined and null is returned. 
  70. * {@inheritdoc} 
  71. */ 
  72. public function getSize() 
  73. $size = 0; 
  74.  
  75. foreach ($this->streams as $stream) { 
  76. $s = $stream->getSize(); 
  77. if ($s === null) { 
  78. return null; 
  79. $size += $s; 
  80.  
  81. return $size; 
  82.  
  83. public function eof() 
  84. return !$this->streams || 
  85. ($this->current >= count($this->streams) - 1 && 
  86. $this->streams[$this->current]->eof()); 
  87.  
  88. public function rewind() 
  89. $this->seek(0); 
  90.  
  91. /** 
  92. * Attempts to seek to the given position. Only supports SEEK_SET. 
  93. * {@inheritdoc} 
  94. */ 
  95. public function seek($offset, $whence = SEEK_SET) 
  96. if (!$this->seekable) { 
  97. throw new \RuntimeException('This AppendStream is not seekable'); 
  98. } elseif ($whence !== SEEK_SET) { 
  99. throw new \RuntimeException('The AppendStream can only seek with SEEK_SET'); 
  100.  
  101. $this->pos = $this->current = 0; 
  102.  
  103. // Rewind each stream 
  104. foreach ($this->streams as $i => $stream) { 
  105. try { 
  106. $stream->rewind(); 
  107. } catch (\Exception $e) { 
  108. throw new \RuntimeException('Unable to seek stream ' 
  109. . $i . ' of the AppendStream', 0, $e); 
  110.  
  111. // Seek to the actual position by reading from each stream 
  112. while ($this->pos < $offset && !$this->eof()) { 
  113. $result = $this->read(min(8096, $offset - $this->pos)); 
  114. if ($result === '') { 
  115. break; 
  116.  
  117. /** 
  118. * Reads from all of the appended streams until the length is met or EOF. 
  119. * {@inheritdoc} 
  120. */ 
  121. public function read($length) 
  122. $buffer = ''; 
  123. $total = count($this->streams) - 1; 
  124. $remaining = $length; 
  125. $progressToNext = false; 
  126.  
  127. while ($remaining > 0) { 
  128.  
  129. // Progress to the next stream if needed. 
  130. if ($progressToNext || $this->streams[$this->current]->eof()) { 
  131. $progressToNext = false; 
  132. if ($this->current === $total) { 
  133. break; 
  134. $this->current++; 
  135.  
  136. $result = $this->streams[$this->current]->read($remaining); 
  137.  
  138. // Using a loose comparison here to match on '', false, and null 
  139. if ($result == null) { 
  140. $progressToNext = true; 
  141. continue; 
  142.  
  143. $buffer .= $result; 
  144. $remaining = $length - strlen($buffer); 
  145.  
  146. $this->pos += strlen($buffer); 
  147.  
  148. return $buffer; 
  149.  
  150. public function isReadable() 
  151. return true; 
  152.  
  153. public function isWritable() 
  154. return false; 
  155.  
  156. public function isSeekable() 
  157. return $this->seekable; 
  158.  
  159. public function write($string) 
  160. throw new \RuntimeException('Cannot write to an AppendStream'); 
  161.  
  162. public function getMetadata($key = null) 
  163. return $key ? null : [];