ThinkPHP本身不支持语音搜索,需前端录音上传、后端调用百度/讯飞等ASR接口实现;关键在打通“录音→上传→API调用”链路,注意音频格式、上传限制、签名认证及响应解析。

ThinkPHP 里没法直接语音搜索,得靠前端录音 + 后端调用第三方 ASR
ThinkPHP 本身不提供语音采集、音频上传、语音识别(ASR)能力。所谓“语音搜索”,实际是:用户在前端按住说话 → 录成音频文件(如 .wav 或 .mp3)→ 前端上传到 ThinkPHP 接口 → ThinkPHP 转发给百度语音、讯飞开放平台或腾讯云 ASR → 拿回文字再查数据库。
常见错误现象:Undefined function audio_to_text()、上传后接口返回空、识别结果乱码、超时 504 —— 这些都不是 ThinkPHP 的锅,而是没走通「前端录音 → 文件上传 → 第三方 API 调用」这条链路。
- 必须用前端(如 Web Speech API 或
MediaRecorder)完成录音,ThinkPHP 只负责收文件和发请求 - 音频格式优先选
.wav(16kHz 单声道 PCM),讯飞/百度对这种格式兼容性最好;.mp3要额外转码,容易出错 - ThinkPHP 接收文件要用
$request->file('audio'),别用$_FILES手动处理,否则绕过框架的上传校验和临时目录管理 - 调第三方 ASR 时,注意签名生成逻辑(尤其是讯飞的
iat_sign)、Content-Type是否设为multipart/form-data,否则直接 400
百度语音 REST API 在 ThinkPHP 中调用的关键参数
百度语音识别(短语音版)要求 POST 二进制音频流,且需带 access_token、format、rate、channel 等字段。ThinkPHP 里用 think\Http 或原生 cURL 都行,但别漏掉这些:
-
format必须小写,填wav或pcm,不能写WAV -
rate填16000(百度只支持这个采样率),前端录音时就得设好,后端改不了 -
channel固定为1(单声道),双声道音频会识别失败 -
token有效期 30 分钟,建议封装成服务类缓存,别每次请求都重新获取 - POST body 必须是原始二进制流,不是 Base64,别用
json_encode包一层
示例片段(使用 think\Http):
Http::post('https://vop.baidu.com/server_api', [
'body' => file_get_contents($tempPath),
'headers' => ['Content-Type' => 'audio/wav; rate=16000'],
'query' => [
'cuid' => 'your_app_id',
'token' => $token,
'dev_pid' => 1537 // 中文普通话
]
]);
上传大音频文件时 ThinkPHP 报 413 或 500 怎么调
用户说 30 秒以上语音,文件可能超 2MB,ThinkPHP 默认限制上传大小,Nginx/Apache 也拦着,不调就直接 413 Request Entity Too Large。
立即学习“PHP免费学习笔记(深入)”;
- ThinkPHP 配置:在
config/filesystem.php或控制器里用$request->file('audio')->getSize()做前置判断,但更关键是改底层限制 - PHP 层:修改
php.ini中的upload_max_filesize = 10M和post_max_size = 12M - Nginx 层:在 server 块加
client_max_body_size 10M,否则请求根本到不了 PHP - Apache 层:加
LimitRequestBody 10485760到虚拟主机配置 - 别信 “前端用 Blob.slice 分片上传” —— 百度/讯飞 ASR 接口不支持分片,必须传完整音频流
识别结果中文乱码或返回 empty 的典型原因
拿到 ASR 返回 JSON,result 字段却是空数组或一堆问号,大概率是编码或音频质量问题,和 ThinkPHP 字符集设置关系不大。
- 音频静音时间太长(比如开头 2 秒没声音),百度会截断,导致有效内容丢失 —— 前端录音完先用
Web Audio API检测音量,低于阈值就提示重录 - 返回 JSON 是 UTF-8,但 ThinkPHP 输出时被自动转义,检查是否误用了
htmlspecialchars处理了响应体 - 讯飞接口返回的
data是 Base64,需用base64_decode()解码后再json_decode(),漏一步就变空 - 百度返回的
result是数组,哪怕只有一句,也要取$res['result'][0] ?? '',直接$res['result']可能报 notice - 别在测试时用系统自带录音机录的文件 —— 它常带元数据和非标准头,ASR 服务解析失败率高
事情说清了就结束。


















