在 Amazon S3 上使用 php 强制下载
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/870215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Force-Download with php on Amazon S3
提问by michaelespinosa
I am trying to use http://code.google.com/p/amazon-s3-php-class/to force-dowload files from AWS S3. I have an mp3 that I want people to "play" or "download." By default the when you access the file directly on s3 it begins to play in the browser. I need to add an option to actually download. I have Googled and found came up with nothing. I conceptually know what needs to happen but don't know how to produce it php. I know I need to modify the headers to Content-Disposition: attachment. Any help would be greatly appreciated.
我正在尝试使用http://code.google.com/p/amazon-s3-php-class/从 AWS S3 强制下载文件。我有一个 mp3,我想让人们“播放”或“下载”。默认情况下,当您直接在 s3 上访问文件时,它开始在浏览器中播放。我需要添加一个选项来实际下载。我用谷歌搜索,发现什么也没有。我从概念上知道需要发生什么,但不知道如何生成它 php。我知道我需要将标题修改为 Content-Disposition: 附件。任何帮助将不胜感激。
Thanks, Michael
谢谢,迈克尔
采纳答案by Ben
The php scripts that have been mentioned so far will work ok, but the main downside is that every time a visitor on your site requests a file, your own servers will load it from the S3 and then relay that data to the browser. For low traffic sites, it's probably not a big deal, but for high traffic ones, you definitely want to avoid running everything through your own servers.
到目前为止提到的 php 脚本可以正常工作,但主要的缺点是每次您站点上的访问者请求文件时,您自己的服务器都会从 S3 加载它,然后将该数据中继到浏览器。对于低流量站点,这可能没什么大不了的,但是对于高流量站点,您肯定希望避免通过自己的服务器运行所有内容。
Luckily, there's a fairly straight-forward way to set your files to be forced to download from the S3. And you're exactly right - you just want to set the content-type and content-disposition (just setting content-disposition will work in some browsers, but setting both should work in all browsers).
幸运的是,有一种相当直接的方法可以将您的文件设置为强制从 S3 下载。而且您完全正确 - 您只想设置 content-type 和 content-disposition (仅设置 content-disposition 将在某些浏览器中工作,但设置两者应该在所有浏览器中工作)。
This code is assuming that you're using the Amazon S3 PHP class from Undesigned:
此代码假设您使用的是 Undesigned 中的 Amazon S3 PHP 类:
<?php
// set S3 auth and get your bucket listing
// then loop through the bucket and copy each file over itself, replacing the "request headers":
S3::copyObject($bucketName, $filename, $bucketName, $filename, "public-read", array(), array("Content-Type" => "application/octet-stream", "Content-Disposition" => "attachment"));
?>
Now all your files will be forced to download. You may need to clear your cache to see the change. And obviously, don't do that on any file that you actually do want to be loaded "inline" in the browser.
现在您的所有文件都将被强制下载。您可能需要清除缓存才能看到更改。显然,不要对您确实希望在浏览器中“内联”加载的任何文件执行此操作。
The nice part with this solution is that applications that load media files directly (like let's say an mp3 player in Flash) don't care about the content-type or content-disposition, so you can still play your files in the browser and then link to download that same file. If the user already finished loading the file in flash, they'll most likely still have it in their cache, which means their download will be super quick and it won't even cost you any extra bandwidth charges from the S3.
此解决方案的好处在于,直接加载媒体文件的应用程序(例如 Flash 中的 mp3 播放器)不关心内容类型或内容配置,因此您仍然可以在浏览器中播放文件,然后下载相同文件的链接。如果用户已经在闪存中完成加载文件,他们很可能仍将其保存在缓存中,这意味着他们的下载速度将非常快,甚至不会花费您任何额外的 S3 带宽费用。
回答by Alex Neth
Amazon has now solved this problem and allows overriding of headers on a per-request basis with signed requests:
亚马逊现在已经解决了这个问题,并允许在每个请求的基础上使用签名请求覆盖标头:
http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?RESTObjectGET.html
http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?RESTObjectGET.html
w00t!
哇!
回答by Ran
Just add this to your file's metadata on s3:
只需将其添加到 s3 上的文件元数据中:
Content-Disposition: attachment; filename=FILENAME.EXT
Content-Type: application/octet-stream
回答by Destreyf
Just wanting to post a contribution to this, Alex Neth is correct on this reference, but i do not feel a link is sufficient information, using amazon's own AWS PHP SDK2. Below I've outlined a basic (untested) method for calling data this way, you can use either S3 Factory Method or AWS Service Builder to make the S3 Client.
只是想对此发表贡献,Alex Neth 在此参考文献中是正确的,但我认为使用亚马逊自己的 AWS PHP SDK2 的链接不足以提供足够的信息。下面我概述了一种以这种方式调用数据的基本(未经测试)方法,您可以使用 S3 工厂方法或 AWS Service Builder 来制作 S3 客户端。
<?php
// S3 Factory Method
/*use Aws\S3\S3Client;
$s3= S3Client::factory(array(
'key' => '<aws access key>',
'secret' => '<aws secret key>'
));*/
// OR AWS Service Builder
use Aws\Common\Aws;
// Create a service builder using a configuration file
$aws = Aws::factory('/path/to/my_config.json');
// Get the client from the builder by namespace
$s3 = $aws->get('S3');
// Now lets create our request object.
$command = $s3->getCommand('GetObject',array(
'Bucket' => 'your-bucket-name',
'Key' => 'keyname',
'ResponseContentType' => 'application/octet-stream',
'ResponseContentDisposition' => 'attachment; filename="filename.mp3',
));
$url = $command->createPresignedUrl('+1 days');
?>
You can then use PHP's header("Location: $url"); in order to redirect the visitor to the MP3 file with a force download, this should prevent it from playing in the browser, Please note, i use ResponseContentType quite frequently but I've never used ResponseContentDisposition with AWS (it should work according to the docs).
然后你可以使用 PHP 的 header("Location: $url"); 为了通过强制下载将访问者重定向到 MP3 文件,这应该会阻止它在浏览器中播放,请注意,我经常使用 ResponseContentType 但我从未在 AWS 中使用过 ResponseContentDisposition(它应该根据文档工作)。
Converting this sample into a function should be easy, you could even pass in $bucket, $key, $force_download as such
将此示例转换为函数应该很容易,您甚至可以像这样传入 $bucket、$key、$force_download
<?php
use Aws\Common\Aws;
function gen_url($bucket,$key,$force_download=false){
// OR AWS Service Builder (personal method to do this)
// Create a service builder using a configuration file
$aws = Aws::factory('/path/to/my_config.json');
// Get the client from the builder by namespace
$s3 = $aws->get('S3');
$params = array(
'Bucket' => $bucket,
'Key' => 'keyname',
'ResponseContentType' => 'application/octet-stream',
'ResponseContentDisposition' => 'attachment; filename="filename.mp3',
);
if($force_download){
$params['ResponseContentType'] = 'application/octet-stream';
$params['ResponseContentDisposition'] = 'attachment; filename="'.basename($key).'"';
}
$command = $s3->getCommand('GetObject',$params);
return $command->createPresignedUrl('+1 days');
}
// Location redirection to an MP3 force downlaod
header("Location: ".gen_url("recordings","my-file.mp3",true));
// Location redirection to a MP3 that lets the browser decide what to do.
header("Location: ".gen_url("recordings","my-file.mp3"));
?>
WARNING, if you haven't figured it out, this requires the AWS PHP SDK 2 currently (April 7th 2014) found here http://aws.amazon.com/sdkforphp/This code is mostly pseudo code and may require some additional tweaking to actually make work as i'm referencing this from memory.
警告,如果您还没有弄清楚,这需要 AWS PHP SDK 2 当前(2014 年 4 月 7 日)在此处找到http://aws.amazon.com/sdkforphp/此代码主要是伪代码,可能需要一些额外的调整实际开始工作,因为我正在从记忆中引用它。
回答by user3715513
<?php
require_once __DIR__.'/vendor/autoload.php';
use Aws\Common\Aws;
function gen_url($bucket,$key,$force_download=false){
// OR AWS Service Builder (personal method to do this)
$config = array(
'key' => '',
'secret' => '',
);
// Create a service builder using a configuration file
$aws = Aws::factory($config);
// Get the client from the builder by namespace
$s3 = $aws->get('S3');
$params = array(
'Bucket' => $bucket,
'Key' => $key,
'ResponseContentType' => 'application/octet-stream',
'ResponseContentDisposition' => 'attachment; filename="'.$key,
);
if($force_download){
$params['ResponseContentType'] = 'application/octet-stream';
$params['ResponseContentDisposition'] = 'attachment; filename="'.basename($key).'"';
}
$command = $s3->getCommand('GetObject',$params);
return $command->createPresignedUrl('+1 days');
}
$bucket = '';
$filename = '';
$url = gen_url($bucket,$filename,true);
echo "\n".$url."\n\n";
The code above works, you just need to install the S3 composer dependency and link in the autoload file, put your key/secret into config and then supply the bucket/filename.
上面的代码有效,您只需要在自动加载文件中安装 S3 composer 依赖项和链接,将您的密钥/秘密放入配置,然后提供存储桶/文件名。
回答by respectTheCode
So modify my example above to be like this
所以修改我上面的例子是这样的
<?php
header('Content-Type: audio/mpeg');
header("Content-Disposition: attachment; filename={$_GET['file']};");
readfile("url to the file/{$_GET['file']}");
exit();
?>
Now you will want to put some validation in there so that you not giving the world access to every file you put on S3, but this should work.
现在您需要在其中进行一些验证,这样您就不会让全世界访问您放在 S3 上的每个文件,但这应该可行。
回答by Corey
If you are using a library like Tarzan AWS, you can add meta headers, that amazon will include when the file is retrieved. Check out the meta parameter in the update_object function here, for example: http://tarzan-aws.com/docs/2.0/files/s3-class-php.html#AmazonS3.update_object
如果您使用的是Tarzan AWS 之类的库,则可以添加元标头,亚马逊将在检索文件时包含该标头。在此处查看 update_object 函数中的元参数,例如:http://tarzan-aws.com/docs/2.0/files/s3-class-php.html#AmazonS3.update_object
回答by Mahdi.Montgomery
Also worth mentioning is you are able to hard-set the headers for files in S3. For example, if you need to force-download a certain file you can set the appropriate headers for that file. Such as defaulting to stream, and either having a secondary file set to force-download or spend the bandwidth to use php/fputs and force-download via PHP.
另外值得一提的是,您可以在 S3 中硬设置文件的标头。例如,如果您需要强制下载某个文件,您可以为该文件设置适当的标题。例如默认为流式传输,或者将辅助文件设置为强制下载或花费带宽使用 php/fputs 并通过 PHP 强制下载。
回答by Justin
This is now possible by overwriting the S3 headers using signed requests.
现在可以通过使用签名请求覆盖 S3 标头来实现这一点。
Request Parameters
There are times when you want to override certain response header values in a GET response. For example, you might override the Content-Disposition response header value in your GET request.
You can override values for a set of response headers using the query parameters listed in the following table.
response-content-type- Sets the Content-Type header of the response response-content-disposition- Sets the Content-Disposition header of the response.
Note
You must sign the request, either using an Authorization header or a pre-signed URL, when using these parameters. They cannot be used with an unsigned (anonymous) request.
请求参数
有时您希望覆盖 GET 响应中的某些响应标头值。例如,您可以覆盖 GET 请求中的 Content-Disposition 响应标头值。
您可以使用下表中列出的查询参数覆盖一组响应标头的值。
response-content-type- 设置响应的 Content-Type 标头 response-content-disposition- 设置响应的 Content-Disposition 标头。
笔记
使用这些参数时,您必须使用 Authorization 标头或预签名 URL 对请求进行签名。它们不能与未签名(匿名)请求一起使用。
So, you would set those headers to:
因此,您可以将这些标头设置为:
response-content-disposition: attachment; filename=FILENAME.EXT
response-content-type: application/octet-stream
Found answer here: https://stackoverflow.com/a/5903710/922522
回答by Tim Hoolihan
php would just download the file to the server, not the client. remember, php doesn't do anything on the client, it just returns content (html, javascript, css, xml, whatever...)
php 只会将文件下载到服务器,而不是客户端。请记住,php 不会在客户端上执行任何操作,它只返回内容(html、javascript、css、xml 等等……)
[edit: added for clarity]: php can serve audio content, but you want to serve a web page and audio at the same time. To get that client behaviour, you have to get the client to request the file based on the web page's html or javascript.
[编辑:为清晰起见添加]:php 可以提供音频内容,但您希望同时提供网页和音频。要获得该客户端行为,您必须让客户端根据网页的 html 或 javascript 请求文件。
So you have to get the client to download the file. For instance, have an iframe on the page with the url of the file on s3. Use css to make the iframe invisible. It should render the page and download and play the mp3.
所以你必须让客户端下载文件。例如,在页面上有一个 iframe,其中包含 s3 上文件的 url。使用 css 使 iframe 不可见。它应该呈现页面并下载和播放 mp3。
Otherwise, look into using javascript to kick of a download when the page loads. I'm not sure if that's possible.
否则,请考虑在页面加载时使用 javascript 来启动下载。我不确定这是否可能。

