Принудительная загрузка с помощью php на Amazon S3

Я пытаюсь использовать http://code.google.com/p/amazon-s3-php-class/ для принудительной загрузки файлов с AWS S3. У меня есть mp3, который я хочу, чтобы люди «играли» или «скачивали». По умолчанию, когда вы открываете файл прямо на s3, он начинает воспроизводиться в браузере. Мне нужно добавить возможность загрузки. Я погуглил и обнаружил, что ничего не придумал. Я концептуально знаю, что должно произойти, но не знаю, как это сделать. Php. Я знаю, что мне нужно изменить заголовки на Content-Disposition: attachment. Любая помощь будет принята с благодарностью.

Спасибо Майкл


person michaelespinosa    schedule 15.05.2009    source источник
comment
stackoverflow.com/questions/2613792 /   -  person andrewrk    schedule 15.06.2010


Ответы (11)


Сценарии php, которые были упомянуты до сих пор, будут работать нормально, но основным недостатком является то, что каждый раз, когда посетитель на вашем сайте запрашивает файл, ваши собственные серверы загружают его с S3, а затем передают эти данные в браузер. Для сайтов с низким трафиком это, вероятно, не имеет большого значения, но для сайтов с высоким трафиком вам определенно следует избегать запуска всего через свои собственные серверы.

К счастью, есть довольно простой способ настроить принудительную загрузку файлов с S3. И вы совершенно правы - вы просто хотите установить content-type и content-disposition (просто установка content-disposition будет работать в некоторых браузерах, но установка обоих должна работать во всех браузерах).

В этом коде предполагается, что вы используете класс PHP Amazon S3 из Undesigned:

<?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"));

?>

Теперь все ваши файлы будут загружены принудительно. Возможно, вам придется очистить кеш, чтобы увидеть изменения. И, очевидно, не делайте этого ни с одним файлом, который вы действительно хотите загрузить «встроенным» в браузер.

Приятная часть этого решения заключается в том, что приложения, которые загружают медиафайлы напрямую (например, mp3-плеер во Flash), не заботятся о типе контента или его расположении, поэтому вы все равно можете воспроизводить свои файлы в браузере, а затем ссылка для загрузки того же файла. Если пользователь уже завершил загрузку файла во флэш-памяти, он, скорее всего, все еще будет иметь его в своем кеше, что означает, что их загрузка будет очень быстрой, и это даже не будет стоить вам дополнительных затрат на пропускную способность от S3.

person Ben    schedule 21.12.2009
comment
это довольно большой недостаток. Не думаю, что буду считать этот вопрос ответом. - person andrewrk; 15.06.2010
comment
Смотрите мой ответ ниже. Amazon выпустила функцию, решающую эту проблему. - person Alex Neth; 06.05.2011

Amazon решила эту проблему и позволяет заменять заголовки для каждого запроса подписанными запросами:

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

w00t!

person Alex Neth    schedule 05.05.2011

Просто добавьте это в метаданные вашего файла на s3:

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

Просто желая опубликовать свой вклад в это, Алекс Нет прав в этой ссылке, но я не считаю, что ссылка является достаточной информацией, используя собственный AWS PHP SDK2 от Amazon. Ниже я описал базовый (непроверенный) метод вызова данных таким образом, вы можете использовать либо фабричный метод S3, либо AWS Service Builder для создания клиента 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');
?>

Затем вы можете использовать заголовок PHP ("Location: $ url"); чтобы перенаправить посетителя к файлу MP3 с принудительной загрузкой, это должно помешать его воспроизведению в браузере. Обратите внимание: я довольно часто использую ResponseContentType, но никогда не использовал ResponseContentDisposition с AWS (он должен работать в соответствии с документами ).

Преобразование этого примера в функцию должно быть простым, вы даже можете передать $ 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"));

?>

ПРЕДУПРЕЖДЕНИЕ, если вы не догадались, для этого требуется AWS PHP SDK 2 в настоящее время (7 апреля 2014 г.), который можно найти здесь http://aws.amazon.com/sdkforphp/ Этот код в основном является псевдокодом и может потребовать некоторой дополнительной настройки, чтобы действительно работать, поскольку я ссылаюсь на это по памяти.

