应通过扩展名白名单+fileinfo真实MIME检测双重校验音频格式,禁用$_FILES['type']单独判断;保存时重命名文件、隔离存储路径并禁Web直接访问,防止解析漏洞执行。

怎么用 $_FILES 的 type 字段判断音频格式
别信 $_FILES['audio']['type'],它只是浏览器传来的 MIME 类型,可以伪造,比如把 .exe 改名成 .mp3 再拖进去,type 很可能还是 audio/mpeg。这个字段只适合做快速预筛,不能当真。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 必须配合文件内容检测(即“魔数”或扩展名白名单双重校验)
- 如果只做前端+
type校验,等于没限制 - 常见音频 MIME 类型有:
audio/mpeg、audio/wav、audio/ogg、audio/flac、audio/mp4(注意不是video/mp4)
怎么用 pathinfo() 和白名单校验扩展名
这是最简单也最有效的第一道防线,但必须严格限定后缀,且不区分大小写。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
pathinfo($filename, PATHINFO_EXTENSION)提取扩展名,再转小写 - 白名单只保留明确支持的后缀,例如:
['mp3', 'wav', 'ogg', 'flac', 'm4a'](m4a对应audio/mp4) - 拒绝所有带点的异常扩展名,如
.mp3.php、.wav.zip—— 这类要先用strrpos()检查最后那个点的位置,确保只有一个点 - 不要接受
.aac除非你确认播放器和服务器都支持,很多 PHP 环境默认不识别它的 MIME
怎么用 finfo_open() 做真实 MIME 检测
这才是防伪装的关键一步:读取文件头几个字节,比对实际格式。依赖 fileinfo 扩展(PHP 默认开启,但某些精简版 Docker 镜像可能关了,记得检查 extension_loaded('fileinfo'))。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
finfo_open(FILEINFO_MIME_TYPE)获取真实 MIME,不是FILEINFO_MIME(后者含编码,易误判) - 校验返回值是否在音频 MIME 白名单中,例如:
in_array($mime, ['audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/flac', 'audio/mp4']) - 注意:
audio/x-wav和audio/wav都可能出现,建议用strpos($mime, 'audio/') === 0粗筛 + 显式白名单精筛 - 别跳过这步直接 move_uploaded_file —— 上传临时文件仍可被读取,
finfo开销极小
怎么避免 move_uploaded_file() 后被绕过执行
即使前面都校验了,如果保存路径不当或文件名未重命名,攻击者仍可能通过解析漏洞(如 Nginx 的 .php.mp3 被当作 PHP 执行)触发风险。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 保存时强制重命名,用
uniqid() . '.' . $ext,绝不直接用原始$_FILES['audio']['name'] - 存储目录禁止 Web 直接访问,或通过脚本代理下载(如
readfile()+ header),而不是放在public/下裸露路径 - Apache 用户注意关闭
MultiViews,Nginx 用户检查是否有类似location ~ \.php$规则误匹配音频文件 - 上传成功后,可用
get_headers()或 curl 模拟请求,确认该 URL 返回的是403或404,而非200+ 可执行内容
真正麻烦的从来不是“怎么判断是 MP3”,而是“怎么确保它永远只是 MP3,且不会被当成别的东西执行”。每一步校验都要独立成立,缺一不可。



















