123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- <?php
- declare(strict_types=1);
- namespace 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.
- */
- final class PumpStream implements StreamInterface
- {
- /** @var callable(int): (string|false|null)|null */
- private $source;
- /** @var int|null */
- private $size;
- /** @var int */
- private $tellPos = 0;
- /** @var array */
- private $metadata;
- /** @var BufferStream */
- private $buffer;
- /**
- * @param callable(int): (string|false|null) $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|null on error
- * or EOF.
- * @param array{size?: int, metadata?: 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 = $options['size'] ?? null;
- $this->metadata = $options['metadata'] ?? [];
- $this->buffer = new BufferStream();
- }
- public function __toString(): string
- {
- try {
- return Utils::copyToString($this);
- } catch (\Throwable $e) {
- if (\PHP_VERSION_ID >= 70400) {
- throw $e;
- }
- trigger_error(sprintf('%s::__toString exception: %s', self::class, (string) $e), E_USER_ERROR);
- return '';
- }
- }
- public function close(): void
- {
- $this->detach();
- }
- public function detach()
- {
- $this->tellPos = 0;
- $this->source = null;
- return null;
- }
- public function getSize(): ?int
- {
- return $this->size;
- }
- public function tell(): int
- {
- return $this->tellPos;
- }
- public function eof(): bool
- {
- return $this->source === null;
- }
- public function isSeekable(): bool
- {
- return false;
- }
- public function rewind(): void
- {
- $this->seek(0);
- }
- public function seek($offset, $whence = SEEK_SET): void
- {
- throw new \RuntimeException('Cannot seek a PumpStream');
- }
- public function isWritable(): bool
- {
- return false;
- }
- public function write($string): int
- {
- throw new \RuntimeException('Cannot write to a PumpStream');
- }
- public function isReadable(): bool
- {
- return true;
- }
- public function read($length): string
- {
- $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(): string
- {
- $result = '';
- while (!$this->eof()) {
- $result .= $this->read(1000000);
- }
- return $result;
- }
- /**
- * @return mixed
- */
- public function getMetadata($key = null)
- {
- if (!$key) {
- return $this->metadata;
- }
- return $this->metadata[$key] ?? null;
- }
- private function pump(int $length): void
- {
- if ($this->source !== null) {
- do {
- $data = ($this->source)($length);
- if ($data === false || $data === null) {
- $this->source = null;
- return;
- }
- $this->buffer->write($data);
- $length -= strlen($data);
- } while ($length > 0);
- }
- }
- }
|