如何仅用PHP实现Dropzone.js分片文件上传?
纯PHP实现Dropzone.js分片文件上传完整方案
问题复盘
我懂你现在的痛点——翻遍资料都找不到纯PHP配合Dropzone.js做分片上传的完整方案,而且客户端还不能加额外库。你之前的代码没任何输出,且只触发了一次请求,核心问题出在客户端params函数的参数格式错误,导致Dropzone没正确识别分片配置,直接跳过了分片上传流程。
修正后的客户端配置代码
var myDropzone = new Dropzone("div#formDiv", { url: "uploadform.php", // 修正参数格式:返回标准键值对对象,而非字符串拼接 params: function(files, xhr, chunk) { if (chunk) { return { dzUuid: chunk.file.upload.uuid, dzChunkIndex: chunk.index, dzTotalFileSize: chunk.file.size, dzCurrentChunkSize: chunk.dataBlock.data.size, dzTotalChunkCount: chunk.file.upload.totalChunkCount, dzChunkByteOffset: chunk.index * this.options.chunkSize, dzChunkSize: this.options.chunkSize, dzFilename: chunk.file.name }; } return {}; }, method: "post", timeout: 600000, maxFileSize: 1024, // 单位MB,这里设置为1GB上限 parallelUploads: 1, chunking: true, forceChunking: true, chunkSize: 1000000, // 1MB大小的分片 parallelChunkUploads: true, retryChunks: true, retryChunksLimit: 3, chunksUploaded: function(file, done) { // 所有分片上传完成后,主动通知后端合并文件 fetch("uploadform.php", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: `action=merge&dzUuid=${file.upload.uuid}&dzFilename=${file.name}&dzTotalChunkCount=${file.upload.totalChunkCount}` }).then(response => response.text()) .then(data => { console.log("文件合并结果:", data); done(); // 告诉Dropzone整个上传流程完成 }).catch(err => { console.error("合并失败:", err); done(err); }); }, error: function(file, msg) { alert(`上传错误:${msg.responseText}`); } });
PHP后端完整代码(uploadform.php)
<?php // 自定义日志函数:输出到页面+写入日志文件 function _log($content) { echo $content . "<br>"; file_put_contents("upload_log.txt", date("Y-m-d H:i:s") . " - " . $content . PHP_EOL, FILE_APPEND); } // 临时分片存储目录,确保有写入权限 $tempDir = __DIR__ . "/temp_chunks/"; if (!is_dir($tempDir)) { mkdir($tempDir, 0777, true); } // 处理分片上传或合并请求 if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 处理文件合并请求 if (isset($_POST['action']) && $_POST['action'] === 'merge') { $uuid = $_POST['dzUuid']; $filename = $_POST['dzFilename']; $totalChunks = (int)$_POST['dzTotalChunkCount']; $finalFile = __DIR__ . "/uploads/" . $filename; // 创建最终文件存储目录 if (!is_dir(__DIR__ . "/uploads/")) { mkdir(__DIR__ . "/uploads/", 0777, true); } // 逐个合并分片 $finalHandle = fopen($finalFile, "wb"); $mergeSuccess = true; for ($i = 0; $i < $totalChunks; $i++) { $chunkFile = $tempDir . $uuid . "_chunk_" . $i; if (!file_exists($chunkFile)) { _log("合并失败:分片 $i 不存在"); $mergeSuccess = false; break; } fwrite($finalHandle, file_get_contents($chunkFile)); unlink($chunkFile); // 合并后删除临时分片 } fclose($finalHandle); if ($mergeSuccess) { _log("文件合并完成:$filename"); exit("上传成功"); } else { exit("分片缺失,合并失败"); } } // 处理分片上传请求 if (isset($_POST['dzUuid']) && isset($_POST['dzChunkIndex']) && isset($_FILES['file'])) { $uuid = $_POST['dzUuid']; $chunkIndex = (int)$_POST['dzChunkIndex']; $chunkFile = $tempDir . $uuid . "_chunk_" . $chunkIndex; if (move_uploaded_file($_FILES['file']['tmp_name'], $chunkFile)) { _log("分片 $chunkIndex 上传成功"); exit("分片上传成功"); } else { _log("分片 $chunkIndex 上传失败:错误码" . $_FILES['file']['error']); exit("分片上传失败"); } } // 无效请求处理 _log("未接收到有效分片或合并参数"); exit("无效请求"); } ?>
关键注意事项
- 参数格式正确性:你之前用
dzUuid=xxx的字符串格式完全错误,Dropzone需要标准的键值对对象才能识别分片参数,这是触发分片流程的核心。 - 目录权限:必须确保
temp_chunks/和uploads/目录有PHP写入权限,生产环境可根据服务器配置调整为更安全的权限(如0755)。 - 合并时机:通过
chunksUploaded回调主动通知后端合并分片,这一步是必须的,否则后端无法判断何时完成所有分片上传。 - 日志调试:保留
_log函数可以清晰追踪每个分片的上传状态和合并过程,方便排查问题。
内容的提问来源于stack exchange,提问作者Lokiare
相关产品推荐
相关产品推荐

