File indexing completed on 2024-12-29 05:27:23

0001 <?php
0002 namespace GuzzleHttp\Psr7;
0003 
0004 use Psr\Http\Message\StreamInterface;
0005 
0006 /**
0007  * Provides a read only stream that pumps data from a PHP callable.
0008  *
0009  * When invoking the provided callable, the PumpStream will pass the amount of
0010  * data requested to read to the callable. The callable can choose to ignore
0011  * this value and return fewer or more bytes than requested. Any extra data
0012  * returned by the provided callable is buffered internally until drained using
0013  * the read() function of the PumpStream. The provided callable MUST return
0014  * false when there is no more data to read.
0015  */
0016 class PumpStream implements StreamInterface
0017 {
0018     /** @var callable */
0019     private $source;
0020 
0021     /** @var int */
0022     private $size;
0023 
0024     /** @var int */
0025     private $tellPos = 0;
0026 
0027     /** @var array */
0028     private $metadata;
0029 
0030     /** @var BufferStream */
0031     private $buffer;
0032 
0033     /**
0034      * @param callable $source Source of the stream data. The callable MAY
0035      *                         accept an integer argument used to control the
0036      *                         amount of data to return. The callable MUST
0037      *                         return a string when called, or false on error
0038      *                         or EOF.
0039      * @param array $options   Stream options:
0040      *                         - metadata: Hash of metadata to use with stream.
0041      *                         - size: Size of the stream, if known.
0042      */
0043     public function __construct(callable $source, array $options = [])
0044     {
0045         $this->source = $source;
0046         $this->size = isset($options['size']) ? $options['size'] : null;
0047         $this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
0048         $this->buffer = new BufferStream();
0049     }
0050 
0051     public function __toString()
0052     {
0053         try {
0054             return copy_to_string($this);
0055         } catch (\Exception $e) {
0056             return '';
0057         }
0058     }
0059 
0060     public function close()
0061     {
0062         $this->detach();
0063     }
0064 
0065     public function detach()
0066     {
0067         $this->tellPos = false;
0068         $this->source = null;
0069     }
0070 
0071     public function getSize()
0072     {
0073         return $this->size;
0074     }
0075 
0076     public function tell()
0077     {
0078         return $this->tellPos;
0079     }
0080 
0081     public function eof()
0082     {
0083         return !$this->source;
0084     }
0085 
0086     public function isSeekable()
0087     {
0088         return false;
0089     }
0090 
0091     public function rewind()
0092     {
0093         $this->seek(0);
0094     }
0095 
0096     public function seek($offset, $whence = SEEK_SET)
0097     {
0098         throw new \RuntimeException('Cannot seek a PumpStream');
0099     }
0100 
0101     public function isWritable()
0102     {
0103         return false;
0104     }
0105 
0106     public function write($string)
0107     {
0108         throw new \RuntimeException('Cannot write to a PumpStream');
0109     }
0110 
0111     public function isReadable()
0112     {
0113         return true;
0114     }
0115 
0116     public function read($length)
0117     {
0118         $data = $this->buffer->read($length);
0119         $readLen = strlen($data);
0120         $this->tellPos += $readLen;
0121         $remaining = $length - $readLen;
0122 
0123         if ($remaining) {
0124             $this->pump($remaining);
0125             $data .= $this->buffer->read($remaining);
0126             $this->tellPos += strlen($data) - $readLen;
0127         }
0128 
0129         return $data;
0130     }
0131 
0132     public function getContents()
0133     {
0134         $result = '';
0135         while (!$this->eof()) {
0136             $result .= $this->read(1000000);
0137         }
0138 
0139         return $result;
0140     }
0141 
0142     public function getMetadata($key = null)
0143     {
0144         if (!$key) {
0145             return $this->metadata;
0146         }
0147 
0148         return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
0149     }
0150 
0151     private function pump($length)
0152     {
0153         if ($this->source) {
0154             do {
0155                 $data = call_user_func($this->source, $length);
0156                 if ($data === false || $data === null) {
0157                     $this->source = null;
0158                     return;
0159                 }
0160                 $this->buffer->write($data);
0161                 $length -= strlen($data);
0162             } while ($length > 0);
0163         }
0164     }
0165 }