Stahování souborů z adres URL v systému Laravel

Zpracování stahování souborů z adres URL v systému Laravel V tomto článku se dozvíte, jak v aplikaci Laravel stahovat soubory z externích adres URL. Budete to dělat jak pro uložen...

Poptat web

04. 12. 2025

Stahování souborů z adres URL v systému Laravel

Zpracování stahování souborů z adres URL v systému Laravel

V tomto článku se dozvíte, jak v aplikaci Laravel stahovat soubory z externích adres URL. Budete to dělat jak pro uložení souboru na serveru, tak pro jeho odeslání uživateli ke stažení. Vše se odehrává uvnitř běžného kódu Laravelu, například v kontrolérech nebo úlohách. Zaměříme se pouze na praktické, kopírovatelné vzory, které můžete přizpůsobit svému vlastnímu projektu.

Základní nastavení ovladače

Všechny níže uvedené příklady předpokládají volání metody řadiče z trasy. Například:

// routes/web.php
 
use App\Http\Controllers\FileDownloadController;
use Illuminate\Support\Facades\Route;
 
Route::get('/download-remote', [FileDownloadController::class, 'downloadRemote']);
Route::get('/cache-remote', [FileDownloadController::class, 'cacheRemote']);
// app/Http/Controllers/FileDownloadController.php
 
namespace App\Http\Controllers;
 
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
 
class FileDownloadController extends Controller
{
// methods will go here
}

Nemusíte svůj kód strukturovat přesně takto, ale díky speciálnímu kontroléru jsou příklady přehledné.

Přímé streamování vzdálené adresy URL do prohlížeče

Někdy chcete pouze převzít vzdálenou adresu URL souboru a nechat uživatele stáhnout jej prostřednictvím aplikace Laravel, aniž byste jej museli ukládat na disk. To je běžné, když stahujete přes proxy server svou aplikaci kvůli ověřování nebo protokolování.

Můžete to udělat pomocí response()->streamDownload() a obyčejný proud PHP:

// app/Http/Controllers/FileDownloadController.php
 
public function downloadRemote(Request $request)
{
$url = $request->query('url'); // example: https://example.com/file.pdf
 
if (! $url) {
abort(400, 'Missing url parameter');
}
 
$fileName = basename(parse_url($url, PHP_URL_PATH)) ?: 'downloaded-file';
 
return response()->streamDownload(function () use ($url) {
$read = fopen($url, 'r');
 
if (! $read) {
abort(502, 'Unable to open remote file');
}
 
while (! feof($read)) {
echo fread($read, 1024 * 1024); // 1 MB chunks
}
 
fclose($read);
}, $fileName);
}

Co to dělá:

  • Čte url parametr dotazu z požadavku.
  • Používá streamDownload streamovat vzdálený soubor přímo do prohlížeče.
  • Používá fopen a fread ve smyčce, takže soubor není zcela načten do paměti.
  • vybere název souboru z cesty URL, nebo se vrátí zpět na adresu downloaded-file.

Okrajové případy, na které je třeba dávat pozor:

  • allow_url_fopen musí být v PHP povoleno, aby fopen($url, 'r') do práce.
  • Pokud je vzdálený server pomalý nebo nedostupný, bude váš požadavek také pomalý nebo selže.
  • Před povolením stahování můžete přidat vlastní logiku autorizace.

Stažení souboru z adresy URL a jeho uložení na disk

Velmi často chcete jednou načíst vzdálený soubor, uložit jej někam na úložný disk a pak jej odtud obsluhovat. To se hodí pro ukládání vzdálených aktiv, faktur, zpráv a podobných souborů do mezipaměti.

Jednoduchým přístupem je použití klienta Laravel HTTP a fasády Úložiště.

// app/Http/Controllers/FileDownloadController.php
 
