From 9cf5b91e9c47b275e9482e9f12b33ff918361be6 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Mon, 27 Feb 2017 19:24:50 +0000 Subject: [PATCH] Media: Keep PDF previews from overwriting files. Since support for PDF previews were added in [38949], it's possible that the generated image file could overwrite an existing image file with the same name. This uses wp_unique_filename() to avoid this issue and adds a '-pdf' identifier on the end of filenames. Props gitlost, desrosj, mikeschroder, joemcgill. Merges [40130] and [40131] to the 4.7 branch. Fixes #39875. See #31050. git-svn-id: https://develop.svn.wordpress.org/branches/4.7@40133 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/image.php | 10 +++- tests/phpunit/tests/image/functions.php | 67 +++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/wp-admin/includes/image.php b/src/wp-admin/includes/image.php index 4ae53b9c3a..40cab01940 100644 --- a/src/wp-admin/includes/image.php +++ b/src/wp-admin/includes/image.php @@ -251,7 +251,15 @@ function wp_generate_attachment_metadata( $attachment_id, $file ) { $editor = wp_get_image_editor( $file ); if ( ! is_wp_error( $editor ) ) { // No support for this type of file - $uploaded = $editor->save( $file, 'image/jpeg' ); + /* + * PDFs may have the same file filename as JPEGs. + * Ensure the PDF preview image does not overwrite any JPEG images that already exist. + */ + $dirname = dirname( $file ) . '/'; + $ext = '.' . pathinfo( $file, PATHINFO_EXTENSION ); + $preview_file = $dirname . wp_unique_filename( $dirname, wp_basename( $file, $ext ) . '-pdf.jpg' ); + + $uploaded = $editor->save( $preview_file, 'image/jpeg' ); unset( $editor ); // Resize based on the full size image, rather than the source. diff --git a/tests/phpunit/tests/image/functions.php b/tests/phpunit/tests/image/functions.php index f17cbb923f..7ed2f0b1b2 100644 --- a/tests/phpunit/tests/image/functions.php +++ b/tests/phpunit/tests/image/functions.php @@ -18,6 +18,13 @@ class Tests_Image_Functions extends WP_UnitTestCase { require_once( ABSPATH . WPINC . '/class-wp-image-editor-imagick.php' ); include_once( DIR_TESTDATA . '/../includes/mock-image-editor.php' ); + + // Ensure no legacy / failed tests detritus. + $folder = '/tmp/wordpress-gsoc-flyer*.{jpg,pdf}'; + + foreach ( glob( $folder, GLOB_BRACE ) as $file ) { + unlink( $file ); + } } /** @@ -373,25 +380,25 @@ class Tests_Image_Functions extends WP_UnitTestCase { $expected = array( 'sizes' => array( 'thumbnail' => array( - 'file' => "wordpress-gsoc-flyer-116x150.jpg", + 'file' => "wordpress-gsoc-flyer-pdf-116x150.jpg", 'width' => 116, 'height' => 150, 'mime-type' => "image/jpeg", ), 'medium' => array( - 'file' => "wordpress-gsoc-flyer-232x300.jpg", + 'file' => "wordpress-gsoc-flyer-pdf-232x300.jpg", 'width' => 232, 'height' => 300, 'mime-type' => "image/jpeg", ), 'large' => array( - 'file' => "wordpress-gsoc-flyer-791x1024.jpg", + 'file' => "wordpress-gsoc-flyer-pdf-791x1024.jpg", 'width' => 791, 'height' => 1024, 'mime-type' => "image/jpeg", ), 'full' => array( - 'file' => "wordpress-gsoc-flyer.jpg", + 'file' => "wordpress-gsoc-flyer-pdf.jpg", 'width' => 1088, 'height' => 1408, 'mime-type' => "image/jpeg", @@ -403,6 +410,9 @@ class Tests_Image_Functions extends WP_UnitTestCase { $this->assertSame( $expected, $metadata ); unlink( $test_file ); + foreach ( $metadata['sizes'] as $size ) { + unlink ( '/tmp/' . $size['file'] ); + } } /** @@ -427,7 +437,7 @@ class Tests_Image_Functions extends WP_UnitTestCase { add_filter( 'fallback_intermediate_image_sizes', array( $this, 'filter_fallback_intermediate_image_sizes' ), 10, 2 ); $expected = array( - 'file' => 'wordpress-gsoc-flyer-77x100.jpg', + 'file' => 'wordpress-gsoc-flyer-pdf-77x100.jpg', 'width' => 77, 'height' => 100, 'mime-type' => 'image/jpeg', @@ -441,6 +451,9 @@ class Tests_Image_Functions extends WP_UnitTestCase { remove_filter( 'fallback_intermediate_image_sizes', array( $this, 'filter_fallback_intermediate_image_sizes' ), 10 ); unlink( $test_file ); + foreach ( $metadata['sizes'] as $size ) { + unlink ( '/tmp/' . $size['file'] ); + } } function filter_fallback_intermediate_image_sizes( $fallback_sizes, $metadata ) { @@ -449,4 +462,48 @@ class Tests_Image_Functions extends WP_UnitTestCase { return $fallback_sizes; } + + /** + * Test PDF preview doesn't overwrite existing JPEG. + * @ticket 39875 + */ + public function test_pdf_preview_doesnt_overwrite_existing_jpeg() { + if ( ! wp_image_editor_supports( array( 'mime_type' => 'application/pdf' ) ) ) { + $this->markTestSkipped( 'Rendering PDFs is not supported on this system.' ); + } + + // Dummy JPEGs. + $jpg1_path = '/tmp/test.jpg'; // Straight. + file_put_contents( $jpg1_path, 'asdf' ); + $jpg2_path = '/tmp/test-pdf.jpg'; // With PDF marker. + file_put_contents( $jpg2_path, 'fdsa' ); + + // PDF with same name as JPEG. + $pdf_path = '/tmp/test.pdf'; + copy( DIR_TESTDATA . '/images/wordpress-gsoc-flyer.pdf', $pdf_path ); + + $attachment_id = $this->factory->attachment->create_object( $pdf_path, 0, array( + 'post_mime_type' => 'application/pdf', + ) ); + + $metadata = wp_generate_attachment_metadata( $attachment_id, $pdf_path ); + $preview_path = '/tmp/' . $metadata['sizes']['full']['file']; + + // PDF preview didn't overwrite PDF. + $this->assertNotEquals( $pdf_path, $preview_path ); + // PDF preview didn't overwrite JPG with same name. + $this->assertNotEquals( $jpg1_path, $preview_path ); + $this->assertSame( 'asdf', file_get_contents( $jpg1_path ) ); + // PDF preview didn't overwrite PDF preview with same name. + $this->assertNotEquals( $jpg2_path, $preview_path ); + $this->assertSame( 'fdsa', file_get_contents( $jpg2_path ) ); + + // Cleanup. + unlink( $jpg1_path ); + unlink( $jpg2_path ); + unlink( $pdf_path ); + foreach ( $metadata['sizes'] as $size ) { + unlink( '/tmp/' . $size['file'] ); + } + } }