Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpdeclare(strict_types=1);namespace GuzzleHttp\Psr7;use Psr\Http\Message\StreamInterface;/*** Reads from multiple streams, one after the other.** This is a read-only stream decorator.*/final class AppendStream implements StreamInterface{/** @var StreamInterface[] Streams being decorated */private $streams = [];/** @var bool */private $seekable = true;/** @var int */private $current = 0;/** @var int */private $pos = 0;/*** @param StreamInterface[] $streams Streams to decorate. Each stream must* be readable.*/public function __construct(array $streams = []){foreach ($streams as $stream) {$this->addStream($stream);}}public function __toString(): string{try {$this->rewind();return $this->getContents();} 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 '';}}/*** Add a stream to the AppendStream** @param StreamInterface $stream Stream to append. Must be readable.** @throws \InvalidArgumentException if the stream is not readable*/public function addStream(StreamInterface $stream): void{if (!$stream->isReadable()) {throw new \InvalidArgumentException('Each stream must be readable');}// The stream is only seekable if all streams are seekableif (!$stream->isSeekable()) {$this->seekable = false;}$this->streams[] = $stream;}public function getContents(): string{return Utils::copyToString($this);}/*** Closes each attached stream.*/public function close(): void{$this->pos = $this->current = 0;$this->seekable = true;foreach ($this->streams as $stream) {$stream->close();}$this->streams = [];}/*** Detaches each attached stream.** Returns null as it's not clear which underlying stream resource to return.*/public function detach(){$this->pos = $this->current = 0;$this->seekable = true;foreach ($this->streams as $stream) {$stream->detach();}$this->streams = [];return null;}public function tell(): int{return $this->pos;}/*** Tries to calculate the size by adding the size of each stream.** If any of the streams do not return a valid number, then the size of the* append stream cannot be determined and null is returned.*/public function getSize(): ?int{$size = 0;foreach ($this->streams as $stream) {$s = $stream->getSize();if ($s === null) {return null;}$size += $s;}return $size;}public function eof(): bool{return !$this->streams ||($this->current >= count($this->streams) - 1 &&$this->streams[$this->current]->eof());}public function rewind(): void{$this->seek(0);}/*** Attempts to seek to the given position. Only supports SEEK_SET.*/public function seek($offset, $whence = SEEK_SET): void{if (!$this->seekable) {throw new \RuntimeException('This AppendStream is not seekable');} elseif ($whence !== SEEK_SET) {throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');}$this->pos = $this->current = 0;// Rewind each streamforeach ($this->streams as $i => $stream) {try {$stream->rewind();} catch (\Exception $e) {throw new \RuntimeException('Unable to seek stream '. $i . ' of the AppendStream', 0, $e);}}// Seek to the actual position by reading from each streamwhile ($this->pos < $offset && !$this->eof()) {$result = $this->read(min(8096, $offset - $this->pos));if ($result === '') {break;}}}/*** Reads from all of the appended streams until the length is met or EOF.*/public function read($length): string{$buffer = '';$total = count($this->streams) - 1;$remaining = $length;$progressToNext = false;while ($remaining > 0) {// Progress to the next stream if needed.if ($progressToNext || $this->streams[$this->current]->eof()) {$progressToNext = false;if ($this->current === $total) {break;}$this->current++;}$result = $this->streams[$this->current]->read($remaining);if ($result === '') {$progressToNext = true;continue;}$buffer .= $result;$remaining = $length - strlen($buffer);}$this->pos += strlen($buffer);return $buffer;}public function isReadable(): bool{return true;}public function isWritable(): bool{return false;}public function isSeekable(): bool{return $this->seekable;}public function write($string): int{throw new \RuntimeException('Cannot write to an AppendStream');}/*** {@inheritdoc}** @return mixed*/public function getMetadata($key = null){return $key ? null : [];}}