src/Crypto/LazyDecryptStream.php (69 lines of code) (raw):

<?php declare(strict_types=1); namespace AlibabaCloud\Oss\V2\Crypto; use AlibabaCloud\Oss\V2\Utils; use Psr\Http\Message\StreamInterface; use Psr\Http\Message\ResponseInterface; use GuzzleHttp\Psr7\StreamDecoratorTrait; /** * Lazily decrypt data into the stream * Class LazyDecryptStream * @package AlibabaCloud\Oss\V2\Crypto */ final class LazyDecryptStream implements StreamInterface { use StreamDecoratorTrait; /** * @var StreamInterface */ private $stream; /** * @var int */ private $discardSize; /** * @var callable(ResponseInterface $response): ContentCipherInterface */ private $getContentCipher; private ?CipherInterface $cipher; private $discard; /** * @param StreamInterface $stream stream to lazily write * @param int $discardSize how many bytes need to be discarded * @param callable(ResponseInterface $response): ContentCipherInterface $getContentCipher */ public function __construct(StreamInterface $stream, int $discardSize, callable $getContentCipher) { $this->stream = $stream; $this->discardSize = $discardSize; $this->getContentCipher = $getContentCipher; $this->discard = $discardSize; $this->cipher = null; } public function on_headers(ResponseInterface $response) { /** * @var ContentCipherInterface $contentCipher * @var array $contentRange */ $contentCipher = ($this->getContentCipher)($response); if ($contentCipher != null) { $offset = 0; if ($response->hasHeader('content-range')) { $contentRange = $response->getHeader('content-range')[0]; $vals = Utils::parseContentRange($contentRange); if ($vals === false) { throw new \RuntimeException("parse Content-Range error, got $contentRange"); } $offset = $vals[0]; } $this->cipher = $contentCipher->getCipher($offset); } } public function rewind(): void { $this->discard = $this->discardSize; if ($this->cipher != null) { $this->cipher->reset(); } $this->seek(0); } public function write($string): int { $len = strlen($string); if ($len == 0) { return 0; } if ($this->cipher != null) { $string = $this->cipher->decrypt($string); } if ($this->discard > 0) { $min = min($this->discard, $len); $string = substr($string, $min); $this->discard -= $min; } $this->stream->write($string); return $len; } public function unwrap(): StreamInterface { return $this->stream; } }