: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Returns first matched extension for the mime-type,
* as mapped from wp_get_mime_types().
* @param string $mime_type
function wp_get_default_extension_for_mime_type( $mime_type ) {
$extensions = explode( '|', array_search( $mime_type, wp_get_mime_types(), true ) );
if ( empty( $extensions[0] ) ) {
* Retrieves the file type from the file name.
* You can optionally define the mime array, if needed.
* @param string $filename File name or path.
* @param string[]|null $mimes Optional. Array of allowed mime types keyed by their file extension regex.
* Defaults to the result of get_allowed_mime_types().
* Values for the extension and mime type.
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
function wp_check_filetype( $filename, $mimes = null ) {
$mimes = get_allowed_mime_types();
foreach ( $mimes as $ext_preg => $mime_match ) {
$ext_preg = '!\.(' . $ext_preg . ')$!i';
if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
return compact( 'ext', 'type' );
* Attempts to determine the real file type of a file.
* 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().
* @param string $file Full path to the file.
* @param string $filename The name of the file (may differ from $file due to $file being
* @param string[]|null $mimes Optional. Array of allowed mime types keyed by their file extension regex.
* Defaults to the result of get_allowed_mime_types().
* Values for the extension, mime type, and corrected filename.
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
* @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
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' );
if ( $type && str_starts_with( $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.
* @param array $mime_to_ext Array of image mime types and their matching extensions.
$mime_to_ext = apply_filters(
'getimagesize_mimes_to_exts',
// 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'];
// Reset $real_mime and try validating again.
// 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 );
$google_docs_types = array(
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
foreach ( $google_docs_types as $google_docs_type ) {
* finfo_file() can return duplicate mime type for Google docs,
* this conditional reduces it to a single instance.
* @see https://bugs.php.net/bug.php?id=77784
* @see https://core.trac.wordpress.org/ticket/57898
if ( 2 === substr_count( $real_mime, $google_docs_type ) ) {
$real_mime = $google_docs_type;
// fileinfo often misidentifies obscure files as one of these types.
$nonspecific_types = array(
'application/octet-stream',
'application/CDFV2-encrypted',
* 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' ), true ) ) {
} elseif ( str_starts_with( $real_mime, 'video/' ) || str_starts_with( $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, '/' ) ) ) {
} elseif ( 'text/plain' === $real_mime ) {
// A few common file types are occasionally detected as text/plain; allow those.
} elseif ( 'application/csv' === $real_mime ) {
// Special casing for CSV files.
} elseif ( 'text/rtf' === $real_mime ) {
// Special casing for RTF files.
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.
// The mime type must be allowed.
$allowed = get_allowed_mime_types();
if ( ! in_array( $type, $allowed, true ) ) {
* Filters the "real" file type of the given file.
* @since 5.1.0 The $real_mime parameter was added.
* @param array $wp_check_filetype_and_ext {
* Values for the extension, mime type, and corrected filename.
* @type string|false $ext File extension, or false if the file doesn't match a mime type.
* @type string|false $type File mime type, or false if the file doesn't match a mime type.
* @type string|false $proper_filename File name with its correct extension, or false if it cannot be determined.
* @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 string[]|null $mimes Array of mime types keyed by their file extension regex, or null if
* @param string|false $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 );
* Returns the real mime type of an image file.
* This depends on exif_imagetype() or getimagesize() to determine real mime types.
* @since 5.8.0 Added support for WebP images.
* @since 6.5.0 Added support for AVIF images.
* @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 available. If either function throws an Exception
* we assume the file could not be validated.
if ( is_callable( 'exif_imagetype' ) ) {
$imagetype = exif_imagetype( $file );
$mime = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
} elseif ( function_exists( 'getimagesize' ) ) {
// Don't silence errors when in debug mode, unless running unit tests.
if ( defined( 'WP_DEBUG' ) && WP_DEBUG
&& ! defined( 'WP_RUN_CORE_TESTS' )
// Not using wp_getimagesize() here to avoid an infinite loop.
$imagesize = getimagesize( $file );
$imagesize = @getimagesize( $file );
$mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
$magic = file_get_contents( $file, false, null, 0, 12 );
if ( false === $magic ) {
* Add WebP fallback detection when image library doesn't support WebP.
* Note: detection values come from LibWebP, see
* https://github.com/webmproject/libwebp/blob/master/imageio/image_dec.c#L30
$magic = bin2hex( $magic );
( str_starts_with( $magic, '52494646' ) ) &&
( 16 === strpos( $magic, '57454250' ) )
* Add AVIF fallback detection when image library doesn't support AVIF.
* Detection based on section 4.3.1 File-type box definition of the ISO/IEC 14496-12
* specification and the AV1-AVIF spec, see https://aomediacodec.github.io/av1-avif/v1.1.0.html#brands.
// Divide the header string into 4 byte groups.
$magic = str_split( $magic, 8 );
'ftyp' === hex2bin( $magic[1] ) &&
( 'avif' === hex2bin( $magic[2] ) || 'avis' === hex2bin( $magic[2] ) )
} catch ( Exception $e ) {
* Retrieves the list of mime types and file extensions.
* @since 4.2.0 Support was added for GIMP (.xcf) files.
* @since 4.9.2 Support was added for Flac (.flac) files.
* @since 4.9.6 Support was added for AAC (.aac) files.
* @return string[] Array of mime types keyed by the file extension regex corresponding to those types.
function wp_get_mime_types() {
* Filters the list of mime types and file extensions.
* This filter should be used to add, not remove, mime types. To remove
* mime types, use the {@see 'upload_mimes'} filter.
* @param string[] $wp_get_mime_types Mime types keyed by the file extension regex
* corresponding to those types.
'jpg|jpeg|jpe' => 'image/jpeg',
'tiff|tif' => 'image/tiff',
'asf|asx' => 'video/x-ms-asf',
'wmv' => 'video/x-ms-wmv',
'wmx' => 'video/x-ms-wmx',
'mov|qt' => 'video/quicktime',
'mpeg|mpg|mpe' => 'video/mpeg',
'mp4|m4v' => 'video/mp4',
'mkv' => 'video/x-matroska',
'3gp|3gpp' => 'video/3gpp', // Can also be audio.
'3g2|3gp2' => 'video/3gpp2', // Can also be audio.
'txt|asc|c|cc|h|srt' => 'text/plain',
'tsv' => 'text/tab-separated-values',
'ics' => 'text/calendar',
'rtx' => 'text/richtext',
'htm|html' => 'text/html',
'dfxp' => 'application/ttaf+xml',
'mp3|m4a|m4b' => 'audio/mpeg',
'ra|ram' => 'audio/x-realaudio',
'ogg|oga' => 'audio/ogg',
'mid|midi' => 'audio/midi',
'wma' => 'audio/x-ms-wma',
'wax' => 'audio/x-ms-wax',
'mka' => 'audio/x-matroska',
// Misc application formats.
'rtf' => 'application/rtf',
'js' => 'application/javascript',
'pdf' => 'application/pdf',
'swf' => 'application/x-shockwave-flash',
'class' => 'application/java',
'tar' => 'application/x-tar',
'zip' => 'application/zip',
'gz|gzip' => 'application/x-gzip',
'rar' => 'application/rar',
'7z' => 'application/x-7z-compressed',
'exe' => 'application/x-msdownload',
'psd' => 'application/octet-stream',
'xcf' => 'application/octet-stream',
'doc' => 'application/msword',
'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
'wri' => 'application/vnd.ms-write',
'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
'mdb' => 'application/vnd.ms-access',
'mpp' => 'application/vnd.ms-project',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
'oxps' => 'application/oxps',
'xps' => 'application/vnd.ms-xpsdocument',
'odt' => 'application/vnd.oasis.opendocument.text',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',