【问题标题】:PHP Force Download of Remote FilePHP 强制下载远程文件
【发布时间】:2010-12-03 15:08:54
【问题描述】:

我的 Amazon S3 存储上存储了一堆视频。我正在创建一个 PHP 脚本,与 here 非常相似,用户可以将视频下载到他们的硬盘上。

我想用这样的东西:

<?php
$file_name = $_GET['file'];
$file_url = 'http://www.myamazons3.com/' . $file_name;
header('Content-Type: application/octet-stream');
header("Content-Transfer-Encoding: Binary"); 
header("Content-disposition: attachment; filename=\"".$file_name."\""); 
readfile($file_url);
exit;

但是,我的印象是这会增加带宽,因为视频将通过我的服务器传输。

关于如何强制下载这些视频,同时避免先通过我自己的服务器阅读的任何想法?

非常感谢!

【问题讨论】:

  • 如果您使用 php 来执行此操作(即服务器端脚本),您的服务器必须中继文件。检查 api 的客户端实现(即 javascript)。

标签: php download amazon-s3


【解决方案1】:

查看 S3 API 文档,并注意您可以设置的标头值。亚马逊将在请求文件时发送这些:http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html(可以使用 POST 发送相同的参数以更新现有对象)

【讨论】:

    【解决方案2】:

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

    幸运的是,有一种相当直接的方法可以将您的文件设置为强制从 S3 下载。您只想设置 content-type 和 content-disposition(仅设置 content-disposition 将在某些浏览器中工作,但同时设置应在所有浏览器中工作)。

    此代码假设您使用的是来自 Undesign 的 Amazon S3 PHP 类:

    "application/octet-stream", "Content-Disposition" => "attachment")); ?>

    现在您的所有文件都将被强制下载。您可能需要清除缓存才能看到更改。显然,不要对您确实希望在浏览器中“内联”加载的任何文件执行此操作。

    这个解决方案的好处在于,直接加载媒体文件的应用程序(比如 Flash 中的 mp3 播放器)并不关心内容类型或内容配置,因此您仍然可以在浏览器,然后链接以下载相同的文件。如果用户已经在闪存中完成了文件的加载,他们很可能仍会将其保存在缓存中,这意味着他们的下载速度将非常快,甚至不会从 S3 中花费任何额外的带宽费用。

    【讨论】:

      【解决方案3】:
      header('Location: ' . $file_url);
      

      【讨论】:

      • 这是一种重定向请求的方法,但是他在'Location'之前输出的所有标头都没有意义,因为在位置标头之后正在生成一个与前一个无关的新HTTP请求(因为 HTTP 是一种无状态协议)。
      • 当您将文件放入 S3 时,您会告诉它内容类型,它会自行进行传输编码,并且会完全按原样使用文件名,因此可以正常工作。如果您的文件未在 S3 上公开,那么您需要生成安全的、有时间限制的 URL(S3 文档对此进行了详细说明...),然后重定向到该 URL。
      • 因此,目前,当我在 S3 中打开其中一个 MP4 时(无论如何在 Firefox 中),它会嵌入 MP4 并开始播放。我需要调用什么内容类型,我该怎么做?
      【解决方案4】:

      我知道这是一个旧线程,但在过去一年中,S3 团队增加了对 request parameters 的支持,它允许您根据请求覆盖某些 HTTP 标头。

      例如,您可以将 SVG 图像上传为 image/svg+xml,然后在检索为 application/octet-stream 时覆盖标题以强制下载。

      使用AWS SDK for PHP,可以使用Aws\S3\S3Client::createPresignedUrl()方法来实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多