首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 大文件分割與合併實現斷點續傳核心邏輯

     編輯:PHP 綜合知識

核心原理

將大文件按固定塊大小(如 10MB)切分為多個臨時文件,上傳時逐塊傳輸,中斷後可從失敗塊繼續;合併時按序讀取臨時文件追加寫入目標文件。

分割與合併核心類

<?php
class FileChunker {
    private $chunkSize;
    private $tempDir;
    private $prefix;

    public function __construct(int $chunkSize = 10 * 1024 * 1024, string $tempDir = '/tmp', string $prefix = 'chunk_') {
        $this->chunkSize = $chunkSize;
        $this->tempDir   = rtrim($tempDir, '/');
        $this->prefix    = $prefix;
    }

    /**
     * 分割文件
     * @return array ['total' => 總塊數, 'files' => 臨時文件路徑數組]
     */
    public function split(string $sourcePath): array {
        if (!is_file($sourcePath)) throw new InvalidArgumentException('Source file not exists');
        $handle = fopen($sourcePath, 'rb');
        $files = [];
        $index = 0;
        while (!feof($handle)) {
            $chunk = fread($handle, $this->chunkSize);
            if ($chunk === '') break;
            $index++;
            $chunkFile = "{$this->tempDir}/{$this->prefix}{$index}.part";
            file_put_contents($chunkFile, $chunk);
            $files[] = $chunkFile;
        }
        fclose($handle);
        return ['total' => $index, 'files' => $files];
    }

    /**
     * 合併文件
     * @param array $chunkFiles 按序排列的臨時文件路徑
     */
    public function merge(array $chunkFiles, string $targetPath): bool {
        $target = fopen($targetPath, 'wb');
        foreach ($chunkFiles as $file) {
            if (!is_file($file)) return false;
            $src = fopen($file, 'rb');
            stream_copy_to_stream($src, $target);
            fclose($src);
        }
        fclose($target);
        return true;
    }

    /**
     * 清理臨時文件
     */
    public function cleanup(array $chunkFiles): void {
        foreach ($chunkFiles as $file) {
            @unlink($file);
        }
    }
}

// 使用示例
$chunker = new FileChunker(10 * 1024 * 1024, sys_get_temp_dir(), 'upload_');

// 1. 分割(服務端預處理或客戶端分片上傳)
$result = $chunker->split('/path/to/large_file.zip');
echo "分割完成,共 {$result['total']} 片\n";

// 2. 模擬上傳後合併
$success = $chunker->merge($result['files'], '/path/to/restored.zip');
echo $success ? '合併成功' : '合併失敗';

// 3. 清理
$chunker->cleanup($result['files'])

斷點續傳完整流程設計

前端(JavaScript)

  1. File API 讀取文件,blob.slice(start, end) 切片
  2. 計算每片 SHA-256(可選,用於秒傳/校驗)
  3. 並發上傳分片,記錄已上傳分片索引到 localStorage
  4. 失敗重試、暫停恢復讀取本地記錄
  5. 全部分片上傳完成,調用合併接口

後端(PHP)

<?php
// 1. 接收分片
$chunkIndex = (int)($_POST['chunk'] ?? 0);
$totalChunks = (int)($_POST['chunks'] ?? 0);
$fileHash = $_POST['file_hash'] ?? ''; // 唯一標識
$tempDir = sys_get_temp_dir() . "/uploads/{$fileHash}";
@mkdir($tempDir, 0755, true);

$chunkFile = "{$tempDir}/{$chunkIndex}.part";
move_uploaded_file($_FILES['file']['tmp_name'], $chunkFile);

// 2. 檢查是否全部到齊
$uploaded = glob("{$tempDir}/*.part");
if (count($uploaded) === $totalChunks) {
    // 3. 合併(按文件名排序保證順序)
    sort($uploaded, SORT_NATURAL);
    $targetPath = "/data/uploads/{$fileHash}.zip";
    $fp = fopen($targetPath, 'wb');
    foreach ($uploaded as $part) {
        $fh = fopen($part, 'rb');
        stream_copy_to_stream($fh, $fp);
        fclose($fh);
    }
    fclose($fp);

    // 4. 校驗完整性(可選)
    if (hash_file('sha256', $targetPath) === $fileHash) {
        // 5. 清理分片
        array_map('unlink', $uploaded);
        rmdir($tempDir);
        echo json_encode(['status' => 'complete', 'path' => $targetPath]);
    } else {
        echo json_encode(['status' => 'checksum_failed']);
    }
} else {
    echo json_encode(['status' => 'chunk_received', 'received' => count($uploaded)]);
}

關鍵優化點

優化說明
流式複製stream_copy_to_stream 避免將大塊內容載入內存
分片校驗上傳前計算 SparkMD5/Hash,支持秒傳、斷點校驗
並發控制Nginx limit_req_zone + PHP 信號量防止磁盤 IO 暴衝
斷點恢復前端記錄已上傳索引,續傳時跳過
臨時文件清理定時任務清理 24h 以上未完成上傳目錄
大文件直傳雲存儲阿里云 OSS/騰訊云 COS 分片上傳 API,減輕源站壓力

生產級建議

  • 使用成熟庫:tus-php 實現 TUS 協議(HTTP 分片上傳標準)
  • 對象存儲直傳:前端獲取簽名直傳 OSS/COS/S3,後端僅處理回調合併
  • 異步合併:大文件合併耗時長,放入消息隊列異步處理,WebSocket 推送進度
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved