You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何仅用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:20:18