File Streaming with PHP and Amazon’s A3 Service

For one of our clients we’ve been tasked with adapting their current file store system from hard-drive-based to utilizing Amazon’s A3 system. One of the issues we encountered was the ability to provide authenticated access to certain files quickly and seemlessly. We needed to run authorization on our end and then somehow stream files to the user’s computer without leaving the files publicly-accessible on the A3 servers. This meant that we couldn’t use header redirects to stream data. We also couldn’t run a regular request using PEAR HTTP_Request, as that would have meant waiting for the the file to first download to the server, and then to be output to the user.

There were really two options for accomplishing this. The first was to use stream_get_contents(). This was an impossibility, however, as the client wasn’t running PHP5 on their server.

Mission Data has a really cool article on how to stream content to S3 for file uploads, it has the potential to be quite an elegant solution for downloads as well. Adapting their code for downloads was a snap:


/**
* getObjectStream -- Streams data to the output buffer.
*
* Takes ($objectname, $bucketname)
*
*
* - [str] $objectname: the object to be requested
* - [str] $bucketname: the bucket the object is found in
*/
function getObjectStream($objectname, $bucketname = NULL, $streamFunction) {
if ($bucketname == NULL) {
$bucketname = $this->bucketname;
}

$resource = urlencode("$bucketname/$objectname");

$httpDate = gmdate("D, d M Y G:i:s T");

$curl_inst = curl_init();

curl_setopt ($curl_inst, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt ($curl_inst, CURLOPT_LOW_SPEED_LIMIT, 1);
curl_setopt ($curl_inst, CURLOPT_LOW_SPEED_TIME, 180);
curl_setopt ($curl_inst, CURLOPT_NOSIGNAL, 1);
curl_setopt ($curl_inst, CURLOPT_HEADER, 0);
curl_setopt ($curl_inst, CURLOPT_WRITEFUNCTION, $streamFunction);
curl_setopt ($curl_inst, CURLOPT_URL, $this->serviceUrl . $resource);

$header[] = "Date: $httpDate";

$stringToSign = "GET\n\n\n$httpDate\n/$resource";

$signature = $this->constructSig($stringToSign);

$header[] = "Authorization: AWS $this->accessKeyId:$signature";

curl_setopt($curl_inst, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl_inst, CURLOPT_RETURNTRANSFER, 0);

$result = curl_exec ($curl_inst);

$this->responseString = $result;
$this->responseCode = curl_getinfo($curl_inst, CURLINFO_HTTP_CODE);

curl_close($curl_inst);
}

function curlResponseCallback($curl_inst, $str) {
echo $str;
return strlen($str);
}

Though the callback function does little more than output the cURL return transfer to the screen (we’re simply reading files here), it can be adapted for any purpose. The function can be called like this:


function s3StreamFile($objectname, $bucketname = null) {
return $this->S3->getObjectStream($objectname, $bucketname, array(&$this->S3, 'curlResponseCallback'));
}

You should be able to plug that into your PHP S3 library from Amazon and start streaming away.

Tags:
Bookmark: Post to Del.icio.us Post to Digg Post to Google Post to Ma.gnolia Post to MyWeb Post to Newsvine Post to Reddit Post to Simpy Post to Slashdot Post to Technorati

Leave a Reply