最可靠方式是用 finfo_file() 基于二进制头识别音频 MIME 类型,因其依赖 libmagic 解析内容而非扩展名或浏览器伪造的 type 字段;处理内存数据时应改用 finfo_buffer()。
用 finfo_file() 判断音频 MIME 类型最可靠
仅靠文件扩展名(如 .mp3)判断音频类型极易被绕过,真实场景中必须检查文件内容。PHP 的 finfo_file() 基于 libmagic,能解析二进制头信息,是识别音频类型的首选方式。
常见错误是直接用 mime_content_type() —— 它已被弃用,且在某些 PHP 版本中不可用;还有人用 getimagesize() 试图“碰运气”,但它只支持图片,对音频返回 false 或警告。
正确做法:
- 始终使用
finfo_open(FILEINFO_MIME_TYPE)初始化资源 - 调用
finfo_file()传入文件路径,不依赖$_FILES临时路径以外的变量 - 检查返回值是否为已知音频 MIME 类型,例如
"audio/mpeg"、"audio/wav"、"audio/ogg"、"audio/flac" - 注意:部分 Web 服务器会把
.m4a识别为"audio/mp4"或"video/mp4",需一并接受
为什么 pathinfo($file, PATHINFO_EXTENSION) 不足以判定音频
扩展名只是字符串,可被任意修改。攻击者上传伪造后缀的恶意脚本(如 shell.mp3 实际是 PHP 文件),仅校验扩展名会完全失效。
立即学习“PHP免费学习笔记(深入)”;
典型误用场景:
- 用
in_array(pathinfo($file, PATHINFO_EXTENSION), ['mp3', 'wav', 'ogg'])放行文件 - 未配合 MIME 检查就直接
move_uploaded_file() - 把
$_FILES['audio']['type']当作可信来源(浏览器可随意伪造该字段)
扩展名只能作为辅助提示,不能参与安全决策。