我将所有上传都保存在一个自定义的外部驱动器上。文件是通过自定义API存储的。
在Laravel 5.2中,我可以为本地文件下载它:
return response()->download('path/to/file/image.jpg');
不幸的是,当我传递URL而不是路径时,Laravel抛出了一个错误:
文件"https://my-cdn.com/files/image.jpg"不存在
(URL当然是一个伪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;DR
如果您使用的是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行代码上传到浏览器(如果需要(。
假设在你的服务器端(Laravel应用程序(,你想要一些远程文件(比如谷歌主页HTML(本地保存到你的服务器文件系统上。然后让你的客户端浏览器下载该文件:
// 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响应的文件的响应下载文档。
为什么不使用简单的重定向?
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()
方法的浏览器提供要下载的文件
文档:
- https://laravel.com/docs/9.x/filesystem#downloading-文件
- https://laravel.com/docs/9.x/responses#file-下载
示例:
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
更改为包含数据所在文件的mimetype,Content-Disposition
更改为您希望其显示为.的文件名
不确定这是否可行,我的只是用PDF下载弹出浏览器,所以我不确定它是否适用于嵌入CDN文件。。。不过值得一试。