Upload Huge File - Mastering Chunked File Uploads in Laravel

Upload Huge File - Mastering Chunked File Uploads in Laravel

In this tutorial, you'll learn how to efficiently upload large files using Laravel and Resumable.js, handling chunked file uploads and merging them on the server side.Uploading large files can be a challenge, but by breaking them into chunks, you can improve performance and user experience.

Why Use Chunked File Uploads?

When working with large files like videos or high-resolution images, uploading them in one go may lead to interruptions or failures due to network issues. Chunked file uploads break down large files into smaller parts (chunks), allowing for: * Resuming uploads after interruptions * Improved system performance * Efficient handling of large files This guide will show you how to implement chunked file uploads in Laravel using Resumable.js, a JavaScript library designed to handle large file uploads by splitting them into smaller parts.

Prerequisites

If you haven’t installed Laravel yet, follow the Laravel installation instructions: Laravel Installation Documentation .

Step 1: Create a Controller for Chunked Uploads

To manage file uploads, we'll create a MediaController to handle both the chunked file uploads and the merging process on the server. Run the following command to generate the controller:
php artisan make:controller MediaController

Step 2: Set Up the Blade View

Here’s a basic HTML view for uploading files. We'll use Resumable.js for chunked uploads and Bootstrap for styling the progress bar
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Upload Huge File - Elegant Laravel</title> <!-- Resumable js --> <script src="https://cdnjs.cloudflare.com/ajax/libs/resumable.js/1.0.3/resumable.min.js" integrity="sha512-OmtdY/NUD+0FF4ebU+B5sszC7gAomj26TfyUUq6191kbbtBZx0RJNqcpGg5mouTvUh7NI0cbU9PStfRl8uE/rw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <!-- Bootstrap js --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> </head> <body> <div class="video_upload mt-5" id="video_upload "> <div id="upload-container" class="text-center"> <button id="browseFile" class="btn btn-primary">Upload File</button> </div> <div style="display: none" class="progress mt-3 w-25 mx-auto" style="height: 25px"> <div class="progress-bar progress-bar-striped progress-bar-animated text-center" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 75%; height: 100%"> 75%</div> </div> </div> <div class="d-none text-center" id="final_success"> <h2 class="text-success">File Upload Successfull </h2> </div> <!-- Botostrap --> <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js"></script> <!-- Jquery --> <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script> </body> </html>

Step 3: Set Up Routes for Chunked Uploads

Add the following routes in routes/web.php:
use App\Http\Controllers\MediaController; Route::get('/media', [MediaController::class,'create']); Route::post('/media', [MediaController::class,'uploadMedia'])->name('media.upload');

Handle AJAX Request from Blade Template

let resumable = new Resumable({ target: "{{ route('media.upload') }}", query: { _token: '{{ csrf_token() }}' }, chunkSize: 10 * 1024 * 1024, // 10MB chunks testChunks: false, throttleProgressCallbacks: 1, }); resumable.assignBrowse(document.getElementById('browseFile')); resumable.on('fileAdded', function(file) { // trigger when file picked showProgress(); resumable.upload() // to actually start uploading. }); resumable.on('fileProgress', function(file) { // trigger when file progress update updateProgress(Math.floor(file.progress() * 100)); }); resumable.on('fileSuccess', function(file, response) { // trigger when file upload complete $('#video_upload').addClass('d-none'); $('#video_upload').hide(); $('#final_success').removeClass('d-none'); $('#final_success').show(); hideProgress(); }); resumable.on('fileError', function(file, response) { // trigger when there is any error hideProgress(); alert('file uploading error.') }); let progress = $('.progress'); function showProgress() { progress.find('.progress-bar').css('width', '0%'); progress.find('.progress-bar').html('0%'); progress.find('.progress-bar').removeClass('bg-success'); progress.show(); } function updateProgress(value) { progress.find('.progress-bar').css('width', `${value}%`) progress.find('.progress-bar').html(`${value}%`) } function hideProgress() { progress.hide(); }

Step 4: Handling File Chunks in the Controller

In MediaController, we’ll handle the chunked file uploads and merge them once all parts are uploaded.
namespace App\Http\Controllers; use Illuminate\Http\Request; class MediaController extends Controller { public function create() { return view('media'); } public function uploadMedia(Request $request) { $file = $request->file('file'); $chunkNumber = $request->input('resumableChunkNumber'); $totalChunks = $request->input('resumableTotalChunks'); $fileName = $request->input('resumableFilename'); $filePath = storage_path('app/uploads/' . $fileName . '.part'); // Move the uploaded chunk to the temporary directory $file->move(storage_path('app/uploads'), $fileName . '.part' . $chunkNumber); if ($chunkNumber == $totalChunks) { $this->mergeChunks($fileName, $totalChunks); } return response()->json(['message' => 'Chunk uploaded successfully']); } private function mergeChunks($fileName, $totalChunks) { $filePath = storage_path('app/uploads/' . $fileName); $output = fopen($filePath, 'wb'); for ($i = 1; $i <= $totalChunks; $i++) { $chunkPath = storage_path('app/uploads/' . $fileName . '.part' . $i); $chunkFile = fopen($chunkPath, 'rb'); stream_copy_to_stream($chunkFile, $output); fclose($chunkFile); unlink($chunkPath); } fclose($output); } }

Output

Install Bootstrap in laravel 11

Summary

After uploading huge files in chunks using Resumable.js and ajax request , now you have the solution to handle large file efficiently.This approach is smooth and reliable for huge file uploading.Make sure to adapt the chunk size based on your server capabilities and the average file size expected from your users. With chunked uploads, you can scale your application to handle larger files more efficiently.
Tags
Upload Huge File Laravel Chunk Upload Big File In Chunks Laravel Laravel Tutorial Mastering Laravel Laravel Fast Uploads Laravel File Handling Resumable.js Video File Upload Php Large Files Laravel Performance Optimization

Recommended Articles