Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Zip and download files from Amazon s3 with php

I'm creating my first web application using php hosted on Amazon Elastic Beanstalk, and I'm a little in over my head with what to do. My task is to reach out to files specified by an end customer in an AWS S3 cloud, zip them up, and finally provide a download link to the resulting zip file. I've done a lot of hunting around to find an instance of what exactly I'm trying to do, but my inexperience with php has been a hinderince in determining if a certain solution would work for me.

I found this question and response here, and seeing that it seems to address php and zip downloads in a general sense, I thought I might be able to adapt it to my needs. Below is what I have in php:

<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);

require "./aws.phar";
use Aws\S3\S3Client;

$client = S3Client::factory(array(
    'key'    => getenv("AWS_ACCESS_KEY_ID"),
    'secret' => getenv("AWS_SECRET_KEY")
));

echo "Starting zip test";

$client->registerStreamWrapper();

// make sure to send all headers first
// Content-Type is the most important one (probably)
//
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="file.zip"');

// use popen to execute a unix command pipeline
// and grab the stdout as a php stream
// (you can use proc_open instead if you need to 
// control the input of the pipeline too)
//
$fp = popen('zip -r - s3://myBucket/test.txt s3://myBucket/img.png', 'r');

// pick a bufsize that makes you happy (8192 has been suggested).
$bufsize = 8192;
$buff = '';
while( !feof($fp) ) {
   $buff = fread($fp, $bufsize);
   echo $buff;
}
pclose($fp);

And here is what I'm using to call it:

$(document).ready(function() {
    $("#download_button").click(function() {
        $.get("../php/ZipAndDownload.php", function(data){alert(data)});
        return false;
    });
});

I've also tried:

$(document).ready(function() {
        $("#download_button").click(function() {
            $.ajax({
                url:url,
                type:"GET",
                complete: function (response) {
                    $('#output').html(response.responseText);
                },
                error: function () {
                    $('#output').html('Bummer: there was an error!');
                }
            });
            return false;
        });
    });

Now whenever I click the download button, I get an echo of "Starting zip test" and nothing else. No errors, and no zip file. What do I need to know or what am I doing obviously wrong?

Thank you in advance for your help and advice.

EDIT: Here's what I have after some advice from Derek. This still produces a big nasty string of binary.

<?php
header('Content-Type: application/octet-stream');
header('Content-disposition: attachment; filename="file.zip"');

require "./aws.phar";
use Aws\S3\S3Client;

$bucket = 'myBucket';

$client = S3Client::factory(array(
    'key'    => getenv('AWS_ACCESS_KEY_ID'),
    'secret' => getenv('AWS_SECRET_KEY')
));

$result = $client->getObject(array(
    'Bucket' => $bucket,
    'Key'    => 'test.txt',
    'SaveAs' => '/tmp/test.txt'
));

$Uri = $result['Body']->getUri();

$fp = popen('zip -r - '.$Uri, 'r');

$bufsize = 8192;
$buff = '';
while( !feof($fp) ) {
   $buff = fread($fp, $bufsize);
   echo $buff;
}
pclose($fp);
?>
like image 584
KDhyne Avatar asked Sep 29 '22 17:09

KDhyne


1 Answers

Marc B's comment is correct. The call to zip does not know what s3:// means.

You will need to download the file from S3, then zip it locally. You have several options for downloading the file from S3. For example, you could use:

$client->getObjectUrl($bucket, $key) 

to get a URL for your object, then use cUrl or wget to download from that URL, depending on your permissions settings.

Once you have the file locally, update your zip command using the location where you saved the file in order to generate the .zip file.

like image 87
Derek Kurth Avatar answered Oct 23 '22 20:10

Derek Kurth