PHP无法直接获取上传进度,需前端分片上传+后端记录进度文件+轮询查询;禁用multipart/form-data整体上传,改用FileReader分块fetch;进度存临时文件并加LOCK_EX锁;FFmpeg转码须异步执行,通过队列交由守护进程处理。

PHP后端无法直接处理前端上传进度
浏览器的 XMLHttpRequest 和 fetch 本身不暴露上传过程中的原始字节流进度,PHP 更不可能“主动推送”进度——它只是被动接收完请求体后才开始执行。所谓“实时反馈”,本质是前端分片上传 + 后端记录中间状态 + 前端轮询或 SSE 查询进度。
直接用 $_FILES 接收大视频文件,既没进度、又易超时、还占内存。必须绕开传统表单提交。
- 禁用
enctype="multipart/form-data"整体上传(无进度可控性) - 前端用
FileReader+slice()分块读取,通过fetch逐片 POST 到 PHP 接口 - 每片上传成功后,PHP 记录当前已接收字节数到临时文件或 Redis,例如写入
/tmp/upload_progress_abc123 - 前端另起一个定时器,定期 GET
/api/progress?token=abc123拉取最新进度
PHP如何安全记录和读取分片上传进度
不要用 PHP session 存进度——并发上传时 session 文件锁会导致阻塞;也不要存数据库——小数据高频写入反而成瓶颈。最轻量可靠的是文件 + 原子写入。
示例:上传 token 为 vid_7f3a9,PHP 收到一片后执行:
$token = $_POST['token'] ?? ''; $chunkSize = (int)($_POST['chunk_size'] ?? 0); $chunkIndex = (int)($_POST['chunk_index'] ?? 0); $filePath = sys_get_temp_dir() . '/upload_progress_' . $token; <p>// 只写纯数字:已接收总字节数 file_put_contents($filePath, ($chunkIndex * $chunkSize) . "\n", LOCK_EX);</p>
- 务必用
LOCK_EX避免多片并发写入错乱 - 不要写 JSON 或序列化数据——增加解析开销,且非原子
- 读取进度接口(如
get_progress.php)只需file_get_contents($filePath)+intval(),返回纯数字 - 上传完成合并后,立刻 unlink 进度文件,避免残留
FFmpeg转码必须异步执行,否则阻塞HTTP响应
PHP 默认同步执行 exec() 会卡住整个请求,前端轮询会超时。必须把 FFmpeg 转码扔进后台,同时让 PHP 立即返回成功响应。
- 用
nohup ffmpeg -i ... -c:v libx264 ... > /dev/null 2>&1 &启动,但需注意:Web 服务器用户(如www-data)可能无权执行后台进程 - 更稳妥做法是写转码命令到队列文件(如
/tmp/ffmpeg_queue),由独立守护进程(systemd或supervisor管理的 PHP 脚本)持续监听并消费 - 转码过程中,仍用同一
token写入进度文件,例如写入"converting:58"表示转码进度 58% - 前端轮询时若读到
converting:前缀,就显示“正在转码中”,而非“上传中”
前端轮询频率与失败重试要克制
频繁轮询(如 200ms 一次)对服务压力大,且多数时间进度没变。合理策略是“渐进式拉取”:
- 上传阶段:每 500ms 查一次,直到达 100%
- 转码阶段:升至 2s 间隔,因 FFmpeg 进度更新本身就不频繁
- 若连续 3 次返回空或错误,停止轮询并提示“服务异常,请稍后查看结果”
- 轮询 URL 必须带
cache-bust参数(如?t=171xxxx),避免被代理或浏览器缓存返回旧值
真正难的不是代码拼凑,而是各环节状态对齐:前端切片序号、PHP 临时文件生命周期、FFmpeg 进程存活判断、失败后清理逻辑——任意一环漏掉,就会出现“页面卡在 99%”或“转码完成但找不到文件”。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











