Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to override content disposition header in s3

I'm using the following php function to give temporary access to the public for a private file.

function get_s3_signed_url($bucket, $resource, $AWS_S3_KEY, $AWS_s3_secret_key, $expire_seconds) {
    $expires = time()+$expire_seconds;
    // S3 Signed URL creation
    $string_to_sign = "GET\n\n\n{$expires}\n/".str_replace(".s3.amazonAWS.com","", $bucket)."/$resource";
    $signature = urlencode(base64_encode((hash_hmac("sha1", utf8_encode($string_to_sign), $AWS_s3_secret_key, TRUE))));

    $authentication_params = "AWSAccessKeyId=".$AWS_S3_KEY;
    $authentication_params.= "&Expires={$expires}";
    $authentication_params.= "&Signature={$signature}";

    return $link = "http://s3.amazonAWS.com/{$bucket}/{$resource}?{$authentication_params}";
}       

I wanted to add the content disposition header so I can change the filename to test.mp3 when a user tries to access this url which defaults the filename to 982jdjd2p3.mp3

$privateUrl = array('privateUrl' => get_s3_signed_url('testbucket', '982jdjd2p3.mp3', $my_aws_key, $my_aws_secret_key, 60));

I tried adding the following line of code to the function

$file_name = 'test.mp3';       
$authentication_params.= "&Content-Disposition={$file_name}";

However when I click on the url

http://s3.amazonAWS.com/testbucket/982jdjd2p3.mp3?AWSAccessKeyId=***&Expires=***&Signature=***&Content-Disposition=test.mp3

The proposed filename is to be saved as 982jdjd2p3.mp3

How do I override the content disposition header for s3 GET requests using this function?

See Also

Amazon S3 Change file download name

EDIT

Here is the most recent attempt to rename the file with a get request using this function.

function get_s3_signed_url($bucket, $resource, $AWS_S3_KEY, $AWS_s3_secret_key, $expire_seconds) {
    $expires = time()+$expire_seconds;
    // S3 Signed URL creation
    $filename='moot.mp3';
    $disposition = "response-content-disposition=" . urlencode("attachment; filename={$filename}");            

    $string_to_sign = "GET\n\n\n{$expires}\n/".str_replace(".s3.amazonAWS.com","", $bucket)."/$resource";
    $string_to_sign .= "?{$disposition}";
    $signature = urlencode(base64_encode((hash_hmac("sha1", utf8_encode($string_to_sign), $AWS_s3_secret_key, TRUE))));

    $authentication_params = "AWSAccessKeyId=".$AWS_S3_KEY;  
    $authentication_params.= "&Expires={$expires}";
    $authentication_params.= "&Signature={$signature}";
    $authentication_params.= "&{$disposition}";

    return $link = "http://s3.amazonAWS.com/{$bucket}/{$resource}?{$authentication_params}";
}       
like image 462
user784637 Avatar asked Sep 24 '12 02:09

user784637


People also ask

Does content disposition have a header?

In a regular HTTP response, the Content-Disposition response header is a header indicating if the content is expected to be displayed inline in the browser, that is, as a Web page or as part of a Web page, or as an attachment, that is downloaded and saved locally.

What is content disposition S3?

S3 provides multiple ways to set the Content-Disposition header of an object being downloaded, two of the main ways are: Set Content Disposition parameter on upload – works for new objects. Set response-content-disposition parameter in request – works for an existing object however requires a signed URL.

Is content disposition required?

Content-Disposition is an optional header and allows the sender to indicate a default archival disposition; a filename. The optional "filename" parameter provides for this. This header field definition is based almost verbatim on Experimental RFC 1806 by R.

How do you use content disposition inline?

Working of Content Disposition and Multipart : On using inline disposition, the multipart should be displayed normally and if any attachment sub-part is present, it requires user action. User action is required when attachment disposition is used as whole on multipart.


1 Answers

The problem with your function is that the header values should be encoded in the final hyperlink, but not for signing. The following function corrects that:

function get_s3_signed_url($bucket, $resource, $AWS_S3_KEY, $AWS_s3_secret_key, $expire_seconds, $save_as)
{
    $expires = time()+$expire_seconds;
    // S3 Signed URL creation
    $headers = array(
        'response-content-disposition' => 'attachment; filename=' . $save_as,
    );
    $resource = str_replace(array('%2F', '%2B'), array('/', '+'), rawurlencode($resource));

    $string_to_sign = "GET\n\n\n$expires\n/$bucket/$resource";
    $final_url = "http://s3.amazonaws.com/$bucket/$resource?";

    $append_char = '?';
    foreach ($headers as $header => $value) {
        $final_url .= $header . '=' . urlencode($value) . '&';
        $string_to_sign .= $append_char . $header . '=' . $value;
        $append_char = '&';
    }

    $signature = urlencode(base64_encode(hash_hmac('sha1', $string_to_sign, $AWS_s3_secret_key, true)));

    return $final_url . "AWSAccessKeyId=$AWS_S3_KEY&Expires=$expires&Signature=$signature";
}
like image 165
Ja͢ck Avatar answered Oct 13 '22 06:10

Ja͢ck