Skip to content

Commit 0b536f1

Browse files
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
1 parent 03ad616 commit 0b536f1

File tree

3 files changed

+104
-7
lines changed

3 files changed

+104
-7
lines changed

src/wp-admin/includes/media.php

+12-7
Original file line numberDiff line numberDiff line change
@@ -2194,14 +2194,19 @@ function media_upload_form( $errors = null ) {
21942194
$plupload_init['multi_selection'] = false;
21952195
}
21962196

2197-
// Check if WebP images can be edited.
2198-
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) {
2199-
$plupload_init['webp_upload_error'] = true;
2200-
}
2197+
/** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */
2198+
$prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, null );
2199+
2200+
if ( $prevent_unsupported_uploads ) {
2201+
// Check if WebP images can be edited.
2202+
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/webp' ) ) ) {
2203+
$plupload_init['webp_upload_error'] = true;
2204+
}
22012205

2202-
// Check if AVIF images can be edited.
2203-
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) {
2204-
$plupload_init['avif_upload_error'] = true;
2206+
// Check if AVIF images can be edited.
2207+
if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) {
2208+
$plupload_init['avif_upload_error'] = true;
2209+
}
22052210
}
22062211

22072212
/**

src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php

+30
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,36 @@ public function create_item_permissions_check( $request ) {
134134
array( 'status' => rest_authorization_required_code() )
135135
);
136136
}
137+
$files = $request->get_file_params();
138+
139+
/**
140+
* Filter whether the server should prevent uploads for image types it doesn't support. Default true.
141+
*
142+
* Developers can use this filter to enable uploads of certain image types. By default image types that are not
143+
* supported by the server are prevented from being uploaded.
144+
*
145+
* @since 6.8.0
146+
*
147+
* @param bool $check_mime Whether to prevent uploads of unsupported image types.
148+
* @param string|null $mime_type The mime type of the file being uploaded (if available).
149+
*/
150+
$prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, isset( $files['file']['type'] ) ? $files['file']['type'] : null );
151+
152+
// If the upload is an image, check if the server can handle the mime type.
153+
if (
154+
$prevent_unsupported_uploads &&
155+
isset( $files['file']['type'] ) &&
156+
str_starts_with( $files['file']['type'], 'image/' )
157+
) {
158+
// Check if the image editor supports the type.
159+
if ( ! wp_image_editor_supports( array( 'mime_type' => $files['file']['type'] ) ) ) {
160+
return new WP_Error(
161+
'rest_upload_image_type_not_supported',
162+
__( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ),
163+
array( 'status' => 400 )
164+
);
165+
}
166+
}
137167

138168
return true;
139169
}

tests/phpunit/tests/rest-api/rest-attachments-controller.php

+62
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ class WP_Test_REST_Attachments_Controller extends WP_Test_REST_Post_Type_Control
2727
*/
2828
private static $test_file2;
2929

30+
/**
31+
* @var string The path to the AVIF test image.
32+
*/
33+
private static $test_avif_file;
34+
3035
/**
3136
* @var array The recorded posts query clauses.
3237
*/
@@ -72,6 +77,9 @@ public static function wpTearDownAfterClass() {
7277
if ( file_exists( self::$test_file2 ) ) {
7378
unlink( self::$test_file2 );
7479
}
80+
if ( file_exists( self::$test_avif_file ) ) {
81+
unlink( self::$test_avif_file );
82+
}
7583

7684
self::delete_user( self::$editor_id );
7785
self::delete_user( self::$author_id );
@@ -101,6 +109,12 @@ public function set_up() {
101109
copy( $orig_file2, self::$test_file2 );
102110
}
103111

112+
$orig_avif_file = DIR_TESTDATA . '/images/avif-lossy.avif';
113+
self::$test_avif_file = get_temp_dir() . 'avif-lossy.avif';
114+
if ( ! file_exists( self::$test_avif_file ) ) {
115+
copy( $orig_avif_file, self::$test_avif_file );
116+
}
117+
104118
add_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 );
105119
add_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 );
106120
}
@@ -2541,4 +2555,52 @@ static function () {
25412555
}
25422556
);
25432557
}
2558+
2559+
/**
2560+
* Test that uploading unsupported image types throws a `rest_upload_image_type_not_supported` error.
2561+
*
2562+
* @ticket 61167
2563+
*/
2564+
public function test_upload_unsupported_image_type() {
2565+
2566+
// Only run this test when the editor doesn't support AVIF.
2567+
if ( wp_image_editor_supports( array( 'AVIF' ) ) ) {
2568+
$this->markTestSkipped( 'The image editor suppports AVIF.' );
2569+
}
2570+
2571+
$request = new WP_REST_Request( 'POST', '/wp/v2/media' );
2572+
2573+
wp_set_current_user( self::$author_id );
2574+
$request->set_header( 'Content-Type', 'image/avif' );
2575+
$request->set_header( 'Content-Disposition', 'attachment; filename=avif-lossy.avif' );
2576+
$request->set_body( file_get_contents( self::$test_avif_file ) );
2577+
$response = rest_get_server()->dispatch( $request );
2578+
2579+
$this->assertErrorResponse( 'rest_upload_image_type_not_supported', $response, 400 );
2580+
}
2581+
2582+
/**
2583+
* Test that the `wp_prevent_unsupported_image_uploads` filter enables uploading of unsupported image types.
2584+
*
2585+
* @ticket 61167
2586+
*/
2587+
public function test_upload_unsupported_image_type_with_filter() {
2588+
2589+
// Only run this test when the editor doesn't support AVIF.
2590+
if ( wp_image_editor_supports( array( 'AVIF' ) ) ) {
2591+
$this->markTestSkipped( 'The image editor suppports AVIF.' );
2592+
}
2593+
2594+
add_filter( 'wp_prevent_unsupported_image_uploads', '__return_false' );
2595+
2596+
$request = new WP_REST_Request( 'POST', '/wp/v2/media' );
2597+
2598+
wp_set_current_user( self::$author_id );
2599+
$request->set_header( 'Content-Type', 'image/avif' );
2600+
$request->set_header( 'Content-Disposition', 'attachment; filename=avif-lossy.avif' );
2601+
$request->set_body( file_get_contents( self::$test_avif_file ) );
2602+
$response = rest_get_server()->dispatch( $request );
2603+
2604+
$this->assertSame( 201, $response->get_status() );
2605+
}
25442606
}

0 commit comments

Comments
 (0)