不能改 php.ini 时,必须采用前端分片上传+后端按序合并方案:前端切片(如每2MB)、后端用 fopen('c') + fseek 定位写入临时分片,全部接收后再校验哈希并设权限。
upload_max_filesize 超了但改不了 php.ini 怎么办
直接说结论:不能改 php.ini 时,靠前端分片 + 后端合并是最可行的路径。php 的 upload_max_filesize 和 post_max_size 是硬限制,运行时无法用 ini_set() 绕过,任何试图“临时调大”的操作都无效。
常见错误现象是表单提交后直接 400 或空白页,查 error_log 会看到类似 PHP Warning: POST Content-Length of XXX bytes exceeds the limit of YYY bytes 的报错 —— 这说明请求根本没进脚本,更别提执行逻辑了。
- 必须在前端把文件切片(例如每 2MB 一片),用
fetch或XMLHttpRequest分批上传 - 后端接收时不做完整校验,只存临时分片(命名带序号和唯一标识,如
upload_abc123_001.tmp) - 所有分片上传完成后,再用
file_put_contents()配合FILE_APPEND合并,**不要用file_get_contents()全读进内存** - 合并完立刻校验
md5_file()或sha1_file(),比对前端传来的总哈希值
用 curl 或命令行模拟分片上传调试
浏览器上传容易卡在 CORS、超时或 chunk 失序,本地用 curl 直接发请求能快速验证后端接口是否健壮。关键不是“能不能传”,而是“断点续传”和“重复片去重”有没有做。
使用场景包括:测试大文件中断后重试、检查分片序号错位是否导致合并乱序、确认临时目录权限是否允许写入大量小文件。
- 上传第 1 片:
curl -F "chunk=0" -F "total=5" -F "identifier=xyz" -F "file=@part1.bin" https://yoursite.com/upload.php - 上传第 3 片(跳过第 2 片):
curl -F "chunk=2" -F "total=5" -F "identifier=xyz" -F "file=@part3.bin" https://yoursite.com/upload.php - 后端必须支持“任意顺序接收”,靠
identifier和chunk索引分片,不能依赖请求先后 - 临时分片建议存到
/tmp/uploads/这类可写路径,避免和 Web 根目录混在一起
合并时 fopen() 模式选错导致文件损坏
合并大文件最常踩的坑是用了 fwrite(fopen($target, 'w'), $content) —— 'w' 模式每次打开就清空文件,最后只剩最后一片内容。正确做法是只开一次句柄,用 FILE_APPEND 或 fseek() 定位写入。
立即学习“PHP免费学习笔记(深入)”;
性能影响很明显:1GB 文件如果每片都 fopen(..., 'w') 再 fclose(),IO 开销翻倍;而用 fopen(..., 'c') + fseek() 定位写入,能省掉大量磁盘寻道时间。
- 推荐方式:
$fp = fopen($target, 'c'); fseek($fp, $offset); fwrite($fp, $chunk_data); fclose($fp); - 不推荐方式:
file_put_contents($target, $chunk_data, FILE_APPEND)—— 它内部每次都会重新 open/close,高并发下容易锁冲突 - 务必检查
fopen()返回值,false说明磁盘满或权限不足,别直接fwrite()导致 PHP Warning - 合并完成后用
chmod($target, 0644)显式设权限,避免继承临时目录的 0600
Chrome 上传大文件卡在 pending 的真实原因
不是网络慢,大概率是服务端没及时响应分片请求,触发了浏览器的默认 timeout(通常 5 分钟)。哪怕后端 PHP 脚本还在跑,只要没输出 HTTP 头,Chrome 就算“卡住”。
兼容性影响在于:Safari 对单个请求 timeout 更激进(约 90 秒),而 Node.js 后端默认无此限制,所以换后端语言并不能绕开这个问题 —— 根子在 HTTP 协议层的客户端行为。
- 每个分片上传接口必须在 30 秒内返回
HTTP/1.1 200 OK,哪怕只是{"status":"received","chunk":2} - 禁用
set_time_limit(0)来“保命”,它只防脚本超时,不防 Apache/Nginx 的Timeout或proxy_read_timeout - Nginx 用户重点检查
client_max_body_size和fastcgi_read_timeout,这两个值比 PHP 的upload_max_filesize更早拦截请求 - 上传进度条别只信
XMLHttpRequest.upload.onprogress,它不反映服务端处理状态,得靠轮询合并接口的status字段



















