簡體   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