diff --git a/src/StaticCaching/Cachers/Writer.php b/src/StaticCaching/Cachers/Writer.php index 82ac7558228..2696a120cbb 100644 --- a/src/StaticCaching/Cachers/Writer.php +++ b/src/StaticCaching/Cachers/Writer.php @@ -43,6 +43,15 @@ public function write($path, $content, $lockFor = 0) return false; } + // Truncate the file before writing. Since the "c" mode doesn't truncate and leaves + // the pointer at the start, writing content shorter than what's already on disk + // would otherwise leave stale bytes behind, producing an invalid document. + if (! ftruncate($handle, 0)) { + fclose($handle); + + return false; + } + fwrite($handle, $content); chmod($path, $this->permissions['file']); diff --git a/tests/StaticCaching/WriterTest.php b/tests/StaticCaching/WriterTest.php new file mode 100644 index 00000000000..1121515677e --- /dev/null +++ b/tests/StaticCaching/WriterTest.php @@ -0,0 +1,49 @@ +path = storage_path('framework/testing/static-cache-writer/page.html'); + + @unlink($this->path); + } + + public function tearDown(): void + { + @unlink($this->path); + @rmdir(dirname($this->path)); + + parent::tearDown(); + } + + #[Test] + public function it_writes_the_content_to_disk() + { + $written = (new Writer)->write($this->path, 'hello'); + + $this->assertTrue($written); + $this->assertSame('hello', file_get_contents($this->path)); + } + + #[Test] + public function it_truncates_stale_bytes_when_overwriting_with_shorter_content() + { + $writer = new Writer; + + $writer->write($this->path, 'this is a much longer page'); + $writer->write($this->path, 'short'); + + $this->assertSame('short', file_get_contents($this->path)); + } +}