Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在AmazonS3上使用php强制下载_Php_Download_Amazon S3 - Fatal编程技术网

在AmazonS3上使用php强制下载

在AmazonS3上使用php强制下载,php,download,amazon-s3,Php,Download,Amazon S3,我试图使用强制从AWS S3下载文件。我有一个mp3,我希望人们“播放”或“下载”。默认情况下,当您直接在s3上访问该文件时,它开始在浏览器中播放。我需要添加一个选项来实际下载。我在谷歌上搜索了一下,发现什么也没找到。我在概念上知道需要发生什么,但不知道如何生成它。我知道我需要将标题修改为内容处置:附件。任何帮助都将不胜感激 谢谢, Michaelphp只会将文件下载到服务器,而不是客户端。记住,php在客户机上不做任何事情,它只返回内容(html、javascript、css、xml等等) [

我试图使用强制从AWS S3下载文件。我有一个mp3,我希望人们“播放”或“下载”。默认情况下,当您直接在s3上访问该文件时,它开始在浏览器中播放。我需要添加一个选项来实际下载。我在谷歌上搜索了一下,发现什么也没找到。我在概念上知道需要发生什么,但不知道如何生成它。我知道我需要将标题修改为内容处置:附件。任何帮助都将不胜感激

谢谢,
Michael

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

[编辑:为清晰起见添加]:php可以提供音频内容,但您希望同时提供网页和音频。要获得该客户端行为,必须让客户端基于网页的html或javascript请求文件

所以你必须让客户端下载文件。例如,在页面上有一个iframe,其中包含s3上文件的url。使用css使iframe不可见。它应该呈现页面,下载并播放mp3


否则,请考虑在页面加载时使用javascript启动下载。我不确定这是否可能

我从未尝试过Amazon的S3托管,但是你没有权限使用那里的.htaccess文件吗?然后,您可以使用以下条目设置整个目录的内容类型和内容处置:

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

ForceType音频/mpeg
标题集内容处置附件

所以将我上面的示例修改为这样


<?php

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

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

exit();

?>


如果您使用的是类似的库,那么可以添加元数据头,amazon在检索文件时会包含这些头。在此处查看update_object函数中的元参数,例如:

到目前为止提到的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中硬设置文件头。例如,如果需要强制下载某个文件,可以为该文件设置适当的标题。例如,默认为流,或者将辅助文件设置为强制下载,或者花费带宽使用php/fputs并通过php强制下载。

只需将此添加到s3上的文件元数据中:

Content-Disposition: attachment; filename=FILENAME.EXT
Content-Type: application/octet-stream

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


w00t

Alex Neth只是想发表一篇文章,在这篇参考文章中是正确的,但我觉得使用亚马逊自己的AWS PHP SDK2链接是不够的。下面我概述了一个基本的(未测试的)数据调用方法,通过这种方式,您可以使用S3工厂方法或AWS服务生成器来创建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');
?>

现在可以使用签名请求覆盖S3头

请求参数

有时您希望覆盖GET响应中的某些响应头值。例如,您可以覆盖GET请求中的内容处置响应头值

可以使用下表中列出的查询参数覆盖一组响应标头的值

响应内容类型-设置响应的内容类型标题 响应内容处置-设置响应的内容处置标题

注意

使用这些参数时,必须使用授权标头或预签名URL对请求进行签名。它们不能用于未签名(匿名)请求

因此,您可以将这些标题设置为:

response-content-disposition: attachment; filename=FILENAME.EXT
response-content-type: application/octet-stream

在这里找到答案:

是的,你的权利。我想要的最终结果是有一个文件,即s3download.php,我可以将该文件传递给需要下载的文件。例如,当文件名为“it access”时,下载看起来是这样的。s3帐户添加了内容处置头,导致文件开始下载。这有意义吗?对于s3download.php,您的步骤如下:-将内容类型的标题值设置为mp3数据-使用curl、http请求或任何您喜欢的方法从s3下载,写入临时文件-读取文件内容并返回给用户我无法将所有示例放入注释中,但如果你在谷歌上搜索每一个步骤的样本,你应该有你需要的。这是一个很大的缺点。我不知道
<?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";
<?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);
response-content-disposition: attachment; filename=FILENAME.EXT
response-content-type: application/octet-stream