最可靠方式是用 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']当作可信来源(浏览器可随意伪造该字段)
扩展名只能作为辅助提示,不能参与安全决策。
处理流式上传或内存数据时如何识别音频
当音频来自 cURL 响应、S3 流或 base64 解码后的二进制内容时,finfo_file() 无法直接使用(它需要文件路径)。此时必须用 finfo_buffer()。
关键点:
- 确保传入的是原始二进制字节(不是字符串或已解码的 UTF-8 文本)
- 若数据来自
file_get_contents()或curl_exec(),默认就是二进制,可直接传入 - 若来自
base64_decode(),确认未被自动转义或截断(特别是含 null 字节时) - 示例:
$finfo = finfo_open(FILEINFO_MIME_TYPE); $mime = finfo_buffer($finfo, $raw_data);
常见音频 MIME 类型及兼容性注意点
不同系统、PHP 版本、libmagic 数据库版本可能导致识别结果略有差异。实际部署前务必在目标环境中验证。
主流音频类型对应关系(以较新 libmagic 为准):
-
"audio/mpeg"→ MP3、MP3pro -
"audio/wav"→ PCM WAV(注意:某些带编码的 WAV 可能返回"audio/x-wav") -
"audio/ogg"→ Vorbis、Opus(但部分 Opus 文件可能返回"application/ogg") -
"audio/flac"→ FLAC(无损) -
"audio/mp4"或"video/mp4"→ M4A、AAC(取决于封装方式)
别硬编码 strict 相等判断,建议用 str_starts_with($mime, 'audio/') + 白名单二次过滤,避免因小版本差异导致合法文件被拒。











