使用外部资源的URL在Laravel中下载文件

p4rjhz4m  于 2022-12-14  发布在  其他
关注(0)|答案(8)|浏览(147)

我把所有上传的文件保存在一个自定义的外部驱动器上。这些文件是通过自定义API存储的。
在Laravel 5.2中,我可以对本地文件执行以下操作以下载它:

return response()->download('path/to/file/image.jpg');

不幸的是,当我传递URL而不是路径时,Laravel会抛出一个错误:
文件https://my-cdn.com/files/image.jpg不存在
(the URL当然是一个哑元)。
有没有什么方法可以让我使用Laravel的实现下载image.jpg文件,或者我可以使用普通的PHP来下载?

g9icjywg

g9icjywg1#

这并不奇怪,您应该使用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);
b1uwtaje

b1uwtaje2#

TL;DR

如果您使用的是5.6或更高版本,请使用streamDownload响应。否则,请实现下面的函数。

原始答案

与“download”响应非常相似,Laravel有一个“stream”响应,可以用来实现这一点。看看API,这两个函数都是围绕Symfony的BinaryFileResponse和StreamedResponse类的 Package 器。在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年1月17日更新

现在它是merged into 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');
});
piah890a

piah890a3#

至于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);

有关磁盘配置和put方法的详细信息,请查找Laravel Storage Facade文档;有关使用HTTP响应返回文件的“使用文件下载响应”文档,请查找。

qco9c6ql

qco9c6ql4#

为什么不使用简单的重定向呢?

return \Redirect::to('https://my-cdn.com/files/image.jpg');
2ekbmq32

2ekbmq325#

请尝试以下脚本:

// $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);
ssgvzors

ssgvzors6#

对我来说,这里的一个关键是能够测试代码。使用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();
wyyhbhjk

wyyhbhjk7#

您可以使用download()方法使用浏览器提供要下载的文件

文件

  • https://laravel.com/docs/9.x/filesystem#downloading-files
  • https://laravel.com/docs/9.x/responses#file-downloads
    示例
return Storage::download('file.jpg');    
    return Storage::download('file.jpg', $name, $headers);
    // or
    return response()->download($pathToFile); 
    return response()->download($pathToFile, $name, $headers);
djmepvbi

djmepvbi8#

您可以下拉原始文件的内容,计算出其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文件...值得一试。

相关问题