diff options
author | Adam Silverstein <adamsilverstein@git.wordpress.org> | 2025-03-25 14:04:47 +0000 |
---|---|---|
committer | Adam Silverstein <adamsilverstein@git.wordpress.org> | 2025-03-25 14:04:47 +0000 |
commit | 0b536f1a8ea1a7ea2fb804d9d93e0dc9748f905f (patch) | |
tree | 372f39d6612df96d4c628389ba93dc7f81b97a8b | |
parent | 03ad616f90c6e505832c6de607c633647c8d7aaf (diff) | |
download | wordpress-0b536f1a8ea1a7ea2fb804d9d93e0dc9748f905f.tar.gz wordpress-0b536f1a8ea1a7ea2fb804d9d93e0dc9748f905f.zip |
Media: prevent uploading image types the server doesn’t support.
Normalize behavior between uploading in the media library and uploading directly to the block editor. Now, when uploading an image with a mime type the server does not support (either in the media library or the block editor), the user will see an error message “This image cannot be processed by the web server. Convert it to JPEG or PNG before uploading”.
Alos, add a new filter `wp_prevent_unsupported_mime_type_uploads` which determines whether the server should prevent uploads for image types it doesn't support. The default value is true and the filter also receives the uploaded image mime type.
Props: joomskys, adamsilverstein, azaozz, swissspidy, joemcgill, flixos90, audrasjb.
Fixes #61167
git-svn-id: https://develop.svn.wordpress.org/trunk@60084 602fd350-edb4-49c9-b593-d223f7449a82
3 files changed, 104 insertions, 7 deletions
diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 73a2585f84..5c0b5d0b38 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -2194,14 +2194,19 @@ function media_upload_form( $errors = null ) { $plupload_init['multi_selection'] = false; } - // Check if WebP images can be edited. - if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { - $plupload_init['webp_upload_error'] = true; - } + /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */ + $prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, null ); + + if ( $prevent_unsupported_uploads ) { + // Check if WebP images can be edited. + if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) { + $plupload_init['webp_upload_error'] = true; + } - // Check if AVIF images can be edited. - if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) { - $plupload_init['avif_upload_error'] = true; + // Check if AVIF images can be edited. + if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) { + $plupload_init['avif_upload_error'] = true; + } } /** diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index 0c98a729e4..4c49a1f335 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -134,6 +134,36 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller { array( 'status' => rest_authorization_required_code() ) ); } + $files = $request->get_file_params(); + + /** + * Filter whether the server should prevent uploads for image types it doesn't support. Default true. + * + * Developers can use this filter to enable uploads of certain image types. By default image types that are not + * supported by the server are prevented from being uploaded. + * + * @since 6.8.0 + * + * @param bool $check_mime Whether to prevent uploads of unsupported image types. + * @param string|null $mime_type The mime type of the file being uploaded (if available). + */ + $prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, isset( $files['file']['type'] ) ? $files['file']['type'] : null ); + + // If the upload is an image, check if the server can handle the mime type. + if ( + $prevent_unsupported_uploads && + isset( $files['file']['type'] ) && + str_starts_with( $files['file']['type'], 'image/' ) + ) { + // Check if the image editor supports the type. + if ( ! wp_image_editor_supports( array( 'mime_type' => $files['file']['type'] ) ) ) { + return new WP_Error( + 'rest_upload_image_type_not_supported', + __( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ), + array( 'status' => 400 ) + ); + } + } return true; } diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 5794bf944d..1fdaaa26e1 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -28,6 +28,11 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control private static $test_file2; /** + * @var string The path to the AVIF test image. + */ + private static $test_avif_file; + + /** * @var array The recorded posts query clauses. */ protected $posts_clauses; @@ -72,6 +77,9 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control if ( file_exists( self::$test_file2 ) ) { unlink( self::$test_file2 ); } + if ( file_exists( self::$test_avif_file ) ) { + unlink( self::$test_avif_file ); + } self::delete_user( self::$editor_id ); self::delete_user( self::$author_id ); @@ -101,6 +109,12 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control copy( $orig_file2, self::$test_file2 ); } + $orig_avif_file = DIR_TESTDATA . '/images/avif-lossy.avif'; + self::$test_avif_file = get_temp_dir() . 'avif-lossy.avif'; + if ( ! file_exists( self::$test_avif_file ) ) { + copy( $orig_avif_file, self::$test_avif_file ); + } + add_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 ); add_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 ); } @@ -2541,4 +2555,52 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control } ); } + + /** + * Test that uploading unsupported image types throws a `rest_upload_image_type_not_supported` error. + * + * @ticket 61167 + */ + public function test_upload_unsupported_image_type() { + + // Only run this test when the editor doesn't support AVIF. + if ( wp_image_editor_supports( array( 'AVIF' ) ) ) { + $this->markTestSkipped( 'The image editor suppports AVIF.' ); + } + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + + wp_set_current_user( self::$author_id ); + $request->set_header( 'Content-Type', 'image/avif' ); + $request->set_header( 'Content-Disposition', 'attachment; filename=avif-lossy.avif' ); + $request->set_body( file_get_contents( self::$test_avif_file ) ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertErrorResponse( 'rest_upload_image_type_not_supported', $response, 400 ); + } + + /** + * Test that the `wp_prevent_unsupported_image_uploads` filter enables uploading of unsupported image types. + * + * @ticket 61167 + */ + public function test_upload_unsupported_image_type_with_filter() { + + // Only run this test when the editor doesn't support AVIF. + if ( wp_image_editor_supports( array( 'AVIF' ) ) ) { + $this->markTestSkipped( 'The image editor suppports AVIF.' ); + } + + add_filter( 'wp_prevent_unsupported_image_uploads', '__return_false' ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + + wp_set_current_user( self::$author_id ); + $request->set_header( 'Content-Type', 'image/avif' ); + $request->set_header( 'Content-Disposition', 'attachment; filename=avif-lossy.avif' ); + $request->set_body( file_get_contents( self::$test_avif_file ) ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( 201, $response->get_status() ); + } } |