wp_check_filetype_and_ext()
云策文档标注
概述
wp_check_filetype_and_ext() 函数用于验证文件类型,特别是图像文件,通过检测实际 MIME 类型与扩展名是否匹配,并在不匹配时提供正确的文件名和扩展名。它主要依赖 wp_get_image_mime() 进行图像验证,并支持通过 Hook 过滤 MIME 类型映射。
关键要点
- 函数尝试确定文件的真实类型,若无法确定则使用文件扩展名;若扩展名与真实类型不匹配,会设置 proper_filename 值以提供正确的文件名和扩展名。
- 目前仅支持通过 wp_get_image_mime() 验证的图像类型,包括 JPEG、PNG、GIF、BMP、TIFF、WebP、AVIF 和 HEIC 等格式。
- 参数包括 $file(文件路径)、$filename(文件名)和可选的 $mimes(允许的 MIME 类型数组),默认使用 get_allowed_mime_types()。
- 返回数组包含 ext(扩展名)、type(MIME 类型)和 proper_filename(正确文件名),若无法确定则值为 false。
- 使用前需确保包含 wp-admin/includes/file.php 文件,以避免函数未定义错误。
- 提供 apply_filters Hook 如 'getimagesize_mimes_to_exts' 和 'wp_check_filetype_and_ext' 用于自定义 MIME 类型映射和文件类型验证。
代码示例
$validate = wp_check_filetype_and_ext( $file, $filename, $mimes );
if( $validate['proper_filename'] !== false )
$filename = $validate['proper_filename'];注意事项
- 当前函数仅支持验证 getimagesize() 已知的图像类型,非图像文件可能无法完全验证。
- 在插件或主题中使用时,若遇到函数未定义错误,需添加 require_once ABSPATH . 'wp-admin/includes/file.php'; 在调用前。
原文内容
Attempts 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
$filestringrequired-
Full path to the file.
$filenamestringrequired-
The name of the file (may differ from $file due to $file being in a tmp directory).
$mimesstring[]|nulloptional-
Array of allowed mime types keyed by their file extension regex.
Defaults to the result of get_allowed_mime_types() .Default:
null
Source
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 && str_starts_with( $type, 'image/' ) ) {
// Attempt to figure out what type of image it actually is.
$real_mime = wp_get_image_mime( $file );
$heic_images_extensions = array(
'heif',
'heics',
'heifs',
);
if ( $real_mime && ( $real_mime !== $type || in_array( $ext, $heic_images_extensions, true ) ) ) {
/**
* Filters the list mapping image mime types to their respective extensions.
*
* @since 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',
'image/webp' => 'webp',
'image/avif' => 'avif',
/*
* In theory there are/should be file extensions that correspond to the
* mime types: .heif, .heics and .heifs. However it seems that HEIC images
* with any of the mime types commonly have a .heic file extension.
* Seems keeping the status quo here is best for compatibility.
*/
'image/heic' => 'heic',
'image/heif' => 'heic',
'image/heic-sequence' => 'heic',
'image/heif-sequence' => 'heic',
)
);
// 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 );
if ( PHP_VERSION_ID < 80100 ) { // finfo_close() has no effect as of PHP 8.1.
finfo_close( $finfo );
}
$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/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' ), true ) ) {
$type = false;
$ext = false;
}
} 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, '/' ) ) ) {
$type = false;
$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',
'application/csv',
'text/richtext',
'text/tsv',
'text/vtt',
),
true
)
) {
$type = false;
$ext = false;
}
} elseif ( 'application/csv' === $real_mime ) {
// Special casing for CSV files.
if ( ! in_array(
$type,
array(
'text/csv',
'text/plain',
'application/csv',
),
true
)
) {
$type = false;
$ext = false;
}
} elseif ( 'text/rtf' === $real_mime ) {
// Special casing for RTF files.
if ( ! in_array(
$type,
array(
'text/rtf',
'text/plain',
'application/rtf',
),
true
)
) {
$type = false;
$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 = false;
$ext = false;
}
}
}
// The mime type must be allowed.
if ( $type ) {
$allowed = get_allowed_mime_types();
if ( ! in_array( $type, $allowed, true ) ) {
$type = false;
$ext = false;
}
}
/**
* Filters the "real" file type of the given file.
*
* @since 3.0.0
* @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
* none were provided.
* @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 );
}
Hooks
- apply_filters( ‘getimagesize_mimes_to_exts’, array $mime_to_ext )
-
Filters the list mapping image mime types to their respective extensions.
- apply_filters( ‘wp_check_filetype_and_ext’, array $wp_check_filetype_and_ext, string $file, string $filename, string[]|null $mimes, string|false $real_mime )
-
Filters the “real” file type of the given file.
Changelog
| Version | Description |
|---|---|
| 3.0.0 | Introduced. |