| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 | 
							- <?php
 
- declare(strict_types=1);
 
- namespace GuzzleHttp\Psr7;
 
- use Psr\Http\Message\StreamInterface;
 
- /**
 
-  * Stream decorator that can cache previously read bytes from a sequentially
 
-  * read stream.
 
-  */
 
- final class CachingStream implements StreamInterface
 
- {
 
-     use StreamDecoratorTrait;
 
-     /** @var StreamInterface Stream being wrapped */
 
-     private $remoteStream;
 
-     /** @var int Number of bytes to skip reading due to a write on the buffer */
 
-     private $skipReadBytes = 0;
 
-     /**
 
-      * @var StreamInterface
 
-      */
 
-     private $stream;
 
-     /**
 
-      * We will treat the buffer object as the body of the stream
 
-      *
 
-      * @param StreamInterface $stream Stream to cache. The cursor is assumed to be at the beginning of the stream.
 
-      * @param StreamInterface $target Optionally specify where data is cached
 
-      */
 
-     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) {
 
-             // Read the remoteStream until we have read in at least the amount
 
-             // of bytes requested, or we reach the end of the file.
 
-             while ($diff > 0 && !$this->remoteStream->eof()) {
 
-                 $this->read($diff);
 
-                 $diff = $byte - $this->stream->getSize();
 
-             }
 
-         } else {
 
-             // We can just do a normal seek since we've already seen this byte.
 
-             $this->stream->seek($byte);
 
-         }
 
-     }
 
-     public function read($length): string
 
-     {
 
-         // Perform a regular read on any previously read data from the buffer
 
-         $data = $this->stream->read($length);
 
-         $remaining = $length - strlen($data);
 
-         // More data was requested so read from the remote stream
 
-         if ($remaining) {
 
-             // If data was written to the buffer in a position that would have
 
-             // been filled from the remote stream, then we must skip bytes on
 
-             // the remote stream to emulate overwriting bytes from that
 
-             // position. This mimics the behavior of other PHP stream wrappers.
 
-             $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
 
-     {
 
-         // When appending to the end of the currently read stream, you'll want
 
-         // to skip bytes from being read from the remote stream to emulate
 
-         // other stream wrappers. Basically replacing bytes of data of a fixed
 
-         // length.
 
-         $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();
 
-     }
 
-     /**
 
-      * Close both the remote stream and buffer stream
 
-      */
 
-     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();
 
-     }
 
- }
 
 
  |