diff --git a/src/class-tiny-compress.php b/src/class-tiny-compress.php index d17f55c..236e888 100644 --- a/src/class-tiny-compress.php +++ b/src/class-tiny-compress.php @@ -96,7 +96,7 @@ public function get_status() { /** * Compresses a single file * - * @param [type] $file + * @param string $file path to file * @param array $resize_opts * @param array $preserve_opts * @param array{ string } conversion options diff --git a/src/class-tiny-image.php b/src/class-tiny-image.php index a586f43..99e6238 100644 --- a/src/class-tiny-image.php +++ b/src/class-tiny-image.php @@ -221,8 +221,9 @@ public function compress() { if ( ! $size->is_duplicate() ) { $size->add_tiny_meta_start(); $this->update_tiny_post_meta(); - $resize = $this->settings->get_resize_options( $size_name ); - $preserve = $this->settings->get_preserve_options( $size_name ); + $backup_created = $this->create_backup( $size_name, $size->filename ); + $resize = $this->settings->get_resize_options( $size_name ); + $preserve = $this->settings->get_preserve_options( $size_name ); Tiny_Logger::debug( 'compress size', array( @@ -238,6 +239,7 @@ public function compress() { 'has_been_compressed' => $size->has_been_compressed(), 'filesize' => $size->filesize(), 'mimetype' => $size->mimetype(), + 'backup' => $backup_created, ) ); try { @@ -605,4 +607,39 @@ public function mark_as_compressed() { $this->update_tiny_post_meta(); } + + /** + * creates a backup of the image as .bak. + * + * @param string $size_name name of the size + * @param string $filepath path to file that needs backup + * @return bool true when backup is created + */ + private function create_backup( $size_name, $filepath ) { + if ( ! $this->needs_backup( $size_name ) ) { + return false; + } + + $fileinfo = pathinfo( $filepath ); + $backup_file = sprintf( + '%s%s.bak.%s', + trailingslashit( $fileinfo['dirname'] ), + $fileinfo['filename'], + $fileinfo['extension'] + ); + + return copy( $filepath, $backup_file ); + } + + /** + * @param string $size_name name of the size + * @return bool true when backup needs to be created + */ + private function needs_backup( $size_name ) { + if ( ! self::is_original( $size_name ) ) { + return false; + } + + return $this->settings->get_backup_enabled(); + } } diff --git a/src/class-tiny-settings.php b/src/class-tiny-settings.php index 290b8b0..fa5bbe4 100644 --- a/src/class-tiny-settings.php +++ b/src/class-tiny-settings.php @@ -123,6 +123,9 @@ public function admin_init() { $field = self::get_prefixed_name( 'resize_original' ); register_setting( 'tinify', $field ); + $field = self::get_prefixed_name( 'backup' ); + register_setting( 'tinify', $field ); + $field = self::get_prefixed_name( 'preserve_data' ); register_setting( 'tinify', $field ); @@ -305,6 +308,16 @@ public function new_plugin_install() { return ! $compression_timing; } + public function get_backup_enabled() { + $sizes = $this->get_sizes(); + if ( ! $sizes[ Tiny_Image::ORIGINAL ]['tinify'] ) { + return false; + } + + $setting = get_option( self::get_prefixed_name( 'backup' ) ); + return isset( $setting['enabled'] ) && 'on' === $setting['enabled']; + } + public function get_resize_enabled() { /* This only applies if the original is being resized. */ $sizes = $this->get_sizes(); @@ -343,6 +356,12 @@ public function get_preserve_enabled( $name ) { return isset( $setting[ $name ] ) && 'on' === $setting[ $name ]; } + /** + * Retrieves the preserve options for the original image + * + * @param string - size name + * @return false|array false if size is not original, otherwise array of preserved keys + */ public function get_preserve_options( $size_name ) { if ( ! Tiny_Image::is_original( $size_name ) ) { return false; diff --git a/src/views/settings-original-image.php b/src/views/settings-original-image.php index 261dd8d..872055a 100644 --- a/src/views/settings-original-image.php +++ b/src/views/settings-original-image.php @@ -68,6 +68,28 @@ +

+ get_backup_enabled(); + ?> + /> + +

+ render_preserve_input( 'creation', diff --git a/test/helpers/wordpress.php b/test/helpers/wordpress.php index ff1b2c0..50c0b32 100644 --- a/test/helpers/wordpress.php +++ b/test/helpers/wordpress.php @@ -282,6 +282,14 @@ public function createImage($file_size, $path, $name) ->at($dir); } + /** + * Creates images on the virtual disk for testing + * @param null|array $sizes Array of size => bytes to create, file will be named $name-$size.png + * @param int $original_size Bytes of image + * @param string $path Path to image + * @param string $name Name of the image + * @return void + */ public function createImages($sizes = null, $original_size = 12345, $path = '14/01', $name = 'test') { vfsStream::newDirectory(self::UPLOAD_DIR . "/$path")->at($this->vfs); @@ -309,6 +317,13 @@ public function createImagesFromJSON($virtual_images) } } + /** + * creates image meta data for testing + * + * @param string $path directory of the file in UPLOAD_DIR + * @param string $name name of the file without extension + * @return array object containing metadata + */ public function getTestMetadata($path = '14/01', $name = 'test') { $metadata = array( diff --git a/test/unit/TinyImageTest.php b/test/unit/TinyImageTest.php index f70f3b4..6f73c39 100644 --- a/test/unit/TinyImageTest.php +++ b/test/unit/TinyImageTest.php @@ -306,4 +306,94 @@ public function test_conversion_same_mimetype() // second call should be only with image/webp because first call was a image/webp $this->assertEquals(array('image/webp'), $compress_calls[1]['convert_to']); } + + public function test_creates_backup_of_original_image() { + $this->wp->addOption('tinypng_backup', array( + 'enabled' => 'on', + )); + $this->wp->addOption('tinypng_sizes', array( + Tiny_Image::ORIGINAL => 'on', + )); + $this->wp->stub('get_post_mime_type', function () { + return 'image/png'; + }); + + $input_dir = '26/03'; + $input_name = 'testforbackup'; + $this->wp->createImages(array(), 1000, $input_dir, $input_name); + + $settings = new Tiny_Settings(); + $mock_compressor = $this->createMock(Tiny_Compress::class); + $settings->set_compressor($mock_compressor); + + $metadata = $this->wp->getTestMetadata($input_dir, $input_name); + $tinyimg = new Tiny_Image($settings, 999, $metadata); + $tinyimg->compress(); + + $this->assertTrue( + file_exists( $this->vfs->url() . '/wp-content/uploads/' . $input_dir . '/' . $input_name . '.bak.png' ) , + 'backup of file should be created'); + } + + public function test_will_not_backup_other_sizes() { + $this->wp->addOption('tinypng_backup', array( + 'enabled' => 'on', + )); + $this->wp->addOption('tinypng_sizes', array( + 'thumbnail' => 'on', + )); + $this->wp->stub('get_post_mime_type', function () { + return 'image/png'; + }); + + $input_dir = '26/03'; + $input_name = 'testforbackup'; + $this->wp->createImages(array( + 'thumbnail' => 1000, + ), 1000, $input_dir, $input_name); + + $settings = new Tiny_Settings(); + $mock_compressor = $this->createMock(Tiny_Compress::class); + $settings->set_compressor($mock_compressor); + + $metadata = $this->wp->getTestMetadata($input_dir, $input_name); + $tinyimg = new Tiny_Image($settings, 999, $metadata); + $tinyimg->compress(); + + $this->assertFalse( + file_exists( $this->vfs->url() . '/wp-content/uploads/' . $input_dir . '/' . $input_name . '.bak.png' ) , + 'backup of original should not exist'); + + $this->assertFalse( + file_exists( $this->vfs->url() . '/wp-content/uploads/' . $input_dir . '/' . $input_name . '-thumbnail.bak.png' ) , + 'backup of thumbnail should not exist'); + } + + public function test_will_not_backup_when_disabled() { + $this->wp->addOption('tinypng_backup', array( + 'enabled' => false, + )); + $this->wp->addOption('tinypng_sizes', array( + Tiny_Image::ORIGINAL => 'on', + )); + $this->wp->stub('get_post_mime_type', function () { + return 'image/png'; + }); + + $input_dir = '26/03'; + $input_name = 'testforbackup'; + $this->wp->createImages(array(), 1000, $input_dir, $input_name); + + $settings = new Tiny_Settings(); + $mock_compressor = $this->createMock(Tiny_Compress::class); + $settings->set_compressor($mock_compressor); + + $metadata = $this->wp->getTestMetadata($input_dir, $input_name); + $tinyimg = new Tiny_Image($settings, 999, $metadata); + $tinyimg->compress(); + + $this->assertFalse( + file_exists( $this->vfs->url() . '/wp-content/uploads/' . $input_dir . '/' . $input_name . '.bak.png' ) , + 'backup of original should not exist'); + } } diff --git a/test/unit/TinyTestCase.php b/test/unit/TinyTestCase.php index 4838a40..c64f22d 100644 --- a/test/unit/TinyTestCase.php +++ b/test/unit/TinyTestCase.php @@ -40,6 +40,11 @@ public static function client_supported() { } abstract class Tiny_TestCase extends TestCase { + /** + * WordPress stubs + * + * @var \WordPressStubs + */ protected $wp; protected $vfs;