使用 Laravel 合併前端上傳的檔案片段

使用 Laravel 合併前端上傳的檔案片段

使用 Laravel 合併前端上傳的檔案片段

當前端將檔案(例如 MP4)分割為多個片段後逐一上傳到伺服器,我們可以透過 Laravel 在後端合併這些片段,形成完整的檔案。這篇文章記錄了如何在 Laravel 中實現不使用 FFmpeg 的檔案合併流程。

流程概覽

  1. 前端將檔案切割為多個片段並逐一上傳。
  2. 後端接收並儲存這些片段。
  3. 後端將片段合併成完整檔案。
  4. 合併後的檔案進行驗證,確保檔案完整性。

1. 前端檔案切割與上傳

在前端,我們可以使用 Blob.slice() API 將檔案切割成多個片段,然後每次上傳一個片段到伺服器。

範例程式碼:

const splitFile = (file, chunkSize) => {
  const chunks = [];
  let currentChunk = 0;

  while (currentChunk < file.size) {
    const chunk = file.slice(currentChunk, currentChunk + chunkSize);
    chunks.push(chunk);
    currentChunk += chunkSize;
  }

  return chunks;
};

這樣可以將檔案切割成大小一致的片段並進行逐步上傳。每個片段需要包含一些資料,如片段編號和原始檔案名稱,便於後端進行合併。

2. 後端儲存片段

在 Laravel 中,每個片段上傳時,我們將它們暫時儲存到伺服器上的指定目錄,這些片段會按照順序命名。

儲存片段的範例 Controller:

use Illuminate\Http\Request;

class FileUploadController extends Controller
{
    public function uploadChunk(Request $request)
    {
        // 檢查請求是否包含檔案
        if ($request->hasFile('file')) {
            $chunk = $request->file('file');
            $chunkNumber = $request->input('chunkNumber');
            $fileName = $request->input('fileName');
            
            // 指定儲存片段的目錄
            $chunkDir = storage_path('app/chunks/' . $fileName);

            // 如果目錄不存在,則創建
            if (!file_exists($chunkDir)) {
                mkdir($chunkDir, 0777, true);
            }

            // 將片段儲存到指定目錄,片段名稱為 chunk_1, chunk_2 等
            $chunk->move($chunkDir, 'chunk_' . $chunkNumber);

            return response()->json(['status' => 'Chunk uploaded successfully']);
        }

        return response()->json(['status' => 'No file uploaded'], 400);
    }
}

3. 後端合併片段

當所有片段上傳完成後,我們會將這些片段按順序讀取並合併成一個完整的檔案。

合併片段的範例 Controller:

use Illuminate\Support\Facades\Storage;

class FileUploadController extends Controller
{
    public function mergeChunks(Request $request)
    {
        $fileName = $request->input('fileName');
        $chunkDir = storage_path('app/chunks/' . $fileName);
        $finalFilePath = storage_path('app/merged/' . $fileName);

        // 打開一個檔案來寫入合併後的結果
        $finalFile = fopen($finalFilePath, 'ab');

        // 獲取所有片段文件,並按順序排序
        $chunkFiles = glob($chunkDir . '/chunk_*');
        natsort($chunkFiles); // 自然排序片段,確保順序正確

        // 將所有片段按順序寫入最終檔案
        foreach ($chunkFiles as $chunkFile) {
            $chunk = fopen($chunkFile, 'rb');
            while (!feof($chunk)) {
                fwrite($finalFile, fread($chunk, 8192));
            }
            fclose($chunk);
        }

        // 關閉最終檔案
        fclose($finalFile);

        // 刪除片段目錄及檔案
        $this->deleteDirectory($chunkDir);

        return response()->json(['status' => 'File merged successfully', 'filePath' => $finalFilePath]);
    }

    // 刪除目錄及其內容
    private function deleteDirectory($dir) {
        if (!is_dir($dir)) return;

        $files = array_diff(scandir($dir), ['.', '..']);
        foreach ($files as $file) {
            (is_dir("$dir/$file")) ? $this->deleteDirectory("$dir/$file") : unlink("$dir/$file");
        }
        rmdir($dir);
    }
}

這裡的 mergeChunks 方法負責將所有的片段合併到一起,並最終刪除片段的臨時目錄。

4. 合併後的檔案驗證

合併完成後,我們可以進行一些基本的檔案驗證,來確保檔案的完整性。

檔案大小比對

你可以檢查合併後的檔案大小是否與原始檔案一致。

哈希值比對

前端可以在上傳前計算原始檔案的哈希值,然後後端在合併完成後計算最終檔案的哈希值,兩者比對來確保檔案沒有損壞。

播放測試

對於影片檔案,檢查合併後影片的播放情況,確保影片能夠從頭到尾播放且內容完整。

結論

不使用 FFmpeg 的情況下,我們可以在 Laravel 中利用 PHP 的檔案處理功能來合併檔案片段。這種方法適用於各種文件類型,包括影片檔案,如 MP4。以下是該流程的總結:

前端切割檔案並逐一上傳片段。 後端接收並儲存片段,最後進行合併。 合併後對檔案進行驗證,確保檔案完整性。 這個流程可以應用於許多情況,特別是需要處理大檔案上傳的場景。

這篇文章詳細記錄了如何在 Laravel 中實現檔案片段的合併,不僅適用於一般的檔案類型,也可以用於像 MP4 這樣的多媒體檔案。如果有需要,你可以進一步加入更多的驗證機制以確保檔案的完整性與正確性。

© 2024 YunBao 紜寶

Version 0.0.4