From db42241c1397b20213eb1be652bbeaa28174e665 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Wed, 11 Jan 2017 13:14:33 +0000 Subject: [PATCH] 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.6 branch. Built from https://develop.svn.wordpress.org/branches/4.6@39833 git-svn-id: http://core.svn.wordpress.org/branches/4.6@39771 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/functions.php | 61 ++++++++++++++++++++++++++++++++++----- wp-includes/version.php | 2 +- 2 files changed, 54 insertions(+), 9 deletions(-) diff --git a/wp-includes/functions.php b/wp-includes/functions.php index ff09f3459d..9d52b00474 100644 --- a/wp-includes/functions.php +++ b/wp-includes/functions.php @@ -2234,7 +2234,7 @@ function wp_check_filetype( $filename, $mimes = null ) { * 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. * - * 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 * @@ -2258,14 +2258,15 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { return compact( 'ext', 'type', 'proper_filename' ); } - // We're able to validate images using GD - if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) { + // Validate image types. + if ( $type && 0 === strpos( $type, 'image/' ) ) { // 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 ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) { + if ( ! $real_mime ) { + $type = $ext = false; + } elseif ( $real_mime != $type ) { /** * Filters the list mapping image mime types to their respective extensions. * @@ -2282,10 +2283,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 - if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) { + if ( ! empty( $mime_to_ext[ $real_mime ] ) ) { $filename_parts = explode( '.', $filename ); array_pop( $filename_parts ); - $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ]; + $filename_parts[] = $mime_to_ext[ $real_mime ]; $new_filename = implode( '.', $filename_parts ); if ( $new_filename != $filename ) { @@ -2295,8 +2296,20 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) { $wp_filetype = wp_check_filetype( $new_filename, $mimes ); $ext = $wp_filetype['ext']; $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; + } } /** @@ -2314,6 +2327,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 ); } +/** + * 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. * diff --git a/wp-includes/version.php b/wp-includes/version.php index c2356ac53d..36295a8d3b 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.6.2-alpha-39821'; +$wp_version = '4.6.2-alpha-39833'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.