wp_check_filetype_and_ext( string $file, string $filename, array $mimes = null )

Attempt to determine the real file type of a file.


Description

If unable to, the file name extension will be used to determine 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.

Currently this function only supports renaming images validated via wp_get_image_mime().


Parameters

$file

(Required) Full path to the file.

$filename

(Required) The name of the file (may differ from $file due to $file being in a tmp directory).

$mimes

(Optional) Key is the file extension with value as the mime type.

Default value: null


Return

(array) Values for the extension, MIME, and either a corrected filename or false if original $filename is valid.


Source

File: wp-includes/functions.php

function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
	$proper_filename = false;

	// Do basic extension validation and MIME mapping
	$wp_filetype = wp_check_filetype( $filename, $mimes );
	$ext = $wp_filetype['ext'];
	$type = $wp_filetype['type'];

	// We can't do any further validation without a file to work with
	if ( ! file_exists( $file ) ) {
		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 && $real_mime != $type ) {
			/**
			 * Filters the list mapping image mime types to their respective extensions.
			 *
			 * @since WP-3.0.0
			 *
			 * @param  array $mime_to_ext Array of image mime types and their matching extensions.
			 */
			$mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
				'image/jpeg' => 'jpg',
				'image/png'  => 'png',
				'image/gif'  => 'gif',
				'image/bmp'  => 'bmp',
				'image/tiff' => 'tif',
			) );

			// Replace whatever is after the last period in the filename with the correct extension
			if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
				$filename_parts = explode( '.', $filename );
				array_pop( $filename_parts );
				$filename_parts[] = $mime_to_ext[ $real_mime ];
				$new_filename = implode( '.', $filename_parts );

				if ( $new_filename != $filename ) {
					$proper_filename = $new_filename; // Mark that it changed
				}
				// Redefine the extension / MIME
				$wp_filetype = wp_check_filetype( $new_filename, $mimes );
				$ext = $wp_filetype['ext'];
				$type = $wp_filetype['type'];
			} else {
				// Reset $real_mime and try validating again.
				$real_mime = false;
			}
		}
	}

	// 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 );

		// fileinfo often misidentifies obscure files as one of these types
		$nonspecific_types = array(
			'application/octet-stream',
			'application/encrypted',
			'application/CDFV2-encrypted',
			'application/zip',
		);

		/*
		 * If $real_mime doesn't match the content type we're expecting from the file's extension,
		 * we need to do some additional vetting. Media types and those listed in $nonspecific_types are
		 * allowed some leeway, but anything else must exactly match the real content type.
		 */
		if ( in_array( $real_mime, $nonspecific_types, true ) ) {
			// File is a non-specific binary type. That's ok if it's a type that generally tends to be binary.
			if ( !in_array( substr( $type, 0, strcspn( $type, '/' ) ), array( 'application', 'video', 'audio' ) ) ) {
				$type = $ext = false;
			}
		} elseif ( 0 === strpos( $real_mime, 'video/' ) || 0 === strpos( $real_mime, 'audio/' ) ) {
			/*
			 * For these types, only the major type must match the real value.
			 * This means that common mismatches are forgiven: application/vnd.apple.numbers is often misidentified as application/zip,
			 * and some media files are commonly named with the wrong extension (.mov instead of .mp4)
			 */
			if ( substr( $real_mime, 0, strcspn( $real_mime, '/' ) ) !== substr( $type, 0, strcspn( $type, '/' ) ) ) {
				$type = $ext = false;
			}
		} elseif ( 'text/plain' === $real_mime ) {
			// A few common file types are occasionally detected as text/plain; allow those.
			if ( ! in_array(
				$type,
				array(
					'text/plain',
					'text/csv',
					'text/richtext',
					'text/tsv',
					'text/vtt',
				)
			)
			) {
				$type = $ext = false;
			}
		} elseif ( 'text/rtf' === $real_mime ) {
			// Special casing for RTF files.
			if ( ! in_array(
				$type,
				array(
					'text/rtf',
					'text/plain',
					'application/rtf',
				)
			)
			) {
				$type = $ext = false;
			}
		} else {
			if ( $type !== $real_mime ) {
				/*
				 * Everything else including image/* and application/*: 
				 * If the real content type doesn't match the file extension, assume it's dangerous.
				 */
				$type = $ext = false;
			}

		}
	}

	// The mime type must be allowed 
	if ( $type ) {
		$allowed = get_allowed_mime_types();

		if ( ! in_array( $type, $allowed ) ) {
			$type = $ext = false;
		}
	}

	/**
	 * Filters the "real" file type of the given file.
	 *
	 * @since WP-3.0.0
	 * @since WP-5.1.0 The $real_mime parameter was added.
	 *
	 * @param array       $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
	 *                                               'proper_filename' keys.
	 * @param string      $file                      Full path to the file.
	 * @param string      $filename                  The name of the file (may differ from $file due to
	 *                                               $file being in a tmp directory).
	 * @param array       $mimes                     Key is the file extension with value as the mime type.
	 * @param string|bool $real_mime                 The actual mime type or false if the type cannot be determined.
	 */
	return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes, $real_mime );
}


Changelog

Changelog
Version Description
WP-3.0.0 Introduced.