diff --git a/src/class-tiny-image-size.php b/src/class-tiny-image-size.php index e93040d5..d10af65c 100644 --- a/src/class-tiny-image-size.php +++ b/src/class-tiny-image-size.php @@ -22,11 +22,29 @@ class Tiny_Image_Size { public $filename; public $meta = array(); - /* Used more than once and not trivial, so we are memoizing these */ + /** + * Whether the file exists on disk. + * + * @var bool|null $exists + */ private $exists; + + /** + * File size in bytes. + * + * @var int|null $file_size + */ private $file_size; + + /** + * MIME type of the file. + * + * @var string|null $mime_type + */ private $mime_type; - private $duplicate = false; + + private $duplicate = false; + private $duplicate_of_size = ''; public function __construct( $filename = null ) { @@ -53,9 +71,26 @@ public function add_tiny_meta( $response ) { if ( isset( $this->meta['start'] ) ) { $this->meta = $response; $this->meta['end'] = time(); + $this->clear_memoized_filesystem(); } } + /** + * Clears the memoized exists/file_size/mime_type values. + * + * Must be called whenever the file on disk changed after those were + * memoized, e.g. after compression overwrites it, so the next read + * reflects the new file instead of the stale cached one. + * + * @return void + */ + private function clear_memoized_filesystem() { + clearstatcache( true, $this->filename ); + $this->exists = null; + $this->file_size = null; + $this->mime_type = null; + } + public function add_tiny_meta_error( $exception ) { if ( isset( $this->meta['start'] ) ) { $this->meta = array( diff --git a/test/unit/TinyImageSizeTest.php b/test/unit/TinyImageSizeTest.php index c77213ad..6015c823 100644 --- a/test/unit/TinyImageSizeTest.php +++ b/test/unit/TinyImageSizeTest.php @@ -58,6 +58,25 @@ public function test_add_tiny_meta_should_add_end_time() { $this->assertEqualWithinDelta( time(), $this->large->meta['end'], 2 ); } + /** + * After compression overwrites the file on disk, add_tiny_meta() must clear + * the memoized file_size so the next filesize() call reflects the new file + * rather than returning the stale pre-compression value. + */ + public function test_add_tiny_meta_clears_memoized_data_after_compression() { + $this->original->add_tiny_meta_start(); + $this->assertEquals( 137856, $this->original->filesize(), 'expected filesize to be original' ); + + file_put_contents( $this->original->filename, str_repeat( 'a', 90000 ) ); + + $this->original->add_tiny_meta( array( + 'input' => array( 'size' => 137856 ), + 'output' => array( 'size' => 90000 ), + ) ); + + $this->assertEquals( 90000, $this->original->filesize(), 'should return refreshed filesize' ); + } + public function test_add_response_should_response() { $this->large->add_tiny_meta_start(); $this->large->add_tiny_meta( array(