From c33009ae3a307c943c32405f93bdadd6c4f8ed6b Mon Sep 17 00:00:00 2001 From: Howard Lopez Date: Fri, 1 Mar 2019 12:04:50 -0800 Subject: [PATCH 1/4] Modify S3 Stream Wrapper to work with PHP 7+ for empty file uploads --- src/S3/StreamWrapper.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/S3/StreamWrapper.php b/src/S3/StreamWrapper.php index 33954a186d..bba66c0992 100644 --- a/src/S3/StreamWrapper.php +++ b/src/S3/StreamWrapper.php @@ -94,6 +94,8 @@ class StreamWrapper /** @var string The opened protocol (e.g., "s3") */ private $protocol = 's3'; + private $isFlushed = false; + /** * Register the 's3://' stream wrapper * @@ -127,12 +129,16 @@ public static function register( public function stream_close() { + if ($this->body->getSize() === 0 && !($this->isFlushed)) { + $this->stream_flush(); + } $this->body = $this->cache = null; } public function stream_open($path, $mode, $options, &$opened_path) { $this->initProtocol($path); + $this->isFlushed = false; $this->params = $this->getBucketKey($path); $this->mode = rtrim($mode, 'bt'); @@ -156,6 +162,7 @@ public function stream_eof() public function stream_flush() { + $this->isFlushed = true; if ($this->mode == 'r') { return false; } From 6267c240e7d2bcd9ef729462713000bce3de4a99 Mon Sep 17 00:00:00 2001 From: Howard Lopez Date: Wed, 6 Mar 2019 14:08:06 -0800 Subject: [PATCH 2/4] Add test for empty file write using stream wrapper --- tests/S3/StreamWrapperTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/S3/StreamWrapperTest.php b/tests/S3/StreamWrapperTest.php index bd0ab9cac4..23f53eaf4b 100644 --- a/tests/S3/StreamWrapperTest.php +++ b/tests/S3/StreamWrapperTest.php @@ -170,6 +170,25 @@ public function testCanOpenWriteOnlyStreams() $this->assertEquals('test', (string) $cmd['Body']); } + public function testCanWriteEmptyFileToStream() + { + $history = new History(); + $this->client->getHandlerList()->appendSign(Middleware::history($history)); + $this->addMockResults($this->client, [new Result()]); + $s = fopen('s3://bucket/key', 'w'); + $this->assertEquals(0, fwrite($s, '')); + $this->assertTrue(fclose($s)); + + // Ensure that the stream was flushed even with zero characters, and + // that it only executed PutObject once. + $this->assertCount(1, $history); + $cmd = $history->getLastCommand(); + $this->assertEquals('PutObject', $cmd->getName()); + $this->assertEquals('bucket', $cmd['Bucket']); + $this->assertEquals('key', $cmd['Key']); + $this->assertEquals('', (string) $cmd['Body']); + } + /** * @expectedException \PHPUnit\Framework\Error\Warning * @expectedExceptionMessage 403 Forbidden From a71e1128f8d871903b0f6199e992810013a1de30 Mon Sep 17 00:00:00 2001 From: Howard Lopez Date: Wed, 6 Mar 2019 14:27:56 -0800 Subject: [PATCH 3/4] Add changelog --- .changes/nextrelease/stream_wrapper_fixes.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changes/nextrelease/stream_wrapper_fixes.json diff --git a/.changes/nextrelease/stream_wrapper_fixes.json b/.changes/nextrelease/stream_wrapper_fixes.json new file mode 100644 index 0000000000..8d79d0099f --- /dev/null +++ b/.changes/nextrelease/stream_wrapper_fixes.json @@ -0,0 +1,7 @@ +[ + { + "type": "feature", + "category": "S3", + "description": "Updates the S3 stream wrapper to be able to write empty files for PHP 7+." + } +] \ No newline at end of file From 56e1be2e276f81aa297878b325a71fd016ba4658 Mon Sep 17 00:00:00 2001 From: Howard Lopez Date: Wed, 6 Mar 2019 14:35:42 -0800 Subject: [PATCH 4/4] Add doc --- src/S3/StreamWrapper.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/S3/StreamWrapper.php b/src/S3/StreamWrapper.php index bba66c0992..fbf6183b67 100644 --- a/src/S3/StreamWrapper.php +++ b/src/S3/StreamWrapper.php @@ -94,6 +94,7 @@ class StreamWrapper /** @var string The opened protocol (e.g., "s3") */ private $protocol = 's3'; + /** @var bool Keeps track of whether stream has been flushed since opening */ private $isFlushed = false; /**