From 76e46a97e49f8f760cddd6e793ce8831cc871466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20P=C4=83tr=C4=83nescu?= Date: Wed, 17 Dec 2025 12:40:26 +0200 Subject: [PATCH 1/2] Check resource before closing stream handle --- src/Flysystem/StreamWrapper.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Flysystem/StreamWrapper.php b/src/Flysystem/StreamWrapper.php index c82c1f8..873bca5 100755 --- a/src/Flysystem/StreamWrapper.php +++ b/src/Flysystem/StreamWrapper.php @@ -71,6 +71,10 @@ public function stream_close(): void E_USER_WARNING ); } + + if (!is_resource($this->current->handle)) { + return; + } } fclose($this->current->handle); From 88c99ca3eade91d3f377f627e85e6fc0848378af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandru=20P=C4=83tr=C4=83nescu?= Date: Fri, 19 Dec 2025 17:13:51 +0200 Subject: [PATCH 2/2] Add test case for when the adapter closes the stream on the workOnLocalCopy flow --- tests/Issues/AdapterClosesStreamTest.php | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/Issues/AdapterClosesStreamTest.php b/tests/Issues/AdapterClosesStreamTest.php index 144c554..b27c568 100644 --- a/tests/Issues/AdapterClosesStreamTest.php +++ b/tests/Issues/AdapterClosesStreamTest.php @@ -9,7 +9,10 @@ namespace M2MTech\FlysystemStreamWrapper\Tests\Issues; +use League\Flysystem\FilesystemOperator; +use M2MTech\FlysystemStreamWrapper\Flysystem\FileData; use M2MTech\FlysystemStreamWrapper\Flysystem\StreamWrapper; +use M2MTech\FlysystemStreamWrapper\FlysystemStreamWrapper; use M2MTech\FlysystemStreamWrapper\Tests\Assert; use M2MTech\FlysystemStreamWrapper\Tests\StreamCommand\AbstractStreamCommandTestCase; @@ -34,4 +37,32 @@ public function testStreamClose(): void $wrapper->stream_close(); $this->assertIsClosedResource($current->handle); } + + public function testStreamCloseWithLocalCopy(): void + { + $filesystem = $this->createMock(FilesystemOperator::class); + FlysystemStreamWrapper::register(self::TEST_PROTOCOL, $filesystem); + + $current = new FileData(); + $current->setPath(self::TEST_PATH); + + $current->handle = fopen('php://temp', 'wb'); + $current->workOnLocalCopy = true; + + $wrapper = new StreamWrapper($current); + + if (!is_resource($current->handle)) { + $this->fail(); + } + + $filesystem->expects($this->once()) + ->method('writeStream') + ->willReturnCallback(static function (string $file, $handle) { + // adapter closes the stream itself after writing it to file + fclose($handle); + }); + + $wrapper->stream_close(); + $this->assertIsClosedResource($current->handle); + } }