123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- <?php
- declare(strict_types=1);
- namespace GuzzleHttp\Psr7;
- use Psr\Http\Message\StreamInterface;
- final class CachingStream implements StreamInterface
- {
- use StreamDecoratorTrait;
-
- private $remoteStream;
-
- private $skipReadBytes = 0;
-
- private $stream;
-
- public function __construct(
- StreamInterface $stream,
- StreamInterface $target = null
- ) {
- $this->remoteStream = $stream;
- $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
- }
- public function getSize(): ?int
- {
- $remoteSize = $this->remoteStream->getSize();
- if (null === $remoteSize) {
- return null;
- }
- return max($this->stream->getSize(), $remoteSize);
- }
- public function rewind(): void
- {
- $this->seek(0);
- }
- public function seek($offset, $whence = SEEK_SET): void
- {
- if ($whence === SEEK_SET) {
- $byte = $offset;
- } elseif ($whence === SEEK_CUR) {
- $byte = $offset + $this->tell();
- } elseif ($whence === SEEK_END) {
- $size = $this->remoteStream->getSize();
- if ($size === null) {
- $size = $this->cacheEntireStream();
- }
- $byte = $size + $offset;
- } else {
- throw new \InvalidArgumentException('Invalid whence');
- }
- $diff = $byte - $this->stream->getSize();
- if ($diff > 0) {
-
-
- while ($diff > 0 && !$this->remoteStream->eof()) {
- $this->read($diff);
- $diff = $byte - $this->stream->getSize();
- }
- } else {
-
- $this->stream->seek($byte);
- }
- }
- public function read($length): string
- {
-
- $data = $this->stream->read($length);
- $remaining = $length - strlen($data);
-
- if ($remaining) {
-
-
-
-
- $remoteData = $this->remoteStream->read(
- $remaining + $this->skipReadBytes
- );
- if ($this->skipReadBytes) {
- $len = strlen($remoteData);
- $remoteData = substr($remoteData, $this->skipReadBytes);
- $this->skipReadBytes = max(0, $this->skipReadBytes - $len);
- }
- $data .= $remoteData;
- $this->stream->write($remoteData);
- }
- return $data;
- }
- public function write($string): int
- {
-
-
-
-
- $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
- if ($overflow > 0) {
- $this->skipReadBytes += $overflow;
- }
- return $this->stream->write($string);
- }
- public function eof(): bool
- {
- return $this->stream->eof() && $this->remoteStream->eof();
- }
-
- public function close(): void
- {
- $this->remoteStream->close();
- $this->stream->close();
- }
- private function cacheEntireStream(): int
- {
- $target = new FnStream(['write' => 'strlen']);
- Utils::copyToStream($this, $target);
- return $this->tell();
- }
- }
|