Uploading large files in Laravel without breaking
In the first version of my media service the upload went in a single request. With large videos this broke regularly, because the network layer in front of the server limits both the size and the duration of a request: at around 100 MB and 100 seconds it cuts the connection.
The fix: chunks
The browser cuts the file into 20 MB chunks and sends them one after another. There are three steps.
- init: the server receives the file name, size and chunk count, and returns an upload ID.
- chunk: one piece, with its index. The server stores it as a numbered file.
- complete: the server assembles the chunks in order, checks the size, and hands the file to the existing processor.
Make the retry harmless
The key is that resending the same index overwrites the chunk. So the browser can retry without worry. Mine tries four times, with longer and longer waits, and no harm can come of it.
// Re-sending the same index overwrites the part, so a retry is idempotent.
$request->file('chunk')->move($dir, sprintf('%06d.part', $index));
// ... later, in complete(): assemble the parts in order
$out = fopen($assembled, 'wb');
for ($i = 0; $i < $info['total_chunks']; $i++) {
$part = $dir.'/'.sprintf('%06d.part', $i);
if (! is_file($part)) {
fclose($out);
return response()->json(['success' => false, 'message' => "Missing chunk: {$i}"], 422);
}
$in = fopen($part, 'rb');
stream_copy_to_stream($in, $out);
fclose($in);
}
fclose($out);
if (filesize($assembled) !== $info['size']) {
File::deleteDirectory($dir);
return response()->json(['success' => false, 'message' => 'Size mismatch.'], 422);
}
An excerpt of real code, anonymised.
What else is worth knowing
I check size and type on the assembled file, not on what the client claims, because the latter can be forged. I block executable and server-side extensions. After assembly, the chunk folder is deleted.
I kept the single-request endpoint for backward compatibility, but the new pages no longer use it.
Working on a similar problem?
If you are stuck, or want a second look at your solution, write to me. I am happy to look.
Write to me →More articles
Rewriting a legacy system while it runs
How I replace an old system while users keep working: identical behaviour, a list of differences, audit logging.
Read →How not to send the wrong email to the wrong person
Sending is the easy part of email campaigns. These are the safeguards I built into my own system.
Read →