Ugrás a tartalomra
Rapcsány Krisztián Rapcsány Krisztián
← Összes cikk
2 perc olvasás

Nagy fájlok feltöltése megszakadás nélkül Laravelben

Laravel Feltöltés Videó

A média szolgáltatásomban az első verzióban a feltöltés egyetlen kérésben ment. Nagy videóknál ez rendszeresen megszakadt, mert a szerver előtt lévő hálózati réteg egy kérés méretét és idejét is korlátozza: nagyjából 100 MB-nál és 100 másodpercnél elvágja a kapcsolatot.

A megoldás: darabok

A böngésző 20 MB-os darabokra vágja a fájlt, és sorban küldi őket. Három lépés van.

  • init: a szerver megkapja a fájlnevet, a méretet és a darabszámot, és ad egy feltöltés-azonosítót.
  • chunk: egy darab, indexszel. A szerver sorszámozott fájlként elmenti.
  • complete: a szerver sorrendben összefűzi a darabokat, ellenőrzi a méretet, és átadja a meglévő feldolgozónak.

Az újrapróbálás legyen ártalmatlan

A lényeg az, hogy ugyanannak az indexnek az újraküldése felülírja a darabot. Így a böngésző nyugodtan újrapróbálhat. Nálam négyszer próbálkozik, egyre hosszabb várakozással, és ebből nem lehet kár.

UploadChunkController.php
// 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);
}

Kivonat valódi kódból, anonimizálva.

Amit még érdemes tudni

A méretet és a típust az összefűzött fájlon ellenőrzöm, nem azon, amit a kliens állít, mert az utóbbi hamisítható. A futtatható és szerveroldali kiterjesztéseket letiltom. Az összefűzés után a darabok mappája törlődik.

Az egykérésű feltöltő végpontot meghagytam visszafelé kompatibilitás miatt, de az új oldalak már nem használják.

Hasonló problémán dolgozol?

Ha elakadtál, vagy átnéztetnéd a megoldásodat, írj, szívesen megnézem.

Írok neked →
Ajánlatot kérek →