最可靠方法是用 finfo_file() 读取临时文件二进制签名判断 MIME 类型,需启用 fileinfo 扩展、传入 $_FILES['file']['tmp_name'] 并用 FILEINFO_MIME_TYPE 标志,再通过 str_starts_with($mimeType, 'video/') 判断是否为视频。

用 finfo_file() 检测真实 MIME 类型最可靠
仅靠文件扩展名(如 .mp4)或 $_FILES['file']['type'] 判断视频类型完全不可信——前者可被手动修改,后者由浏览器提供,极易伪造。真正有效的做法是读取文件头部的二进制签名(magic bytes),用 PHP 的 finfo_file() 函数解析实际 MIME 类型。
实操要点:
- 必须启用
fileinfo扩展(PHP 默认已开启,可通过extension_loaded('fileinfo')验证) - 推荐使用
FILEINFO_MIME_TYPE标志,返回类似video/mp4、video/webm的字符串,比FILEINFO_MIME更简洁 - 务必传入临时文件完整路径(
$_FILES['file']['tmp_name']),不能传扩展名或 URL
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
if (str_starts_with($mimeType, 'video/')) {
// 是视频
}
常见视频 MIME 类型有哪些?别只认 video/mp4
不同封装格式对应不同 MIME 类型,硬编码匹配 'video/mp4' 会漏掉大量合法视频。实际需覆盖主流类型:
-
video/mp4(H.264/AAC 封装) -
video/quicktime(.mov,注意不是video/mp4) -
video/x-ms-wmv(.wmv) -
video/x-flv(.flv) -
video/webm(VP8/VP9 + Vorbis/Opus) -
video/x-matroska(.mkv) -
video/3gpp(.3gp)
建议用前缀匹配(str_starts_with($mimeType, 'video/'))而非穷举,既覆盖新增类型,又避免误判(如 video/vnd.dece.mp4 这类变体)。
立即学习“PHP免费学习笔记(深入)”;
getimagesize() 为什么不能用于视频检测?
getimagesize() 只支持图像格式(JPEG/PNG/GIF 等),对任何视频文件都会返回 false 或警告。有人误以为它能“读取尺寸”就等于能识别视频,这是典型误解。
错误写法示例:
// ❌ 不要这么做:对 .mp4 返回 false,但不代表不是视频
$size = getimagesize($_FILES['file']['tmp_name']);
if ($size === false) {
// 错误地认为“不是图片 = 不是视频”,其实可能是视频、音频、PDF……
}
该函数设计目标就是图像,不解析视频容器结构,也不检查编码帧,强行用它做类型判断会直接漏掉全部视频文件。
上传前前端校验只是辅助,后端必须重验
前端用 accept="video/*" 或 JS 读取 File.type 只能提升体验,无法替代后端验证。用户禁用 JS、用 curl 上传、或篡改 FormData,都能绕过所有前端限制。
关键点:
- 前端
File.type和$_FILES['file']['type']均来自文件扩展名或浏览器猜测,不可信 - 即使前端做了
Blob.type检查,仍可能因浏览器差异返回空字符串或错误值(如 Safari 对 .mov 返回空) - 唯一可信路径:服务端用
finfo_file()实际读取临时文件字节流
特别注意:如果上传的是分片文件或未完成上传的临时文件,finfo_file() 可能因数据不全而误判,确保在 is_uploaded_file() 验证通过后再调用。











