Have you ever needed to upload large files like movies, songs, or documents? I’m sure you have. However, these files can be massive—often exceeding 10GB—and uploading them all at once from a mobile device can be challenging due to bandwidth limitations. Keep reading to learn how to upload large files using Laravel and React.js efficiently.
Chunk files
Well, basically, we’ll split our files into smaller chunks, upload them to the backend using React JS, and then reassemble them there. See how to create the initial project here
Set up React Js
First, we will require a zone to select our files, so let’s install react-drag-drop-files
npm i react-drag-drop-files
Now, let’s place the next code in resources\js\components\Upload.jsx
. We are going to send it to /test
but you can customize it:
import React, { useState } from 'react';
import ReactDOM from 'react-dom/client';
import axios from 'axios'
import { FileUploader } from "react-drag-drop-files";
function Upload() {
const [file, setFile] = useState(null);
const [percent, setPercent] = useState(0);
const [text, setText] = useState("Upload");
const handleChange = async (file) => {
setFile(file);
setText("Upload");
setPercent(0);
};
const upload = async () => {
const chunkSize = 1024 * 1024;
let start = 0;
let r = window.crypto.randomUUID();
while (start < file.size) {
var status = await uploadChunk(file.slice(start, start + chunkSize), r + file.name, (start + chunkSize) >= file.size);
if (status == 0) {
return;
}
start += chunkSize;
setPercent((Math.min(start, file.size) / file.size * 100).toFixed(2));
}
}
const uploadChunk = async (chunk, filename, is_last) => {
const formData = new FormData();
formData.append('file', chunk, filename);
formData.append('name', filename);
formData.append('is_last', is_last == true ? 1 : 0)
console.log("is_last: " + is_last);
await axios({
method: 'post',
url: '/test',
data: formData,
headers: { 'Content-Type': 'multipart/form-data' }
})
.then(response => {
if (response.data != "") {
setText("Uploaded successfully!");
}
console.log(response);
}).catch(error => {
console.log("error");
console.log(error);
setText("An error ocurred!");
setPercent(0);
return 0;
})
}
return (
<>
<FileUploader handleChange={handleChange} name="file" />
{file == null ? "" : file.name}
<br />
<button className='btn btn-primary mt-3' onClick={upload}>{text} {percent > 0 ? percent + "%" : ""}</button>
</>
);
}
export default Upload;
if (document.getElementById('example')) {
const Index = ReactDOM.createRoot(document.getElementById("example"));
Index.render(
<React.StrictMode>
<Upload />
</React.StrictMode>
)
}
Remember to add it to resources\js\app.js
:
import './components/Upload'
Now that the front-end side is complete, you will have the next view:
Concat chunk files
Now it is time to set up the backend, so let’s create a file ConcatFile.php
in the same folder of our controller; in this case, it will be app\Http\Controllers\HomeController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Str;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
class ConcatFile
{
protected string $filePath;
public function __construct(
public UploadedFile $file,
private readonly bool $isLast
) {
if (!Storage::disk('local')->exists('files')) {
Storage::disk('local')->makeDirectory('files');
}
$tempFileName = $file->getClientOriginalName();
$this->filePath = Storage::disk('local')->path(
"files/{$tempFileName}"
);
}
public function joinFile()
{
file_put_contents($this->filePath, $this->file->get(), FILE_APPEND);
if ($this->isLast) {
$path ='files/' . $this->file->getClientOriginalName();
return $path;
}
return null;
}
}
Finally, we will call it from our controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
public function index(){
return view('home');
}
public function test(Request $request) {
$filepath = new ConcatFile(
file: $request->file,
isLast: $request->is_last
);
$path = $filepath->joinFile();
return $path;
}
}
Let’s add test to the routes at routes\web.php
:
Route::post('/test', [App\Http\Controllers\HomeController::class, 'test'])->name('test');
Testing
Finally, let’s update a large file from react js and verify that it is in storage\app\private\files\cac7beb8-959f-4608-bb19-781f50042084intro.mp4
Feel free to comment, happy coding 🙂 !