簡體   English   中英

使用指向外部資源的 URL 在 Laravel 中下載文件

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM