finfo_file()是检查音频文件mime类型最可靠方式,必须用fileinfo_mime_type模式校验$_files'file',白名单精确匹配audio/mpeg等完整字符串,拒绝application/octet-stream等异常返回。

用 finfo_file() 检查 MIME 类型最可靠
仅靠文件扩展名(如 .mp3)或 $_FILES['file']['type'] 判断音频文件极不可靠——前者可被随意伪造,后者由浏览器提供,完全不受控。真正有效的做法是读取文件二进制内容,用系统级 MIME 探测工具判断。
finfo_file() 是 PHP 内置函数,底层调用 libmagic,能准确识别真实媒体类型。使用前需确保 fileinfo 扩展已启用(绝大多数现代 PHP 环境默认开启)。
实操建议:
- 上传后立即用
finfo_open(FILEINFO_MIME_TYPE)打开探测器,再传入临时文件路径($_FILES['file']['tmp_name']) - 检查返回值是否在常见音频 MIME 列表中,例如:
audio/mpeg、audio/wav、audio/ogg、audio/flac、audio/mp4 - 注意:不要只匹配
audio/前缀,有些非音频类型(如audio/vnd.wave)虽含audio但不标准;优先白名单精确匹配 - 探测失败时(返回
false或空字符串),应直接拒绝,不回退到扩展名校验
为什么不能只用 pathinfo($filename, PATHINFO_EXTENSION)
用户完全可以把一个 .exe 文件改成 song.mp3 后上传,pathinfo() 只会返回 mp3,毫无安全意义。更危险的是,某些旧版 PHP 配置下,getimagesize() 之类函数甚至会被恶意构造的音频文件触发解析漏洞。
典型错误场景:
- 前端用
accept="audio/*"属性限制选择——这只是 UI 提示,完全可绕过 - 后端只检查
$_FILES['file']['name']是否以.wav结尾——攻击者上传shell.php.wav即可绕过 - 未验证
tmp_name是否为真实临时文件路径,导致 LFI 或路径遍历风险
结合大小和采样限制做二次过滤
MIME 正确只是第一步。真实业务中还需控制音频质量与资源消耗,比如防止用户上传 2GB 的无损 FLAC 当背景音乐。
实操建议:
- 用
$_FILES['file']['size']限制最大字节数(例如50 * 1024 * 1024表示 50MB) - 对关键格式做轻量元数据解析:比如用
ffmpeg -i(需 shell 权限)或getID3库提取时长、码率、采样率,拒绝超长(>30 分钟)或超高码率(>320kbps)文件 - 注意:
ffmpeg调用必须加超时(proc_open+stream_set_timeout),否则恶意构造的损坏文件可能导致进程卡死
常见错误返回值和对应处理
实际运行中,finfo_file() 可能返回非预期结果,需针对性应对:
- 返回
application/octet-stream:文件头不明确或已被截断,按非法文件处理 - 返回
text/plain或application/xml:很可能是文本文件伪装,或 ID3 标签损坏的 MP3,拒绝 - 返回
inode/x-empty:空文件,直接拒收 - 返回
audio/x-wav而非audio/wav:部分老系统行为,可酌情加入白名单,但优先更新 libmagic 数据库
真正难处理的是边缘格式——比如 Apple 的 ALAC(audio/mp4)、Opus(audio/ogg 或 audio/opus),不同 PHP 版本和 libmagic 版本识别结果可能不一致。上线前务必用真实文件样本测试全链路。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











