codeigniter原生上传类不支持断点续传,因其依赖完整$_files机制,无法分片、校验偏移或恢复中断;大文件需改用原生php+前端分片方案,实现chunk接收、临时存储、按序合并及md5校验,并严格管理临时文件生命周期。

CodeIgniter 原生上传类不支持断点续传。它基于 PHP 的 $_FILES 机制,而该机制在请求完成前就已将整个文件载入临时目录,无法分片、校验偏移量或恢复中断上传。
如果你正在处理大文件(比如 >50MB),又需要断点续传能力,必须绕过 upload 类,改用原生 PHP + 前端分片方案。下面直说关键怎么做。
为什么 upload->do_upload() 无法用于断点续传
根本原因有三个:
-
do_upload()依赖完整的$_FILES数组,而浏览器分片上传时每个请求只发一个 chunk,$_FILES里没有完整文件信息 - 上传类的
upload_path、encrypt_name等配置都面向单次完整上传,不提供 chunk 合并、MD5 校验、偏移写入等接口 - 所有验证逻辑(如
is_allowed_filetype())都在单次请求内执行,无法跨请求维护上传状态
用原生 PHP 实现分片接收与合并
核心思路:前端按固定大小切片(如 2MB/chunk),后端逐个接收并追加写入临时文件,最后合并校验。
- 接收接口(如
Upload::chunk)需接受参数:filename、chunk(序号)、chunks(总数)、identifier(唯一标识,推荐用文件名+size+md5前缀) - 每个 chunk 存为
./uploads/.tmp/{identifier}_{chunk}.part,避免并发冲突 - 当收到最后一个 chunk 时,按序号拼接所有
.part文件,并用fopen(..., 'ab')追加写入目标文件 - 合并完成后,用
md5_file()对比前端传来的总 MD5,不一致则删除并报错
示例关键逻辑:
$tmp_dir = './uploads/.tmp/';
$target_file = './uploads/' . $identifier;
$part_file = $tmp_dir . $identifier . '_' . $chunk . '.part';
<p>file_put_contents($part_file, file_get_contents('php://input'));
if ((int)$chunk === (int)$chunks - 1) {
$fp = fopen($target_file, 'ab');
for ($i = 0; $i dir . $identifier . '' . $i . '.part'));
unlink($tmp<em>dir . $identifier . '</em>' . $i . '.part');
}
fclose($fp);
}
</p>
如何防止重复上传和中间态文件残留
分片上传失败很常见,必须主动清理“孤儿”文件:
- 每次接收 chunk 前,先检查
$tmp_dir . $identifier . '_0.part'是否存在;若存在但超 24 小时未更新,说明上次上传卡死,直接清空该 identifier 下所有 part 文件 - 合并成功后,务必删除
$tmp_dir下对应 identifier 的全部残留(哪怕只剩一个 part) - 不要依赖
register_shutdown_function清理 —— 它在 PHP 超时或 Apache kill 进程时不可靠;应由定时脚本(如 crontab 每小时跑一次)扫描并清理过期.part文件
前端必须配合的关键点
CI 后端只是接收方,前端控制力决定断点续传是否真可用:
- 使用
XMLHttpRequest或fetch发送 chunk,禁用form.submit或form_open_multipart - 每个请求必须带
Content-Type: application/octet-stream,且用body: blob.slice(...)发送原始二进制,不能转 base64 - 必须实现上传进度缓存(如 localStorage):记录已上传 chunk 列表、当前 identifier、总 size,页面刷新后能自动跳过已传部分
- 服务端返回 200 并带
{"uploaded": true}即可,不要返回重定向或 HTML 页面 —— 那会破坏 xhr 流程
真正落地时,最易被忽略的是「分片校验」和「临时文件生命周期管理」。很多人只写了接收逻辑,没做 MD5 对比,结果网络抖动导致文件损坏却无感知;也有人忘了定期清理 .part 文件,几个月后磁盘爆满才发现几百 GB 的碎片躺在 .tmp 里。











