
PHP 8.5 没有原生分片上传支持
PHP 本身不提供“分片上传”功能,无论 8.5 还是 8.4,$_FILES 只接收完整 HTTP 请求体里的文件——大文件直接传,超限就报错或截断。所谓“分片”,必须由前端切片 + 后端拼接逻辑共同完成,PHP 8.5 只是运行环境,关键在你写的接收和合并逻辑。
前端切片后,PHP 怎么安全接收并暂存每一片
每片本质是普通 POST 请求,带唯一标识(如 file_id、chunk_index、total_chunks),后端用这些参数决定存哪、是否可合并。
- 用
move_uploaded_file()把每片存到临时目录,命名建议含file_id和chunk_index,比如/tmp/upload_abc123_002.bin - 务必校验
$_POST['chunk_index']是数字、$_POST['total_chunks']合理(别让前端随便填 9999)、$_FILES['file']['size']不超单片上限(如 5MB) - 避免直接用
$_POST['file_id']当目录名——可能含路径遍历字符,用preg_replace('/[^a-zA-Z0-9_\-]/', '', $_POST['file_id'])过滤 - PHP 8.5 的
upload_max_filesize和post_max_size仍需调大,否则单片请求直接 413;但不用设成几 GB,按单片大小设即可(如6M)
所有分片收齐后,怎么高效拼成完整文件
不能用 file_get_contents() 全读进内存拼,大文件会 OOM;要用流式追加写入。
- 先检查是否所有片都存在:循环读
/tmp/upload_{$file_id}_*.bin,确认数量等于total_chunks - 用
fopen($final_path, 'wb')创建空目标文件,再用fopen($chunk_path, 'rb')逐个读片、stream_copy_to_stream()写入,避免内存堆积 - 拼完立刻删所有分片文件,别留临时垃圾;可用
unlink()或批量array_map('unlink', $chunk_files) - 注意文件权限:
fopen(..., 'wb')创建的文件默认属 web server 用户,若后续要由 CLI 脚本处理,得用chmod()补权限
为什么 PHP 8.5 下分片上传更容易出错
PHP 8.5 强化了类型和错误报告,但没改底层上传机制——反而会让旧逻辑更快暴露问题。
立即学习“PHP免费学习笔记(深入)”;
-
$_FILES['file']['error'] === UPLOAD_ERR_NO_FILE很常见:前端没正确设置FormData.append('file', blob),或fetch没传body - PHP 8.5 默认开启
strict_types=1(如果文件顶部写了),但上传逻辑通常不在这范围;真正影响的是你手写的校验函数——比如把int参数当string用,会直接 TypeError - APCu 或 OPcache 在开发时可能缓存了旧的分片状态判断逻辑,改完 PHP 代码记得
sudo systemctl reload php8.5-fpm或清 APCu(apcu_clear_cache()) - 最易忽略的一点:分片合并时没做原子性保障。如果拼到一半服务器重启,会留下损坏文件。加个
.complete标记文件,拼完再生成,业务侧只认有该标记的文件










