ThinkPHP安全接收音频文件需三步校验:调用isValid()、检查后缀白名单、用finfo_open确认真实MIME类型;存文件时生成唯一文件名并存相对路径,禁用原始名和blob存储。

ThinkPHP 怎么安全接收前端传来的音频文件
不能直接信任 $_FILES 里的原始信息,尤其微信小程序或 H5 录音上传时,name 可能为空、type 可被伪造、tmp_name 可能已被清理。关键动作是三步校验:调用 $file->isValid()、检查后缀是否在白名单(如 ['mp3', 'wav', 'ogg', 'amr'])、用 getimagesize($file->getTmpName()) 或 finfo_open(FILEINFO_MIME_TYPE) 确认真实 MIME 类型是否为音频。
存文件时别用原始名:move() 前必须生成唯一文件名,例如:date('YmdHis') . '_' . uniqid() . '.' . $file->extension();路径固定在 public/uploads/audio/,只存相对路径到数据库,不存二进制 blob。
- 避免写死路径,用
ROOT_PATH . 'public' . DS . 'uploads' . DS . 'audio' - 上传前检查
upload_max_filesize和post_max_size(php.ini),建议设为20M起 - 微信
amr文件需额外判断:substr(file_get_contents($tmp, false, null, 0, 3), 0, 3) === "\x23\x21\x41"可辅助识别
怎么用 getID3 获取音频时长并入库
ThinkPHP 自身不提供音频元信息解析能力,getID3 是最轻量且兼容性最好的选择。不要用 ffprobe 做同步调用——它启动慢、易超时、失败无退路;getID3 纯 PHP 实现,无需系统命令,适合读取 playtime_seconds、audio_bitrate、audio_channels 等关键字段。
引入方式推荐 Composer:composer require james-heinrich/getid3,然后在控制器中:
立即学习“PHP免费学习笔记(深入)”;
$getID3 = new \getID3(); $ThisFileInfo = $getID3->analyze($filePath); $duration = $ThisFileInfo['playtime_seconds'] ?? 0;
- 务必传入绝对路径(
realpath($filePath)),否则分析会失败 - MP3 文件若含 ID3v2 标签过大,可能触发内存限制,可加
$getID3->setOption(array('encoding' => 'UTF-8'))优化 - 结果应存入数据库对应字段(如
duration、bitrate),后续列表页排序或筛选都依赖它
为什么直接用 HTML5 <audio> 标签播放会失败
常见报错是“媒体资源无法解码”或“NotSupportedError”,根本原因不是 ThinkPHP 的问题,而是路径、MIME、跨域三者之一没对齐。重点排查:
- 确认 URL 返回的 HTTP Header 中
Content-Type是audio/mpeg(MP3)、audio/wav(WAV)等标准类型,而不是text/html或application/octet-stream - ThinkPHP 默认静态资源走 public 目录,所以音频 URL 必须是形如
/uploads/audio/20260514102345_xyz.mp3,不能是/index.php?s=/audio/play&id=123这类路由地址(除非你显式设置响应头和输出流) - 如果音频放在对象存储(如阿里云 OSS、腾讯云 COS),确保 Bucket 设置了正确的 CORS 规则,允许你的域名发起
GET请求
模板中写法要带容错:<audio controls preload="metadata"><source src="<?php echo $audioUrl ?>" type="audio/<?php echo $ext ?>">您的浏览器不支持音频播放</audio>
ffmpeg 预处理音频时 exec() 不执行怎么办
不是代码写错了,大概率是运行环境卡在三个地方:PHP 禁用了 exec、系统没装 ffmpeg、PHP 进程没权限读写临时目录。先执行 php -i | grep disable_functions 看是否禁用;再 SSH 登录服务器运行 which ffmpeg 和 ffmpeg -version 验证安装;最后检查 public/uploads/audio/ 是否可写(chown -R www:www public/uploads)。
ThinkPHP 8 推荐用 php-ffmpeg/php-ffmpeg 封装调用,比裸 exec() 更可控:
$ffmpeg = FFMpeg::create(['ffmpeg.binaries' => '/usr/bin/ffmpeg']); $video = $ffmpeg->open($inputPath); $video->save(new \FFMpeg\Format\Audio\Mp3(), $outputPath);
- 注意
php-ffmpeg依赖fileinfo和gd扩展,缺一不可 - AMR 转 MP3 必须指定编码器:
-acodec libmp3lame,否则默认转出的 MP3 可能无法播放 - 大文件(>50MB)转码建议丢到队列里异步执行,避免请求超时;TP8 的
think-queue可直接对接
.mp3 当作普通二进制缓存了 1 年,用户改名重传后仍播旧文件——得强制加版本参数或配置缓存规则。



















