From e3db85985f4f490aad4ec9a299fa8d7e2c4f0f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 13 Apr 2023 10:12:33 +0200 Subject: [PATCH] Disallow cloning Stream objects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Streams hold a reference to the stateful resource handle for their actual contents. Cloning a Stream will not actually clone the underlying resource, thus both streams would still refer to the same resource after cloning and any changes in one stream object would be reflected in the other object. This violates user expectations after a cloning operation. Disallow cloning entirely as the safe default choice. Alternatively a new stream could be created and attached and the contents could be copied over. This can get expensive with larger or infinite streams, though. Signed-off-by: Tim Düsterhus --- src/Stream.php | 7 +++++++ test/StreamTest.php | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/Stream.php b/src/Stream.php index 96c0982e..c6de0458 100644 --- a/src/Stream.php +++ b/src/Stream.php @@ -364,4 +364,11 @@ private function isValidStreamResourceType(mixed $resource): bool return false; } + + /** + * Disallow stream cloning. + */ + private function __clone() + { + } } diff --git a/test/StreamTest.php b/test/StreamTest.php index 245d7bde..0503222d 100644 --- a/test/StreamTest.php +++ b/test/StreamTest.php @@ -5,6 +5,7 @@ namespace LaminasTest\Diactoros; use CurlHandle; +use Error; use GdImage; use InvalidArgumentException; use Laminas\Diactoros\Stream; @@ -679,4 +680,18 @@ public function testSizeReportsNullForPhpInputStreams(): void $stream = new Stream($resource); $this->assertNull($stream->getSize()); } + + public function testStreamsAreUnclonable(): void + { + $stream = new Stream(fopen('php://temp', 'r+')); + $stream->write('foo'); + + $this->assertSame('foo', $stream->__toString()); + + $this->expectException(Error::class); + $this->expectExceptionMessage('private Laminas\Diactoros\Stream::__clone()'); + + /** @psalm-suppress InvalidClone */ + clone $stream; + } }