Media: Reduce failing uploads following 4.7.1.

[39831] introduced more strict MIME type checking for uploads, which
resulted in unintetionally blocking several filetypes that were
previously valid. This change uses a more targeted approach to MIME
validation to restore previous behavior for most types.

Props blobfolio, iandunn, ipstenu, markoheijnen, xknown, joemcgill.
Merges [40124] and [40125] to the 4.7 branch.
Fixes #39550, #39552.


git-svn-id: https://develop.svn.wordpress.org/branches/4.7@40134 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Joe McGill 2017-02-27 19:27:58 +00:00
parent 9cf5b91e9c
commit f055694b32
5 changed files with 186 additions and 9 deletions

View File

@ -2268,15 +2268,15 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
return compact( 'ext', 'type', 'proper_filename' );
}
$real_mime = false;
// Validate image types.
if ( $type && 0 === strpos( $type, 'image/' ) ) {
// Attempt to figure out what type of image it actually is
$real_mime = wp_get_image_mime( $file );
if ( ! $real_mime ) {
$type = $ext = false;
} elseif ( $real_mime != $type ) {
if ( $real_mime && $real_mime != $type ) {
/**
* Filters the list mapping image mime types to their respective extensions.
*
@ -2307,18 +2307,29 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
$ext = $wp_filetype['ext'];
$type = $wp_filetype['type'];
} else {
$type = $ext = false;
// Reset $real_mime and try validating again.
$real_mime = false;
}
}
} elseif ( function_exists( 'finfo_file' ) ) {
// Use finfo_file if available to validate non-image files.
}
// Validate files that didn't get validated during previous checks.
if ( $type && ! $real_mime && extension_loaded( 'fileinfo' ) ) {
$finfo = finfo_open( FILEINFO_MIME_TYPE );
$real_mime = finfo_file( $finfo, $file );
finfo_close( $finfo );
// If the extension does not match the file's real type, return false.
if ( $real_mime !== $type ) {
$type = $ext = false;
/*
* If $real_mime doesn't match what we're expecting, we need to do some extra
* vetting of application mime types to make sure this type of file is allowed.
* Other mime types are assumed to be safe, but should be considered unverified.
*/
if ( $real_mime && ( $real_mime !== $type ) && ( 0 === strpos( $real_mime, 'application' ) ) ) {
$allowed = get_allowed_mime_types();
if ( ! in_array( $real_mime, $allowed ) ) {
$type = $ext = false;
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64" height="64">
<circle cx="32" cy="32" r="25" stroke="white" stroke-width="7" fill="black" fill-opacity="0.2"/>
<polygon points="26,22 26,42 43,32" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 274 B

View File

@ -898,4 +898,165 @@ class Tests_Functions extends WP_UnitTestCase {
$unique_uuids = array_unique( $uuids );
$this->assertEquals( $uuids, $unique_uuids );
}
/**
* @ticket 39550
* @dataProvider _wp_check_filetype_and_ext_data
*/
function test_wp_check_filetype_and_ext( $file, $filename, $expected ) {
if ( ! extension_loaded( 'fileinfo' ) ) {
$this->markTestSkipped( 'The fileinfo PHP extension is not loaded.' );
}
$this->assertEquals( $expected, wp_check_filetype_and_ext( $file, $filename ) );
}
/**
* @ticket 39550
*/
function test_wp_check_filetype_and_ext_with_filtered_svg() {
if ( ! extension_loaded( 'fileinfo' ) ) {
$this->markTestSkipped( 'The fileinfo PHP extension is not loaded.' );
}
if ( is_multisite() ) {
$this->markTestSkipped( 'Test does not run in multisite' );
}
$file = DIR_TESTDATA . '/uploads/video-play.svg';
$filename = 'video-play.svg';
$expected = array(
'ext' => 'svg',
'type' => 'image/svg+xml',
'proper_filename' => false,
);
add_filter( 'upload_mimes', array( $this, '_filter_mime_types_svg' ) );
$this->assertEquals( $expected, wp_check_filetype_and_ext( $file, $filename ) );
// Cleanup.
remove_filter( 'upload_mimes', array( $this, '_test_add_mime_types_svg' ) );
}
/**
* @ticket 39550
*/
function test_wp_check_filetype_and_ext_with_filtered_woff() {
if ( ! extension_loaded( 'fileinfo' ) ) {
$this->markTestSkipped( 'The fileinfo PHP extension is not loaded.' );
}
if ( is_multisite() ) {
$this->markTestSkipped( 'Test does not run in multisite' );
}
$file = DIR_TESTDATA . '/uploads/dashicons.woff';
$filename = 'dashicons.woff';
$expected = array(
'ext' => 'woff',
'type' => 'application/font-woff',
'proper_filename' => false,
);
add_filter( 'upload_mimes', array( $this, '_filter_mime_types_woff' ) );
$this->assertEquals( $expected, wp_check_filetype_and_ext( $file, $filename ) );
// Cleanup.
remove_filter( 'upload_mimes', array( $this, '_test_add_mime_types_woff' ) );
}
public function _filter_mime_types_svg( $mimes ) {
$mimes['svg'] = 'image/svg+xml';
return $mimes;
}
public function _filter_mime_types_woff( $mimes ) {
$mimes['woff'] = 'application/font-woff';
return $mimes;
}
public function _wp_check_filetype_and_ext_data() {
$data = array(
// Standard image.
array(
DIR_TESTDATA . '/images/canola.jpg',
'canola.jpg',
array(
'ext' => 'jpg',
'type' => 'image/jpeg',
'proper_filename' => false,
),
),
// Image with wrong extension.
array(
DIR_TESTDATA . '/images/test-image-mime-jpg.png',
'test-image-mime-jpg.png',
array(
'ext' => 'jpg',
'type' => 'image/jpeg',
'proper_filename' => 'test-image-mime-jpg.jpg',
),
),
// Image without extension.
array(
DIR_TESTDATA . '/images/test-image-no-extension',
'test-image-no-extension',
array(
'ext' => false,
'type' => false,
'proper_filename' => false,
),
),
// Valid non-image file with an image extension.
array(
DIR_TESTDATA . '/formatting/big5.txt',
'big5.jpg',
array(
'ext' => 'jpg',
'type' => 'image/jpeg',
'proper_filename' => false,
),
),
// Non-image file not allowed.
array(
DIR_TESTDATA . '/export/crazy-cdata.xml',
'crazy-cdata.xml',
array(
'ext' => false,
'type' => false,
'proper_filename' => false,
),
),
);
// Test a few additional file types on single sites.
if ( ! is_multisite() ) {
$data = array_merge( $data, array(
// Standard non-image file.
array(
DIR_TESTDATA . '/formatting/big5.txt',
'big5.txt',
array(
'ext' => 'txt',
'type' => 'text/plain',
'proper_filename' => false,
),
),
// Non-image file with wrong sub-type.
array(
DIR_TESTDATA . '/uploads/pages-to-word.docx',
'pages-to-word.docx',
array(
'ext' => 'docx',
'type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'proper_filename' => false,
),
),
) );
}
return $data;
}
}