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

Amazon S3(PHP):复制5GB以上文件失败,寻求分段复制实现方案

解决S3大文件复制问题的PHP实现

S3的copyObject接口仅支持复制≤5GB的文件,超过这个大小必须使用分段复制(Multipart Copy)。下面是修改后的代码,会自动判断文件大小,对大文件执行分段复制:

// STEP #1 - SYSTEM FOLDER BACKUP
$objects = $s3->getIterator('ListObjects', array('Bucket' => 'backups', 'Prefix' => $yesterday_system));
$objects = iterator_to_array($objects);

// 定义5GB的字节数阈值
$MAX_SINGLE_COPY_SIZE = 5 * 1024 * 1024 * 1024; // 5368709120
// 定义分段大小(建议8MB-100MB,这里用8MB)
$PART_SIZE = 8 * 1024 * 1024; // 8388608

// 遍历文件
if (!empty($objects)) {
    foreach ($objects as $object) {
        $sourceKey = $object['Key'];
        $fileSize = $object['Size'];
        
        // 处理目标Key
        list($ignore_1a, $ignore_1b, $key_2) = explode('/', $sourceKey);
        $targetKey = "_final/{$yesterday_year}/{$yesterday_month}/{$yesterday_day}/system/{$key_2}";
        $copySource = "backups/" . rawurlencode($sourceKey);

        if ($fileSize <= $MAX_SINGLE_COPY_SIZE) {
            // 小文件用普通复制
            $s3->copyObject([
                'ACL' => 'private',
                'Bucket' => 'backups',
                'CopySource' => $copySource,
                'Key' => $targetKey
            ]);
        } else {
            // 大文件执行分段复制
            copyLargeS3Object($s3, 'backups', $copySource, $targetKey, $fileSize, $PART_SIZE);
        }
    }
}

/**
 * 分段复制S3大文件
 * @param \Aws\S3\S3Client $s3 S3客户端实例
 * @param string $targetBucket 目标Bucket名称
 * @param string $copySource 源文件路径(格式:bucket/key)
 * @param string $targetKey 目标文件Key
 * @param int $fileSize 源文件大小(字节)
 * @param int $partSize 每个分段的大小(字节)
 */
function copyLargeS3Object($s3, $targetBucket, $copySource, $targetKey, $fileSize, $partSize) {
    // 1. 初始化分段复制任务
    $initResponse = $s3->createMultipartUpload([
        'ACL' => 'private',
        'Bucket' => $targetBucket,
        'Key' => $targetKey
    ]);
    $uploadId = $initResponse['UploadId'];

    $parts = [];
    $partNumber = 1;
    $offset = 0;

    // 2. 逐个复制分段
    while ($offset < $fileSize) {
        $currentPartSize = min($partSize, $fileSize - $offset);
        
        // 复制当前分段
        $copyResponse = $s3->uploadPartCopy([
            'Bucket' => $targetBucket,
            'Key' => $targetKey,
            'UploadId' => $uploadId,
            'PartNumber' => $partNumber,
            'CopySource' => $copySource,
            'CopySourceRange' => "bytes={$offset}-" . ($offset + $currentPartSize - 1)
        ]);

        $parts[] = [
            'PartNumber' => $partNumber,
            'ETag' => $copyResponse['CopyPartResult']['ETag']
        ];

        $offset += $currentPartSize;
        $partNumber++;
    }

    // 3. 完成分段复制
    $s3->completeMultipartUpload([
        'Bucket' => $targetBucket,
        'Key' => $targetKey,
        'UploadId' => $uploadId,
        'MultipartUpload' => ['Parts' => $parts]
    ]);
}

关键说明

  • 分段大小可根据实际情况调整(8MB-100MB区间最优),避免过多分段导致性能损耗
  • 分段复制分为三步:初始化任务、分块复制、完成上传,每个分段的ETag必须妥善保存并在最后提交
  • 保留了原脚本的文件路径处理逻辑,仅修改了复制逻辑部分

内容的提问来源于stack exchange,提问作者homertino

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 10:02:34