繁体   English   中英

在Amazon S3上用PHP强制下载

[英]Force-Download with php on Amazon S3

我正在尝试使用http://code.google.com/p/amazon-s3-php-class/从AWS S3强制下载文件。 我有一个MP3,希望人们“播放”或“下载”。 默认情况下,当您直接在s3上访问文件时,它开始在浏览器中播放。 我需要添加一个选项才能实际下载。 我用Google搜索,发现什么都没有。 我从概念上知道需要发生什么,但不知道如何生成php。 我知道我需要将标头修改为Content-Disposition:附件。 任何帮助将不胜感激。

谢谢迈克尔

亚马逊现在已经解决了这个问题,并允许在每个请求的基础上使用已签名的请求覆盖标头:

http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?RESTObjectGET.html

w00t!

到目前为止已经提到的php脚本可以正常工作,但是主要的缺点是,每次您网站上的访问者请求文件时,您自己的服务器都会从S3加载该文件,然后将该数据中继到浏览器。 对于低流量站点,这可能没什么大问题,但是对于高流量站点,您绝对要避免通过自己的服务器运行所有内容。

幸运的是,有一种相当简单的方法可以将文件设置为强制从S3下载。 而且您说得很对-您只想设置content-type和content-disposition(仅设置content-disposition将在某些浏览器中起作用,但是同时设置这两种设置在所有浏览器中都可以起作用)。

这段代码假设您正在使用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播放器)无需关心内容类型或内容处置,因此您仍然可以在浏览器中播放文件,然后链接以下载相同的文件。 如果用户已经完成了闪存文件的加载,他们很可能仍将其保存在缓存中,这意味着他们的下载将非常快捷,甚至不会从S3上花费您任何额外的带宽费用。

只是想发表对此的贡献,Alex Neth在此参考上是正确的,但是我不觉得使用亚马逊自己的AWS PHP SDK2的链接是足够的信息。 下面,我概述了一种以这种方式调用数据的基本(未调试)方法,您可以使用S3 Factory方法或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的标头(“ Location:$ url”); 为了通过强制下载将访问者重定向到MP3文件,这应防止它在浏览器中播放,请注意,我非常频繁地使用ResponseContentType,但我从未在AWS上使用过ResponseContentDisposition(它应根据文档工作)。

将此示例转换为函数应该很容易,您甚至可以像这样传递$ 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"));

?>

警告,如果您还没有弄清楚,这需要当前(2014年4月7日)在这里找到AWS PHP SDK 2 http://aws.amazon.com/sdkforphp/此代码主要是伪代码,可能需要进行一些其他调整实际使工作,因为我从内存中引用了这一点。

只需在s3上将其添加到文件的元数据中即可:

Content-Disposition: attachment; filename=FILENAME.EXT
Content-Type: application/octet-stream
<?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 composer依赖项并在自动加载文件中链接,将您的密钥/秘密放入配置,然后提供存储桶/文件名即可。

还值得一提的是,您可以在S3中硬设置文件头。 例如,如果您需要强制下载某个文件,则可以为该文件设置适当的标题。 例如默认为流式传输,或者将辅助文件设置为强制下载或花费带宽使用php / fputs并通过PHP强制下载。

所以修改我上面的例子是这样的


<?php

header('Content-Type: audio/mpeg');
header("Content-Disposition: attachment; filename={$_GET['file']};");

readfile("url to the file/{$_GET['file']}");

exit();

?>

现在,您将要在其中进行一些验证,以使您不会让世界访问您放在S3上的每个文件,但这应该可行。

如果您使用的是Tarzan AWS之类的库,则可以添加元标头,该标头将在检索文件时包含在Amazon中。 在此处签出update_object函数中的meta参数,例如: http ://tarzan-aws.com/docs/2.0/files/s3-class-php.html#AmazonS3.update_object

现在可以通过使用签名的请求覆盖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

在这里找到答案: https : //stackoverflow.com/a/5903710/922522

php只会将文件下载到服务器,而不是客户端。 记住,php在客户端上不做任何事情,它只返回内容(html,javascript,css,xml等)。

[编辑:为清楚起见添加]:php可以提供音频内容,但是您想同时提供网页和音频。 要获得该客户端的行为,您必须使客户端根据网页的html或javascript请求文件。

因此,您必须让客户端下载文件。 例如,在页面上放置一个iframe,并在s3上添加文件的网址。 使用CSS使iframe不可见。 它应该呈现页面并下载并播放mp3。

否则,请在页面加载时考虑使用javascript进行下载。 我不确定是否可行。

<?php
// PHP solution (for OP and others), works with public and private files
// Download url expires after 30 minutes (no experation after the download initiates, for large files)
// ***Forces client download***
$signed_url = $s3_client->getObjectUrl($s3_bucket_name, $s3_filename_key, '+30 minutes', array(
    'ResponseContentType' => 'application/octet-stream',
    'ResponseContentDisposition' => 'attachment; filename="your-file-name-here.mp4"'
));
redirect($signed_url);

我从未尝试过Amazon的S3托管,但是您不可以在那里使用.htaccess文件吗? 然后,您可以使用以下条目为整个目录设置Content-Type和Content-Disposition:

<IfModule mod_headers.c>
    <FilesMatch "\.(mp3)$">
            ForceType audio/mpeg
            Header set Content-Disposition attachment
    </FilesMatch>
</IfModule>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM