2009-05-15 35 views
13

Estoy tratando de usar http://code.google.com/p/amazon-s3-php-class/ para forzar-descargar archivos desde AWS S3. Tengo un mp3 que quiero que la gente "juegue" o "descargue". Por defecto, cuando accede al archivo directamente en s3, comienza a reproducirse en el navegador. Necesito agregar una opción para descargar realmente. Busqué en Google y encontré nada. Conceptualmente sé lo que debe suceder pero no sé cómo producirlo php. Sé que necesito modificar los encabezados a Content-Disposition: archivo adjunto. Cualquier ayuda sería muy apreciada.Force-Download con php en Amazon S3

Gracias, Michael

+0

http://stackoverflow.com/questions/2613792/amazon-s3-add-metadata- to-existing-key – andrewrk

Respuesta

10

Los scripts PHP que se han mencionado hasta ahora funciona bien, pero el principal inconveniente es que cada vez que un visitante en su sitio solicita un archivo, sus propios servidores lo cargarán desde el S3 y luego transmitirán esos datos al navegador. Para sitios de poco tráfico, probablemente no es un gran problema, pero para los de mucho tráfico, definitivamente desea evitar ejecutar todo a través de sus propios servidores.

Afortunadamente, hay una manera bastante directa de forzar la descarga de sus archivos desde el S3. Y está exactamente en lo cierto: solo desea establecer el tipo de contenido y la disposición del contenido (basta con configurar el contenido: la disposición funcionará en algunos navegadores, pero la configuración de ambos debería funcionar en todos los navegadores).

Este código está asumiendo que usted está utilizando la clase de Amazon S3 PHP desde lo no diseñado:

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

?> 

Ahora todos sus archivos se verán obligados a descargar. Es posible que deba borrar su caché para ver el cambio. Y obviamente, no hagas eso en ningún archivo que realmente quieras cargar "en línea" en el navegador.

Lo bueno de esta solución es que las aplicaciones que cargan archivos multimedia directamente (como, por ejemplo, un reproductor de mp3 en Flash) no se preocupan por el tipo de contenido o disposición de contenido, por lo que aún puede reproducir sus archivos en el navegador y luego el enlace para descargar ese mismo archivo. Si el usuario ya terminó de cargar el archivo en flash, lo más probable es que aún lo tenga en su caché, lo que significa que su descarga será súper rápida y que ni siquiera le costará ningún cargo adicional de ancho de banda del S3.

+1

eso es una desventaja bastante grande. No creo que considere esta pregunta respondida. – andrewrk

+1

Ver mi respuesta a continuación. Amazon ha lanzado una función que resuelve este problema. –

0

php que sólo tiene que descargar el archivo en el servidor, no en el cliente. recuerde, php no hace nada en el cliente, solo devuelve contenido (html, javascript, css, xml, lo que sea ...)

[editado: añadido para mayor claridad]: php puede servir contenido de audio, pero desea servir una página web y audio al mismo tiempo. Para obtener el comportamiento de ese cliente, debe hacer que el cliente solicite el archivo en función de html o javascript de la página web.

Así que tiene que hacer que el cliente descargue el archivo. Por ejemplo, tenga un iframe en la página con la url del archivo en s3. Use css para hacer que el iframe sea invisible. Debería mostrar la página y descargar y reproducir el mp3.

De lo contrario, analice el uso de Javascript para iniciar una descarga cuando se carga la página. No estoy seguro si eso es posible.

+0

Sí, es su derecho. Lo que estoy buscando como resultado final es tener un archivo, es decir, s3download.php, que pueda pasar el archivo para que se descargue. Entonces, por ejemplo, la descarga se vería así Download Cuando se llame al archivo, acceda a 'la cuenta s3, agrega los encabezados de disposición de contenido que hacen que el archivo comience a descargarse. ¿Tiene esto sentido? – michaelespinosa

+0

