使用 Laravel 合併前端上傳的檔案片段
當前端將檔案(例如 MP4)分割為多個片段後逐一上傳到伺服器,我們可以透過 Laravel 在後端合併這些片段,形成完整的檔案。這篇文章記錄了如何在 Laravel 中實現不使用 FFmpeg 的檔案合併流程。
流程概覽
- 前端將檔案切割為多個片段並逐一上傳。
- 後端接收並儲存這些片段。
- 後端將片段合併成完整檔案。
- 合併後的檔案進行驗證,確保檔案完整性。
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 這樣的多媒體檔案。如果有需要,你可以進一步加入更多的驗證機制以確保檔案的完整性與正確性。