person Community    schedule 07.04.2014
comment
это не работает. Я пробовал 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"); - person urfusion; 02.11.2015

Так что измените мой пример выше, чтобы он был таким


<?php

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

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

exit();

?>

Теперь вы захотите поместить туда некоторую проверку, чтобы не предоставлять миру доступ к каждому файлу, который вы помещаете на S3, но это должно сработать.

person respectTheCode    schedule 21.05.2009

Если вы используете такую ​​библиотеку, как Tarzan AWS, вы можете добавить мета-заголовки, которые amazon будет включать, когда файл извлекается. Посмотрите здесь мета-параметр в функции update_object, например: http://tarzan-aws.com/docs/2.0/files/s3-class-php.html#AmazonS3.update_object

person Corey    schedule 03.06.2009

Также стоит упомянуть, что вы можете жестко установить заголовки для файлов в S3. Например, если вам нужно принудительно загрузить определенный файл, вы можете установить соответствующие заголовки для этого файла. Например, по умолчанию используется потоковая передача и либо установлен дополнительный файл для принудительной загрузки, либо используется пропускная способность для использования php / fputs и принудительной загрузки через PHP.

person Mahdi.Montgomery    schedule 08.09.2010

<?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 и ссылку в файле автозагрузки, поместить свой ключ / секрет в конфигурацию, а затем указать корзину / имя файла.

person user3715513    schedule 06.06.2014

php просто загрузит файл на сервер, а не на клиент. помните, php ничего не делает на клиенте, он просто возвращает контент (html, javascript, css, xml, что угодно ...)

[редактировать: добавлено для ясности]: php может обслуживать аудиоконтент, но вы хотите одновременно обслуживать веб-страницу и аудио. Чтобы получить такое поведение клиента, вы должны заставить его запрашивать файл на основе HTML или javascript веб-страницы.

Итак, вам нужно заставить клиента скачать файл. Например, разместите на странице iframe с URL-адресом файла на s3. Используйте css, чтобы сделать iframe невидимым. Он должен отобразить страницу, загрузить и воспроизвести mp3.

В противном случае попробуйте использовать javascript, чтобы ускорить загрузку при загрузке страницы. Я не уверен, возможно ли это.

person Tim Hoolihan    schedule 15.05.2009
comment
Да, ты прав. В качестве конечного результата я ищу файл, то есть s3download.php, в который я могу передать файл, который необходимо загрузить. Так, например, загрузка будет выглядеть так ‹a href=s3download.php?file=test.mp3› Download ‹/a› Когда файл называется, он получает доступ к учетной записи s3, добавляет заголовки размещения содержимого, вызывая файл начать скачивание. Имеет ли это смысл? - person michaelespinosa; 15.05.2009
comment
для s3download.php ваши шаги будут выглядеть примерно так: -установить значения заголовка для типа содержимого, чтобы быть данными mp3 -загрузить из s3 с помощью curl, http-запроса или любого другого предпочтительного метода, записать во временный файл -прочитать содержимое файла и вернуться к пользователю. Я не могу поместить все образцы в комментарий, но если вы погуглите образцы каждого из этих шагов, у вас должно быть то, что вам нужно. - person Tim Hoolihan; 16.05.2009

Теперь это возможно путем перезаписи заголовков S3 с помощью подписанных запросов.

Параметры запроса

Бывают случаи, когда вы хотите переопределить определенные значения заголовка ответа в ответе GET. Например, вы можете переопределить значение заголовка ответа Content-Disposition в своем запросе GET.

Вы можете переопределить значения для набора заголовков ответов, используя параметры запроса, перечисленные в следующей таблице.

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

person Justin    schedule 15.09.2017

Я никогда не пробовал использовать хостинг Amazon S3, но разве у вас нет доступа к использованию там файлов .htaccess? Затем вы можете установить Content-Type и Content-Disposition для всего каталога с помощью этой записи:

<IfModule mod_headers.c>
    <FilesMatch "\.(mp3)$">
            ForceType audio/mpeg
            Header set Content-Disposition attachment
    </FilesMatch>
</IfModule>
person Preben    schedule 20.05.2009
comment
Я не сделал -1, но люди это сделали потому, что S3 не использует .htaccess - person basarat; 06.06.2014