para s3download.php, sus pasos serían algo así como: -configuración de los valores del encabezado para el tipo de contenido como datos mp3 -descarga de s3 usando un curl, http-request o cualquiera que sea su método preferido, escribiendo a una temperatura archivo -leer el contenido del archivo y devolverlo al usuario No puedo poner todas las muestras en un comentario, pero si busca en Google muestras de cada uno de esos pasos, debe tener lo que necesita. –

-3

Nunca intenté el alojamiento S3 de Amazon, pero ¿no tienes acceso al uso de archivos .htaccess allí? Entonces se puede establecer Content-Type y Content-Disposition de un directorio completo con esta entrada:

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

No lo hice -1, pero la razón por la que la gente lo hizo es porque S3 no usa '.htaccess' – basarat

1

Así modificar mi ejemplo anterior que ser así


<?php 

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

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

exit(); 

?> 

Ahora tendrá que poner un poco de validación para que no le dé acceso al mundo a todos los archivos que coloca en S3, pero esto debería funcionar.

1

También vale la pena mencionar que puede establecer los encabezados de los archivos en S3. Por ejemplo, si necesita forzar la descarga de un determinado archivo, puede establecer los encabezados apropiados para ese archivo. Por ejemplo, la opción predeterminada para transmitir y tener un archivo secundario configurado para forzar la descarga o gastar el ancho de banda para usar php/fputs y forzar la descarga a través de PHP.

3

Sólo tiene que añadir esto a los metadatos del archivo en S3:

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

Solo queriendo publicar una contribución a esto, Alex Neth tiene razón en esta referencia, pero no creo que un enlace sea información suficiente, utilizando AWS PHP SDK2 de Amazon. A continuación, describí un método básico (no probado) para llamar a los datos de esta manera, puede usar el Método de fábrica S3 o el Creador de servicios de AWS para crear el Cliente 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'); 
?> 

Puede utilizar el encabezado de PHP ("Ubicación: $ url"); para redirigir al visitante al archivo MP3 con una descarga forzada, esto debería evitar que se reproduzca en el navegador. Tenga en cuenta que utilizo ResponseContentType con bastante frecuencia pero nunca he usado ResponseContentDisposition con AWS (debería funcionar de acuerdo con los documentos).)

conversión de esta muestra en una función debe ser fácil, incluso se podría pasar en balde $, $ key, $ force_download como tal

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

?> 

ADVERTENCIA, si no se ha dado cuenta, esto requiere que el AWS PHP SDK 2 actualmente (7 de abril de 2014) se encuentra aquí http://aws.amazon.com/sdkforphp/ Este código es en su mayoría pseudocódigo y puede requerir algunos ajustes adicionales para realmente hacer el trabajo, ya que estoy haciendo referencia a esto desde la memoria.

+0

esto no funciona. Intenté 'header ('Content-disposition: attachment; filename = s3112.png'); header ('Content-type: image/png'); header ("Ubicación: https://s3-ap-southeast-1.amazonaws.com/mytest.sample/s3112.png"); ' – urfusion

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

El código anterior funciona, sólo tiene que instalar la dependencia S3 compositor y enlace en el archivo de carga automática, ponga su clave/secreta en config y luego suministrar el cubo/nombre de archivo.

-1
<?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); 
0

Esto es ahora posible mediante el sobreescribiendo los encabezados S3 utilizando solicitudes firmadas.

parámetros de la petición

Hay momentos en que desea anular ciertos valores de encabezado de respuesta en una respuesta GET. Por ejemplo, puede anular el valor del encabezado de respuesta Content-Disposition en su solicitud GET.

Puede anular valores para un conjunto de encabezados de respuesta utilizando los parámetros de consulta enumerados en la siguiente tabla.

respuesta de tipo de contenido - Establece la cabecera Content-Type de la respuesta respuesta-content-disposition - Establece la cabecera Content-Disposición de la respuesta.

Nota

Debe firmar la solicitud, ya sea usando una cabecera de autorización o una URL previamente firmado, cuando se utilizan estos parámetros. No se pueden usar con una solicitud sin firma (anónima).

Por lo tanto, se debe establecer los encabezados de:

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

respuesta encontrado aquí: https://stackoverflow.com/a/5903710/922522