Media: Improve image filetype checking.

This adds a new function `wp_get_image_mime()` which is used by
`wp_check_filetype_and_ext()` to validate image files using
`exif_imagetype()` if available instead of `getimagesize()`.

`getimagesize()` is less performant than `exif_imagetype()` and is
dependent on GD. If `exif_imagetype()` is not available, it falls back to
`getimagesize()` as before.

If `wp_check_filetype_and_ext()` can't validate the filetype, we now return
`false` for ext/MIME values.

Merges [39831] to the 4.1 branch.

Built from https://develop.svn.wordpress.org/branches/4.1@39838


git-svn-id: http://core.svn.wordpress.org/branches/4.1@39776 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Joe McGill 2017-01-11 13:18:53 +00:00
parent 4167b5b2cf
commit 6fd71daf13
1 changed files with 53 additions and 8 deletions

View File

@ -2068,7 +2068,7 @@ function wp_check_filetype( $filename, $mimes = null ) {
* If it's determined that the extension does not match the file's real type, * If it's determined that the extension does not match the file's real type,
* then the "proper_filename" value will be set with a proper filename and extension. * then the "proper_filename" value will be set with a proper filename and extension.
* *
* Currently this function only supports validating images known to getimagesize(). * Currently this function only supports renaming images validated via wp_get_image_mime().
* *
* @since 3.0.0 * @since 3.0.0
* *
@ -2093,14 +2093,15 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
return compact( 'ext', 'type', 'proper_filename' ); return compact( 'ext', 'type', 'proper_filename' );
} }
// We're able to validate images using GD // Validate image types.
if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) { if ( $type && 0 === strpos( $type, 'image/' ) ) {
// Attempt to figure out what type of image it actually is // Attempt to figure out what type of image it actually is
$imgstats = @getimagesize( $file ); $real_mime = wp_get_image_mime( $file );
// If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME if ( ! $real_mime ) {
if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) { $type = $ext = false;
} elseif ( $real_mime != $type ) {
/** /**
* Filter the list mapping image mime types to their respective extensions. * Filter the list mapping image mime types to their respective extensions.
* *
@ -2117,10 +2118,10 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
) ); ) );
// Replace whatever is after the last period in the filename with the correct extension // Replace whatever is after the last period in the filename with the correct extension
if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) { if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
$filename_parts = explode( '.', $filename ); $filename_parts = explode( '.', $filename );
array_pop( $filename_parts ); array_pop( $filename_parts );
$filename_parts[] = $mime_to_ext[ $imgstats['mime'] ]; $filename_parts[] = $mime_to_ext[ $real_mime ];
$new_filename = implode( '.', $filename_parts ); $new_filename = implode( '.', $filename_parts );
if ( $new_filename != $filename ) { if ( $new_filename != $filename ) {
@ -2130,8 +2131,20 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
$wp_filetype = wp_check_filetype( $new_filename, $mimes ); $wp_filetype = wp_check_filetype( $new_filename, $mimes );
$ext = $wp_filetype['ext']; $ext = $wp_filetype['ext'];
$type = $wp_filetype['type']; $type = $wp_filetype['type'];
} else {
$type = $ext = false;
} }
} }
} elseif ( function_exists( 'finfo_file' ) ) {
// Use finfo_file if available to validate non-image files.
$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;
}
} }
/** /**
@ -2149,6 +2162,38 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes ); return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
} }
/**
* Returns the real mime type of an image file.
*
* This depends on exif_imagetype() or getimagesize() to determine real mime types.
*
* @since 4.7.1
*
* @param string $file Full path to the file.
* @return string|false The actual mime type or false if the type cannot be determined.
*/
function wp_get_image_mime( $file ) {
/*
* Use exif_imagetype() to check the mimetype if available or fall back to
* getimagesize() if exif isn't avaialbe. If either function throws an Exception
* we assume the file could not be validated.
*/
try {
if ( ! is_callable( 'exif_imagetype' ) ) {
$mime = image_type_to_mime_type( exif_imagetype( $file ) );
} elseif ( function_exists( 'getimagesize' ) ) {
$imagesize = getimagesize( $file );
$mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
} else {
$mime = false;
}
} catch ( Exception $e ) {
$mime = false;
}
return $mime;
}
/** /**
* Retrieve list of mime types and file extensions. * Retrieve list of mime types and file extensions.
* *