[英]Download a file in Laravel using a URL to external resource
我將所有上傳內容保存在自定義的外部驅動器上。 這些文件是通過自定義 API 存儲的。
在 Laravel 5.2 中,我可以對本地文件執行此操作以下載它:
return response()->download('path/to/file/image.jpg');
不幸的是,當我傳遞 URL 而不是路徑時,Laravel 會拋出錯誤:
文件“ https://my-cdn.com/files/image.jpg ”不存在
(URL當然是一個虛擬的)。
有什么方法可以使用 Laravel 的實現來下載image.jpg文件,還是用普通的 PHP 來做呢?
沒有魔法,您應該使用copy()
函數下載外部圖像,然后在響應中將其發送給用戶:
$filename = 'temp-image.jpg';
$tempImage = tempnam(sys_get_temp_dir(), $filename);
copy('https://my-cdn.com/files/image.jpg', $tempImage);
return response()->download($tempImage, $filename);
TL;博士
如果您使用的是 5.6 或更高版本,請使用streamDownload 響應。 否則執行下面的函數。
原始答案
與“下載”響應非常相似,Laravel 有一個“流”響應可用於執行此操作。 查看API ,這兩個函數都是 Symfony 的 BinaryFileResponse 和 StreamedResponse 類的包裝器。 在 Symfony 文檔中,他們有很好的例子來說明如何創建 StreamedResponse
下面是我使用 Laravel 的實現:
<?php
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
Route::get('/', function () {
$response = response()->stream(function () {
echo file_get_contents('http://google.co.uk');
});
$name = 'index.html';
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$name,
str_replace('%', '', Str::ascii($name))
);
$response->headers->set('Content-Disposition', $disposition);
return $response;
});
2018-01-17 更新
這現在已經被合並到 Laravel 5.6中,並被添加到5.6 文檔中。 可以像這樣調用 streamDownload 響應:
<?php
Route::get('/', function () {
return response()->streamDownload(function () {
echo file_get_contents('https://my.remote.com/file/store-12345.jpg');
}, 'nice-name.jpg');
});
至於2020年,這一切都很容易。
2 行代碼下載到您的服務器,2 行代碼上傳到瀏覽器(如果需要)。
假設您希望將 Google 主頁的 HTML 本地保存到您的服務器上,然后返回 HTTP 響應以啟動瀏覽器以在客戶端幻燈片上下載文件:
// Load the file contents into a variable.
$contents = file_get_contents('www.google.com');
// Save the variable as `google.html` file onto
// your local drive, most probably at `your_laravel_project/storage/app/`
// path (as per default Laravel storage config)
Storage::disk('local')->put('google.html', $contents);
// -- Here your have saved the file from the URL
// -- to your local Laravel storage folder on your server.
// -- By default this is `your-laravel-project/storage/app` folder.
// Now, if desired, and if you are doing this within a web application's
// HTTP request (as opposite to CLI application)
// the file can be sent to the browser (client) with the response
// that instructs the browser to download the file at client side:
// Get the file path within you local filesystem
$path = Storage::url('google.html');
// Return HTTP response to a client that initiates the file downolad
return response()->download($path);
查找 Laravel Storage 外觀文檔以獲取有關磁盤配置的詳細信息,並使用文件下載文檔put
方法和響應以返回帶有 HTTP 響應的文件。
為什么不只使用簡單的重定向?
return \Redirect::to('https://my-cdn.com/files/image.jpg');
試試這個腳本:
// $main_url is path(url) to your remote file
$main_url = "http://dl.aviny.com/voice/marsieh/moharram/92/shab-02/mirdamad/mirdamad-m92-sh2-01.mp3";
header("Content-disposition:attachment; filename=$main_url");
readfile($main_url);
如果您不希望最終用戶可以在標頭中看到 main_url,請嘗試以下操作:
$main_url = "http://dl.aviny.com/voice/marsieh/moharram/92/shab-02/mirdamad/mirdamad-m92-sh2-01.mp3";
$file = basename($main_url);
header("Content-disposition:attachment; filename=$file");
readfile($main_url);
對我來說,這里的一件事是能夠測試代碼。 使用較新的 Laravel https://laravel.com/docs/8.x/http-client我可以像這樣使用它
Http::get($follower->profile_pic_url)->body();
看起來像這樣獲取文件並保存
$contents = Http::get($follower->profile_pic_url)->body();
Storage::disk("local")->put($path, $contents);
然后在測試中模擬它
Storage::shouldReceive("disk->exists")->once()->andReturn(false);
Storage::shouldReceive("disk->put")->once();
Http::shouldReceive("get->body")->once();
您可以使用帶有download()
方法的瀏覽器提供要下載的文件
文檔:
示例:
return Storage::download('file.jpg');
return Storage::download('file.jpg', $name, $headers);
// or
return response()->download($pathToFile);
return response()->download($pathToFile, $name, $headers);
您可以提取原始文件的內容,計算出它的 mime 類型,然后制作您自己的響應並給出正確的標題。
我自己使用 PDF 庫執行此操作,但您可以修改為使用file_get_contents()
來下拉遠程資產:
return Response::make(
$pdf,
200,
array(
'Content-Description' => 'File Transfer',
'Cache-Control' => 'public, must-revalidate, max-age=0, no-transform',
'Pragma' => 'public',
'Expires' => 'Sat, 26 Jul 1997 05:00:00 GMT',
'Last-Modified' => ''.gmdate('D, d M Y H:i:s').' GMT',
'Content-Type' => 'application/pdf', false,
'Content-Disposition' => ' attachment; filename="chart.pdf";',
'Content-Transfer-Encoding' => ' binary',
'Content-Length' => ' '.strlen($pdf),
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Methods' =>'GET, PUT, POST, DELETE, HEAD, PATCH',
'Access-Control-Allow-Headers' =>'accept, origin, content-type',
'Access-Control-Allow-Credentials' => 'true')
);
您需要將$pdf
更改為文件的數據,將Content-Type
更改為包含數據所在文件的 MIME 類型,並且Content-Disposition
是您希望它顯示為的文件名。
不確定這是否可行,我的只是讓瀏覽器彈出一個 PDF 下載,所以我不確定它是否適用於嵌入 CDN 文件......不過值得一試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.