最可靠方法是使用finfo_open和finfo_file基于文件内容识别真实mime类型,再通过精简映射表或mime.types文件推导可信后缀,并需截取主类型、统一小写、拒绝未知mime。

当用户上传文件时,仅依赖$_FILES['file']['name']的扩展名判断类型极不可靠,攻击者可轻易伪造后缀绕过校验。finfo_open能基于文件内容识别真实MIME类型,从而推导出更可信的后缀。
初始化finfo资源并获取MIME类型
调用finfo_open传入FILEINFO_MIME_TYPE常量,确保只返回MIME字符串而非完整描述;这一步必须成功,否则后续所有判断都失去意义。
使用finfo_file读取临时文件路径$_FILES['file']['tmp_name'],得到类似"image/jpeg"或"application/pdf"的结果。
注意:若finfo_file返回false或空字符串,说明文件已损坏、路径无效或finfo资源初始化失败,【此时应立即中止处理并拒绝该文件】。
建立MIME到后缀的映射关系
方法一:手动维护精简映射表
只收录业务实际需要的类型,例如:'image/jpeg' → 'jpg'、'image/png' → 'png'、'application/pdf' → 'pdf'、'text/plain' → 'txt'。不建议穷举IANA全部注册类型,冗余映射反而增加维护成本和误判风险。
方法二:使用php-fileinfo内置的mime.types(需确认服务器已部署)
读取/etc/mime.types或php安装目录下的mime.types文件,按行解析,跳过注释与空行,将每行首字段(MIME类型)与后续扩展名一一对应。但要注意某些MIME类型对应多个后缀(如text/html可映射为html或htm),需根据业务规则选定默认值。
处理常见陷阱与边界情况
第一步:过滤掉MIME类型中的参数部分
finfo_file可能返回"image/jpeg; charset=binary"或"application/octet-stream; charset=utf-8",必须用explode(';', $mime, 2)[0]截取分号前主类型,否则映射会失败。
第二步:统一小写处理
MIME类型大小写不敏感,但映射数组键名建议全小写存储,调用前对结果strtolower(),避免因"IMAGE/JPEG"找不到对应项。
第三步:应对未知MIME类型
若映射表中未定义该MIME,不要fallback到原始上传后缀,也不要用通用后缀如.dat;【直接返回null或抛出异常,强制人工审核】。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











