finfo_file() 是 php 中最可靠的文件类型识别方式,通过解析临时文件二进制头(而非扩展名或 content-type)获取真实 mime 类型,需用 fileinfo_mime_type 模式、传入 $_files'file'、校验上传状态并严格白名单匹配。

用 finfo_file() 读取文件头识别真实类型,是PHP中最可靠的方式。它不看扩展名、不信任浏览器传来的 Content-Type,而是直接解析临时文件的二进制头,防伪装能力强。
必须用 finfo_open(FILEINFO_MIME_TYPE)
FILEINFO_MIME_TYPE 模式只返回标准 MIME 字符串,例如 'image/png' 或 'text/plain';而 FILEINFO_MIME 会附带编码信息(如 'image/png; charset=binary'),比对容易出错。初始化时建议指定系统 magic 路径提升准确性:
$finfo = finfo_open(FILEINFO_MIME_TYPE, '/usr/share/misc/magic');- 若未指定路径,PHP 会退回到内置精简库,某些边缘格式可能识别不准
校验目标必须是上传的临时文件路径
一定要传 $_FILES['file']['tmp_name'] 给 finfo_file(),不能传原始文件名或已移动后的路径。原因有三:
- 原始文件名可被伪造,
finfo_file()读的是文件内容,不是名字 - 必须先验证再移动:在
move_uploaded_file()前完成检测,否则风险已发生 - 调用前确认
is_uploaded_file($_FILES['file']['tmp_name'])返回 true,防止路径穿越攻击(如../../etc/passwd)
白名单匹配要严格完整
MIME 类型字符串必须全等匹配,不能用模糊判断:
- ✅ 正确:
in_array($mimeType, ['image/jpeg', 'image/png', 'text/csv']) - ❌ 错误:
strpos($mimeType, 'image/') !== false(会放过image/svg+xml等高危类型) - ❌ 错误:
substr($mimeType, 0, 5) === 'image'(语法不安全,且逻辑不严谨)
补充校验可增强鲁棒性
对关键场景(如配置文件、文本上传),建议叠加一层验证:
- 空文件需单独处理:
filesize($tmp_name) === 0→ 视为特殊 case - 文本类文件可加编码检查:
mb_check_encoding(file_get_contents($tmp_name, false, null, 0, 65536), 'UTF-8') - 图像类可追加魔数比对(如 PNG 头是否为
\x89PNG\r\n\x1a\n),但 finfo 已覆盖绝大多数情况
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











