Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In php, I want to download an s3 file to the browser without storing it on my server

I've got files on Amazon's S3. They are named with a unique ID so there are no duplicates. I am accessing them using an authorized URL. I need to be able to pass them through to the browser, but I need to rename them. Right now I'm using fopen, but it is downloading the file to my server before serving the file to the browser. How can I have the files 'pass through' my server to the browser? Or how do I buffer the download - downloading a small chunk to my server and pass that to the browser while downloading the next chunk?

Also - I would really like to use CloudFront but they don't offer authenticated URLs. I believe I can use CURL to send credentials for the request - can I do this sort of 'pass through' file serving with CURL?

Thanks!

like image 677
Corey Avatar asked Apr 21 '09 13:04

Corey


1 Answers

I'm not familiar with how S3 works, so I don't know if this solution is possible. But couldn't you simply redirect the user's browser to the file? If I understand correctly, S3 allows you to create web URLs for any of the files in your bucket. So if, say, these are paid downloads, then you could have S3 generate a temporary URL for that download and then remove that once the user has downloaded it.

If that is not an option, you can try these PHP Classes:

  • HTTP protocol client - A class that implements requests to HTTP resources (used by the below stream wrapper). Allows requests to be streamed.
  • gHttp - An HTTP stream wrapper that lets you treat remote HTTP resources as files, using functions like fopen(), fread(), etc.
  • Amazon S3 Stream Wrapper - An Amazon S3 stream wrapper by the same developer as gHttp. Also allows remote resources to be accessed like ordinary files via fopen('s3://...').

Edit:

This page has the info on how to "pre-authenticate" a request by encoding the authentication key in the URL. It's under the section titled: Query String Request Authentication Alternative.

// I'm only implementing the parts required for GET requests.
// POST uploads will require additional components.
function getStringToSign($req, $expires, $uri) {
   return "$req\n\n\n$expires\n$uri";
}

function encodeSignature($sig, $key) {
    $sig = utf8_encode($sig);
    $sig = hash_hmac('sha1', $sig, $key);
    $sig = base64_encode($sig);
    return urlencode($sig);
}

$expires = strtotime('+1 hour');
$stringToSign = getStringToSign('GET', $expires, $uri);
$signature = encodeSignature($stringToSign, $awsKey);

$url .= '?AWSAccessKeyId='.$awsKeyId
       .'&Expires='.$expires
       .'&Signature='.$signature;

Then just redirect the user to $url, and they should be able to download the file. The signature is encoded by a one-way encryption scheme (sha1), so there's no risk of your AWS Secret Access Key being uncovered.

like image 134
Calvin Avatar answered Sep 22 '22 20:09

Calvin