谢谢, Michael
谢谢, Michael
现在,亚马逊已经解决了这个问题,并允许使用签名请求的方式基于每个请求覆盖头信息:
http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?RESTObjectGET.html
太好了!
到目前为止提到的PHP脚本可以正常工作,但主要缺点是每当您网站上的访问者请求文件时,您自己的服务器将从S3加载该文件,然后将数据传输到浏览器。对于低流量站点,可能并不重要,但对于高流量站点,您肯定要避免通过自己的服务器运行所有内容。
幸运的是,有一种相当直接的方法可以设置您的文件强制从S3下载。并且您的想法很正确- 您只需要设置内容类型和内容规定(在某些浏览器中仅设置内容规定就可以工作,但在所有浏览器中设置两者都应该可以)。
此代码假设您正在使用来自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"));
?>
现在所有的文件都将被强制下载。您可能需要清除缓存才能看到更改。当然,不要对任何实际上需要在浏览器中"内联"加载的文件执行此操作。
该解决方案的好处是,直接加载媒体文件的应用程序(比如Flash中的MP3播放器)不关心内容类型或内容分发,因此您仍然可以在浏览器中播放文件,然后链接到下载同一文件。如果用户已经在Flash中完成了文件的加载,他们很可能仍然将其保存在缓存中,这意味着他们的下载将非常快,并且它甚至不会给您带来任何额外的S3带宽费用。
只需将此添加到您在S3上的文件元数据中:
Content-Disposition: attachment; filename=FILENAME.EXT
Content-Type: application/octet-stream
我想为这个贡献发表一些意见。Alex Neth在这方面是正确的,但我认为提供一个链接是不足够的信息。可以使用亚马逊自己的AWS PHP SDK2来调用数据。下面是一种基本的(未经测试的)方法,可以使用S3 Factory Method或AWS Service Builder来创建S3 Client。
<?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');
?>
<?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"));
?>
警告,如果你还没有想到,这需要目前(2014年4月7日)找到的AWS PHP SDK 2,网址在http://aws.amazon.com/sdkforphp/。这段代码大部分是伪代码,可能需要一些额外的调整才能实际工作,因为我是根据记忆引用的。
header('Content-disposition: attachment; filename=s3112.png');
header('Content-type: image/png');
header("Location: https://s3-ap-southeast-1.amazonaws.com/mytest.sample/s3112.png");
- urfusion所以将我的上面的例子修改成这样
<?php
header('Content-Type: audio/mpeg');
header("Content-Disposition: attachment; filename={$_GET['file']};");
readfile("url to the file/{$_GET['file']}");
exit();
?>
<?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";
通过使用签名请求覆盖S3头部现在是可行的。
请求参数
有时您想要在GET响应中覆盖某些响应头值。例如,您可能会在GET请求中覆盖Content-Disposition响应头值。
您可以使用以下表格中列出的查询参数覆盖一组响应头的值。
response-content-type - 设置响应的Content-Type头 response-content-disposition - 设置响应的Content-Disposition头。
注意
当使用这些参数时,您必须使用授权标头或预签名URL对请求进行签名。它们不能用于未签名(匿名)请求。
因此,您将设置这些头部:
response-content-disposition: attachment; filename=FILENAME.EXT
response-content-type: application/octet-stream
PHP 只会将文件下载到服务器,而不是客户端。请记住,PHP 在客户端上不执行任何操作,它只返回内容(HTML、JavaScript、CSS、XML 等等)。
[编辑:为了更清晰]: PHP 可以提供音频内容,但您想同时提供网页和音频。要获得该客户端行为,您必须让客户端基于网页的 HTML 或 JavaScript 请求文件。
因此,您必须让客户端下载文件。例如,在页面上放置一个具有 S3 文件 URL 的 iframe。使用 CSS 使 iframe 不可见。它应该呈现页面并下载和播放 MP3。
否则,请查看使用 JavaScript 在页面加载时启动下载。我不确定是否可能。