From 7fc225aa87c80680df01a0a82e6bb94b7773a34c Mon Sep 17 00:00:00 2001 From: Jonny Harris Date: Thu, 10 Mar 2022 13:08:19 +0000 Subject: [PATCH] =?UTF-8?q?Media:=20Store=20attachment=E2=80=99s=20file=20?= =?UTF-8?q?size=20in=20metadata.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store the file size of all newly uploaded attachments, as part of the metadata stored in post meta. Storing file size means, developers will not have to resort to doing `filesize` function calls, that can be time consuming on assets on offloaded to services like Amazon’s S3. This change also introduces a new helper function called, `wp_filesize`. This is a wrapper around the `filesize` php function, that adds some helpful filters and ensures the return value is an integer. Props Cybr, Spacedmonkey, SergeyBiryukov, johnwatkins0, swissspidy, desrosj, joemcgill, azaozz, antpb, adamsilverstein, uday17035. Fixes #49412. git-svn-id: https://develop.svn.wordpress.org/trunk@52837 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/file.php | 38 +++++++++++++++++++ src/wp-admin/includes/image.php | 17 +++++++-- src/wp-admin/includes/media.php | 2 +- src/wp-includes/class-wp-image-editor-gd.php | 1 + .../class-wp-image-editor-imagick.php | 1 + src/wp-includes/media.php | 2 +- src/wp-includes/post.php | 1 + tests/phpunit/tests/file.php | 35 +++++++++++++++++ tests/phpunit/tests/image/editorGd.php | 11 ++++++ tests/phpunit/tests/image/editorImagick.php | 11 ++++++ tests/phpunit/tests/image/functions.php | 37 ++++++++++++++---- 11 files changed, 142 insertions(+), 14 deletions(-) diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index ddd2be849a..759b0974bb 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -2555,3 +2555,41 @@ function wp_opcache_invalidate( $filepath, $force = false ) { return false; } + +/** + * Wrapper for PHP filesize with filters and casting the result as an integer. + * + * @since 6.0.0 + * + * @link https://www.php.net/manual/en/function.filesize.php + * + * @param string $path Path to the file. + * @return int The size of the file in bytes, or 0 in the event of an error. + */ +function wp_filesize( $path ) { + /** + * Filters the result of wp_filesize before the PHP function is run. + * + * @since 6.0.0 + * + * @param null|int $size The unfiltered value. Returning an int from the callback bypasses the filesize call. + * @param string $path Path to the file. + */ + $size = apply_filters( 'pre_wp_filesize', null, $path ); + + if ( is_int( $size ) ) { + return $size; + } + + $size = (int) @filesize( $path ); + + /** + * Filters the size of the file. + * + * @since 6.0.0 + * + * @param int $size The result of PHP filesize on the file. + * @param string $path Path to the file. + */ + return (int) apply_filters( 'wp_filesize', $size, $path ); +} diff --git a/src/wp-admin/includes/image.php b/src/wp-admin/includes/image.php index 627fdfb4b5..2818b3dd5d 100644 --- a/src/wp-admin/includes/image.php +++ b/src/wp-admin/includes/image.php @@ -210,6 +210,9 @@ function _wp_image_meta_replace_original( $saved_data, $original_file, $image_me // Store the original image file name in image_meta. $image_meta['original_image'] = wp_basename( $original_file ); + // Add image file size. + $image_meta['filesize'] = wp_filesize( $new_file ); + return $image_meta; } @@ -235,10 +238,11 @@ function wp_create_image_subsizes( $file, $attachment_id ) { // Default image meta. $image_meta = array( - 'width' => $imagesize[0], - 'height' => $imagesize[1], - 'file' => _wp_relative_upload_path( $file ), - 'sizes' => array(), + 'width' => $imagesize[0], + 'height' => $imagesize[1], + 'file' => _wp_relative_upload_path( $file ), + 'filesize' => wp_filesize( $file ), + 'sizes' => array(), ); // Fetch additional metadata from EXIF/IPTC. @@ -629,6 +633,11 @@ function wp_generate_attachment_metadata( $attachment_id, $file ) { // Remove the blob of binary data from the array. unset( $metadata['image']['data'] ); + // Capture file size for cases where it has not been captured yet, such as PDFs. + if ( ! isset( $metadata['filesize'] ) && file_exists( $file ) ) { + $metadata['filesize'] = wp_filesize( $file ); + } + /** * Filters the generated attachment meta data. * diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index d9dcbd5d7d..093ee69360 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -3378,7 +3378,7 @@ function attachment_submitbox_metadata() { if ( isset( $meta['filesize'] ) ) { $file_size = $meta['filesize']; } elseif ( file_exists( $file ) ) { - $file_size = filesize( $file ); + $file_size = wp_filesize( $file ); } if ( ! empty( $file_size ) ) { diff --git a/src/wp-includes/class-wp-image-editor-gd.php b/src/wp-includes/class-wp-image-editor-gd.php index f32e2b4202..f745bcf9f8 100644 --- a/src/wp-includes/class-wp-image-editor-gd.php +++ b/src/wp-includes/class-wp-image-editor-gd.php @@ -497,6 +497,7 @@ class WP_Image_Editor_GD extends WP_Image_Editor { 'width' => $this->size['width'], 'height' => $this->size['height'], 'mime-type' => $mime_type, + 'filesize' => wp_filesize( $filename ), ); } diff --git a/src/wp-includes/class-wp-image-editor-imagick.php b/src/wp-includes/class-wp-image-editor-imagick.php index d898db553a..fea2e5e4ef 100644 --- a/src/wp-includes/class-wp-image-editor-imagick.php +++ b/src/wp-includes/class-wp-image-editor-imagick.php @@ -729,6 +729,7 @@ class WP_Image_Editor_Imagick extends WP_Image_Editor { 'width' => $this->size['width'], 'height' => $this->size['height'], 'mime-type' => $mime_type, + 'filesize' => wp_filesize( $filename ), ); } diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index 5ab3cd1913..b3204c2799 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -4046,7 +4046,7 @@ function wp_prepare_attachment_for_js( $attachment ) { if ( isset( $meta['filesize'] ) ) { $bytes = $meta['filesize']; } elseif ( file_exists( $attached_file ) ) { - $bytes = filesize( $attached_file ); + $bytes = wp_filesize( $attached_file ); } else { $bytes = ''; } diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 10dddf859b..7cf8204e05 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -6538,6 +6538,7 @@ function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) { * @type array $sizes Keys are size slugs, each value is an array containing * 'file', 'width', 'height', and 'mime-type'. * @type array $image_meta Image metadata. + * @type int $filesize File size of the attachment. * } */ function wp_get_attachment_metadata( $attachment_id = 0, $unfiltered = false ) { diff --git a/tests/phpunit/tests/file.php b/tests/phpunit/tests/file.php index 311ba30339..cf3ec2d356 100644 --- a/tests/phpunit/tests/file.php +++ b/tests/phpunit/tests/file.php @@ -262,4 +262,39 @@ class Tests_File extends WP_UnitTestCase { return $keys; } + + /** + * @ticket 49412 + * @covers ::wp_filesize + */ + function test_wp_filesize_with_nonexistent_file() { + $file = 'nonexistent/file.jpg'; + $this->assertEquals( 0, wp_filesize( $file ) ); + } + + /** + * @ticket 49412 + * @covers ::wp_filesize + */ + function test_wp_filesize() { + $file = DIR_TESTDATA . '/images/test-image-upside-down.jpg'; + + $this->assertEquals( filesize( $file ), wp_filesize( $file ) ); + + $filter = function() { + return 999; + }; + + add_filter( 'wp_filesize', $filter ); + + $this->assertEquals( 999, wp_filesize( $file ) ); + + $pre_filter = function() { + return 111; + }; + + add_filter( 'pre_wp_filesize', $pre_filter ); + + $this->assertEquals( 111, wp_filesize( $file ) ); + } } diff --git a/tests/phpunit/tests/image/editorGd.php b/tests/phpunit/tests/image/editorGd.php index 781ff96cb4..5d967bdcdb 100644 --- a/tests/phpunit/tests/image/editorGd.php +++ b/tests/phpunit/tests/image/editorGd.php @@ -100,6 +100,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 50, 'height' => 33, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-50x33.jpg' ), ), ); @@ -300,6 +301,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 10, 'height' => 7, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-10x7.jpg' ), ), // #1 @@ -308,6 +310,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 75, 'height' => 50, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-75x50.jpg' ), ), // #2 @@ -316,6 +319,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 30, 'height' => 20, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-30x20.jpg' ), ), // #3 @@ -324,6 +328,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 45, 'height' => 400, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-45x400.jpg' ), ), // #4 @@ -332,6 +337,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 50, 'height' => 33, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-50x33.jpg' ), ), // #5 @@ -340,6 +346,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 55, 'height' => 37, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-55x37.jpg' ), ), // #6 @@ -348,6 +355,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 83, 'height' => 55, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-83x55.jpg' ), ), // #7 @@ -356,6 +364,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 90, 'height' => 60, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-90x60.jpg' ), ), // #8 @@ -364,6 +373,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 105, 'height' => 70, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-105x70.jpg' ), ), // #9 @@ -372,6 +382,7 @@ class Tests_Image_Editor_GD extends WP_Image_UnitTestCase { 'width' => 200, 'height' => 133, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-200x133.jpg' ), ), ); diff --git a/tests/phpunit/tests/image/editorImagick.php b/tests/phpunit/tests/image/editorImagick.php index e82486d828..02e0590a2e 100644 --- a/tests/phpunit/tests/image/editorImagick.php +++ b/tests/phpunit/tests/image/editorImagick.php @@ -90,6 +90,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 50, 'height' => 33, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-50x33.jpg' ), ), ); @@ -289,6 +290,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 10, 'height' => 7, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-10x7.jpg' ), ), // #1 @@ -297,6 +299,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 75, 'height' => 50, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-75x50.jpg' ), ), // #2 @@ -305,6 +308,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 30, 'height' => 20, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-30x20.jpg' ), ), // #3 @@ -313,6 +317,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 45, 'height' => 400, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-45x400.jpg' ), ), // #4 @@ -321,6 +326,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 50, 'height' => 33, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-50x33.jpg' ), ), // #5 @@ -329,6 +335,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 55, 'height' => 37, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-55x37.jpg' ), ), // #6 @@ -337,6 +344,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 83, 'height' => 55, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-83x55.jpg' ), ), // #7 @@ -345,6 +353,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 90, 'height' => 60, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-90x60.jpg' ), ), // #8 @@ -353,6 +362,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 105, 'height' => 70, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-105x70.jpg' ), ), // #9 @@ -361,6 +371,7 @@ class Tests_Image_Editor_Imagick extends WP_Image_UnitTestCase { 'width' => 200, 'height' => 133, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( dirname( $file ) . '/waffles-200x133.jpg' ), ), ); diff --git a/tests/phpunit/tests/image/functions.php b/tests/phpunit/tests/image/functions.php index 8cd42a13b5..c02862b3e7 100644 --- a/tests/phpunit/tests/image/functions.php +++ b/tests/phpunit/tests/image/functions.php @@ -479,40 +479,47 @@ class Tests_Image_Functions extends WP_UnitTestCase { $this->assertNotEmpty( $attachment_id ); + $temp_dir = get_temp_dir(); + + $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); + $expected = array( - 'sizes' => array( + 'sizes' => array( 'full' => array( 'file' => 'wordpress-gsoc-flyer-pdf.jpg', 'width' => 1088, 'height' => 1408, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf.jpg' ), ), 'medium' => array( 'file' => 'wordpress-gsoc-flyer-pdf-232x300.jpg', 'width' => 232, 'height' => 300, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-232x300.jpg' ), ), 'large' => array( 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', 'width' => 791, 'height' => 1024, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), ), 'thumbnail' => array( 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', 'width' => 116, 'height' => 150, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), ), ), + 'filesize' => wp_filesize( $test_file ), ); - $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); $this->assertSame( $expected, $metadata ); unlink( $test_file ); - $temp_dir = get_temp_dir(); foreach ( $metadata['sizes'] as $size ) { unlink( $temp_dir . $size['file'] ); } @@ -549,41 +556,49 @@ class Tests_Image_Functions extends WP_UnitTestCase { $this->assertNotEmpty( $attachment_id ); + $temp_dir = get_temp_dir(); + + $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); + $expected = array( - 'sizes' => array( + 'sizes' => array( 'full' => array( 'file' => 'wordpress-gsoc-flyer-pdf.jpg', 'width' => 1088, 'height' => 1408, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf.jpg' ), ), 'medium' => array( 'file' => 'wordpress-gsoc-flyer-pdf-300x300.jpg', 'width' => 300, 'height' => 300, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-300x300.jpg' ), ), 'large' => array( 'file' => 'wordpress-gsoc-flyer-pdf-791x1024.jpg', 'width' => 791, 'height' => 1024, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-791x1024.jpg' ), ), 'thumbnail' => array( 'file' => 'wordpress-gsoc-flyer-pdf-116x150.jpg', 'width' => 116, 'height' => 150, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-116x150.jpg' ), ), ), + 'filesize' => wp_filesize( $test_file ), ); - $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); $this->assertSame( $expected, $metadata ); unlink( $test_file ); foreach ( $metadata['sizes'] as $size ) { - unlink( get_temp_dir() . $size['file'] ); + unlink( $temp_dir . $size['file'] ); } } @@ -617,14 +632,21 @@ class Tests_Image_Functions extends WP_UnitTestCase { add_image_size( 'test-size', 100, 100 ); add_filter( 'fallback_intermediate_image_sizes', array( $this, 'filter_fallback_intermediate_image_sizes' ), 10, 2 ); + $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); + + $temp_dir = get_temp_dir(); + $expected = array( 'file' => 'wordpress-gsoc-flyer-pdf-77x100.jpg', 'width' => 77, 'height' => 100, 'mime-type' => 'image/jpeg', + 'filesize' => wp_filesize( $temp_dir . 'wordpress-gsoc-flyer-pdf-77x100.jpg' ), ); - $metadata = wp_generate_attachment_metadata( $attachment_id, $test_file ); + // Different environments produce slightly different filesize results. + $this->assertSame( $metadata['sizes']['test-size'], $expected ); + $this->assertArrayHasKey( 'test-size', $metadata['sizes'], 'The `test-size` was not added to the metadata.' ); $this->assertSame( $expected, $metadata['sizes']['test-size'] ); @@ -632,7 +654,6 @@ class Tests_Image_Functions extends WP_UnitTestCase { remove_filter( 'fallback_intermediate_image_sizes', array( $this, 'filter_fallback_intermediate_image_sizes' ), 10 ); unlink( $test_file ); - $temp_dir = get_temp_dir(); foreach ( $metadata['sizes'] as $size ) { unlink( $temp_dir . $size['file'] ); }