| 
<?phpnamespace GuzzleHttp\Psr7;
 
 use Psr\Http\Message\StreamInterface;
 
 /**
 * Provides a read only stream that pumps data from a PHP callable.
 *
 * When invoking the provided callable, the PumpStream will pass the amount of
 * data requested to read to the callable. The callable can choose to ignore
 * this value and return fewer or more bytes than requested. Any extra data
 * returned by the provided callable is buffered internally until drained using
 * the read() function of the PumpStream. The provided callable MUST return
 * false when there is no more data to read.
 */
 class PumpStream implements StreamInterface
 {
 /** @var callable */
 private $source;
 
 /** @var int */
 private $size;
 
 /** @var int */
 private $tellPos = 0;
 
 /** @var array */
 private $metadata;
 
 /** @var BufferStream */
 private $buffer;
 
 /**
 * @param callable $source Source of the stream data. The callable MAY
 *                         accept an integer argument used to control the
 *                         amount of data to return. The callable MUST
 *                         return a string when called, or false on error
 *                         or EOF.
 * @param array $options   Stream options:
 *                         - metadata: Hash of metadata to use with stream.
 *                         - size: Size of the stream, if known.
 */
 public function __construct(callable $source, array $options = [])
 {
 $this->source = $source;
 $this->size = isset($options['size']) ? $options['size'] : null;
 $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
 $this->buffer = new BufferStream();
 }
 
 public function __toString()
 {
 try {
 return copy_to_string($this);
 } catch (\Exception $e) {
 return '';
 }
 }
 
 public function close()
 {
 $this->detach();
 }
 
 public function detach()
 {
 $this->tellPos = false;
 $this->source = null;
 }
 
 public function getSize()
 {
 return $this->size;
 }
 
 public function tell()
 {
 return $this->tellPos;
 }
 
 public function eof()
 {
 return !$this->source;
 }
 
 public function isSeekable()
 {
 return false;
 }
 
 public function rewind()
 {
 $this->seek(0);
 }
 
 public function seek($offset, $whence = SEEK_SET)
 {
 throw new \RuntimeException('Cannot seek a PumpStream');
 }
 
 public function isWritable()
 {
 return false;
 }
 
 public function write($string)
 {
 throw new \RuntimeException('Cannot write to a PumpStream');
 }
 
 public function isReadable()
 {
 return true;
 }
 
 public function read($length)
 {
 $data = $this->buffer->read($length);
 $readLen = strlen($data);
 $this->tellPos += $readLen;
 $remaining = $length - $readLen;
 
 if ($remaining) {
 $this->pump($remaining);
 $data .= $this->buffer->read($remaining);
 $this->tellPos += strlen($data) - $readLen;
 }
 
 return $data;
 }
 
 public function getContents()
 {
 $result = '';
 while (!$this->eof()) {
 $result .= $this->read(1000000);
 }
 
 return $result;
 }
 
 public function getMetadata($key = null)
 {
 if (!$key) {
 return $this->metadata;
 }
 
 return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
 }
 
 private function pump($length)
 {
 if ($this->source) {
 do {
 $data = call_user_func($this->source, $length);
 if ($data === false || $data === null) {
 $this->source = null;
 return;
 }
 $this->buffer->write($data);
 $length -= strlen($data);
 } while ($length > 0);
 }
 }
 }
 
 |