【一个PHP外包仔的2G文件上传血泪史:从WebUploader到自救之路】


"老板,这个2G的文件上传需求…要不咱们先聊聊预算?"我擦着额头的汗,盯着客户发来的需求文档。作为一个月接3个外包的野生PHP工程师,我深知这次要栽——毕竟上次用WebUploader上传200M的PPT,客户的Chrome就崩溃成了PPT(字面意思)。

第一幕:WebUploader的临终遗言

"兄弟,我尽力了。"看着控制台里第18个502错误,WebUploader的JS文件仿佛在对我鞠躬谢罪。这个百度开源的组件就像个倔强的老黄牛:

  • 分片上传?能工作,但偶尔会漏掉第7片(就像我小时候抄作业总会漏几行)
  • 进度条?在IE11里会表演"量子波动前进"
  • 断点续传?客户重启路由器后,所有分片都会集体玩失踪

最绝的是技术支持:“亲,建议升级到最新版哦~”——可最新版已经是5年前的遗孤啊!

第二幕:前端后端的相爱相杀

"Vue那边说需要MD5校验分片!"我冲着电话大喊,嘴里还塞着煎饼果子。前端小哥的声线透着绝望:“哥,WebUploader的文档比你的PHP注释还难懂…”

于是我们开启了跨服聊天模式:

// 前端发来的神秘代码片段
uploader.on('uploadError', function(file) {
  console.log('出错了,但我不知道错哪了');
  // 实际应该触发PHP端的日志接口,但没人记得写
});
// 我的后端回应(喝到第三罐红牛后的产物)
$chunk = $_FILES['file'] ?? null;
if(magic_check_chunk($chunk)) { // 这个函数名就透着玄学
    move_uploaded_file(...); // 偶尔会移动到虚无空间
    echo '{"success":true}'; // 其实可能没成功
}

第三幕:MySQL的无声抗议

当客户问"能不能显示所有上传任务的历史记录"时,我盯着InnoDB表陷入了沉思:

CREATE TABLE upload_tasks (
    id BIGINT AUTO_INCREMENT,
    file_hash VARCHAR(64), -- 存储整个文件的MD5
    total_size BIGINT, -- 2G文件就是2147483648
    status TINYINT, -- 0=上传中 1=完成 2=失败(但可能部分分片成功)
    -- 省略了5个关联表的设计...
);

直到测试时发现:

  1. 插入2000条记录后,查询"进行中的任务"需要3.7秒
  2. 文件哈希列没有索引(别问我怎么知道的)
  3. 当Nginx超时断开连接时,PHP还在傻乎乎地插入分片记录

第四幕:绝地求生方案

经过三天三夜的谷歌搜索(和两包速溶咖啡),我制定了新方案:

前端改造计划:

  1. 弃用WebUploader,改用resumable.js(至少文档是2023年的)
  2. 实现真正的断点续传:
    // 伪代码:用localStorage存储已上传分片
    const uploadedChunks = JSON.parse(localStorage.getItem('upload_progress_' + file.id)) || [];
    
  3. 添加心跳检测,防止浏览器假死

后端自救指南:

  1. 用Swoole替代传统PHP-FPM(虽然还在学,但看文档说能处理长连接)
  2. 分片存储方案:
    // 每个分片单独存储,成功后再合并
    $chunkDir = '/tmp/uploads/' . $fileHash;
    if (!is_dir($chunkDir)) mkdir($chunkDir, 0777, true);
    move_uploaded_file($_FILES['file']['tmp_name'], "$chunkDir/$chunkIndex");
    
  3. 合并时用exec('cat /tmp/uploads/* > final.mp4')(虽然不优雅但快)

数据库优化:

  1. 改用MongoDB存储分片元数据(终于不用纠结外键了)
  2. 添加Redis缓存当前上传任务
  3. 对大文件记录采用"软删除"策略(标记为删除但不真删,怕客户反悔)

终幕:测试日的疯狂

当客户终于发来测试文件时,我的监控面板是这样的:

  • Nginx错误日志:每分钟新增3条"upstream timed out"
  • PHP-FPM:内存占用突破1.2G
  • MySQL:慢查询日志里全是SELECT * FROM upload_tasks

但!当那个2.3G的《复仇者联盟4》完整版终于显示"上传成功"时,我激动得把咖啡打翻在键盘上——至少这次没把服务器宕机,对吧?

(客户反馈:IE11下进度条会跳芭蕾舞。我:微笑.jpg)

安装环境

PHP:7.2.14
Alt

调整块大小

Alt

NOSQL

NOSQL不需要任何配置,可以直接访问测试
Alt

SQL

创建数据库

您可以直接复制脚本进行创建
Alt
Alt

配置数据库连接

Alt

安装依赖

Alt

访问页面进行测试

Alt

数据表中的数据

Alt

免费下载示例

点击下载完整示例

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