public function cacheRemote(Request $request)
{
$url = $request->query('url');
 
if (! $url) {
abort(400, 'Missing url parameter');
}
 
$response = Http::timeout(30)->get($url);
 
if (! $response->successful()) {
abort(502, 'Failed to download remote file');
}
 
$extension = pathinfo(parse_url($url, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION);
 
$fileName = 'remote_' . time() . ($extension ? ".{$extension}" : '');
 
$path = "downloads/{$fileName}";
 
Storage::disk('local')->put($path, $response->body());
 
return response()->json([
'stored_as' => $path,
'disk' => 'local',
]);
}

Co to dělá:

  • Použije klienta HTTP k získání vzdálené adresy URL s časovým limitem.
  • Kontroly successful() abyste neukládali chybové stránky jako soubory.
  • Odvozuje jednoduché rozšíření z cesty URL.
  • zapíše nezpracované tělo odpovědi do storage/app/downloads/... pomocí local disk.
  • Vrátí malé užitečné zatížení JSON s místem uložení souboru.

Pro typické malé a střední soubory je to v pořádku. U velmi velkých souborů tento přístup načte celý soubor do paměti jednou, takže pokud na tom záleží, použijte v další části přístup založený na streamování.

Streamování adresy URL přímo do úložiště pomocí sink HTTP

U velkých souborů obvykle nechcete mít v paměti celý soubor. HTTP klient Laravel je postaven na platformě Guzzle, která podporuje funkci sink který přenáší odpověď přímo do souboru.

// app/Http/Controllers/FileDownloadController.php
 
use GuzzleHttp\Psr7\Utils;
 
public function cacheRemoteStreamed(Request $request)
{
$url = $request->query('url');
 
if (! $url) {
abort(400, 'Missing url parameter');
}
 
$extension = pathinfo(parse_url($url, PHP_URL_PATH) ?? '', PATHINFO_EXTENSION);
$fileName = 'remote_' . time() . ($extension ? ".{$extension}" : '');
 
$relativePath = "downloads/{$fileName}";
$absolutePath = Storage::disk('local')->path($relativePath);
 
$resource = Utils::tryFopen($absolutePath, 'w');
 
Http::withOptions([
'sink' => $resource,
'timeout' => 60,
])->get($url);
 
return response()->json([
'stored_as' => $relativePath,
'disk' => 'local',
]);
}

Co to dělá:

  • Vytvoří zapisovatelný handle souboru uvnitř local kořenový adresář disku (ve výchozím nastavení storage/app/private/downloads/...).
  • předá tento handle klientovi HTTP prostřednictvím příkazu sink možnost.
  • Guzzle přenáší odpověď do souboru tak, jak přichází.
  • Využití paměti zůstává nízké i u velkých souborů.

Pokud chcete, můžete místo prostředku předat celý řetězec cesty k souboru do pole sinka Guzzle vám soubor otevře.

Umožnění uživateli stáhnout uložený soubor

Jakmile je soubor uložen na disku, obvykle chcete uživateli umožnit jeho stažení. Pokud jste soubor uložili pomocí Storage na interním disku (například local), nejjednodušší způsob je Storage::download().

// app/Http/Controllers/FileDownloadController.php
 
public function downloadCached(Request $request)
{
$path = $request->query('path'); // for example downloads/remote_1700000000.pdf
 
if (! $path) {
abort(400, 'Missing path parameter');
}
 
if (! Storage::disk('local')->exists($path)) {
abort(404, 'File not found');
}
 
return Storage::disk('local')->download($path);
}

Co to dělá:

  • Čte path který byl vrácen při ukládání souboru do mezipaměti.
  • Zkontroluje, zda soubor existuje na local disk.
  • Vrací odpověď na stahování, která donutí prohlížeč stáhnout soubor.

Můžete také přepsat název stahovaného souboru a hlavičky:

return Storage::disk('local')->download($path, 'report.pdf', [
'Content-Type' => 'application/pdf',
]);

Kombinace vzdáleného stahování a stahování uživatelem v jednom požadavku

Někdy chcete načíst soubor z adresy URL a okamžitě jej odeslat do prohlížeče, aniž byste si uchovávali kopii. Můžete kombinovat klienta HTTP a streamDownload k tomu.

// app/Http/Controllers/FileDownloadController.php
 
public function proxyRemote(Request $request)
{
$url = $request->query('url');
 
if (! $url) {
abort(400, 'Missing url parameter');
}
 
$fileName = basename(parse_url($url, PHP_URL_PATH)) ?: 'downloaded-file';
 
$response = Http::timeout(60)->get($url);
 
if (! $response->successful()) {
abort(502, 'Failed to download remote file');
}
 
$contentType = $response->header('Content-Type', 'application/octet-stream');
 
return response()->streamDownload(function () use ($response) {
echo $response->body();
}, $fileName, [
'Content-Type' => $contentType,
]);
}

Co to dělá:

  • Načte vzdálenou adresu URL pomocí klienta HTTP.
  • Ověřuje, že odpověď byla úspěšná.
  • Používá dálkový ovladač Content-Type hlavičku při odesílání souboru do prohlížeče.
  • Zabalí tělo do streamDownload aby se do prohlížeče stáhla správná příloha.

Tento přístup je vhodný pro malé nebo středně velké soubory. U velmi velkých souborů byste se měli držet varianty streamování, která neukládá celé tělo odpovědi do paměti.

Používání front nebo úloh cronu ke stahování z adres URL

Pokud stahování vzdáleného souboru trvá dlouho, obvykle nechcete blokovat běžný webový požadavek. Běžný vzor je:

  • Požadavek HTTP odešle úlohu, která stáhne a uloží vzdálený soubor pomocí jedné z výše uvedených metod mezipaměti.
  • Úloha zapíše cestu do databáze.
  • Samostatná akce řadiče později zpřístupní soubor prostřednictvím Storage::download().

Přesné nastavení fronty a plánování závisí na vaší aplikaci, ale můžete znovu použít stejný systém. cacheRemote or cacheRemoteStreamed kód uvnitř třídy úloh.

Závěr

Viděli jste, jak stahovat soubory z externích adres URL uvnitř aplikace Laravel. Vzdálené soubory můžete streamovat přímo do prohlížeče, ukládat je do mezipaměti nebo obojí. Víte také, jak pracovat s malými soubory pomocí jednoduchého Http::get volání a velké soubory pomocí možnosti HTTP sink. Pomocí těchto vzorů můžete pokrýt většinu reálných požadavků na stahování z adresy URL bez dalších balíčků.

Původní článek publikoval Nabil Hassen.