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}";
}       
share
up vote 10 down vote accepted
+50

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";
}
share
    
Thanks Jack! However, it only saves as the title up until the first space. For example if $save_as='hello world'; the file would be saved as hello. Any way around this? – user784637 Sep 28 '12 at 4:42
    
@user784637 in that case you would want to consider adding double quotes around it, e.g. filename="hello world.txt" – Ja͢ck Sep 28 '12 at 4:47

Format of your Content-Disposition is invalid, Specify disposition-type.

Example: Content-Disposition: attachment; filename=test.mp3;

Use response-content-disposition in signature and params:

$disposition = "response-content-disposition=" . urlencode("attachment; filename={$filename}");
/* ... */
$string_to_sign .= "?{$disposition}";
/* ... */
$authentication_params.= "&{$disposition}";
share
    
I'm confused about where to make that change, can I do it in the above php script? What's the appropriate code? – user784637 Sep 24 '12 at 6:02
    
I've edited my answer. – b.b3rn4rd Sep 24 '12 at 6:21
    
Unfortunately when I try that I get a link to an .xml page with the following error The request signature we calculated does not match the signature you provided. Check your key and signing method. – user784637 Sep 24 '12 at 7:15
    
probably you forgot to add content-disposition in signature – b.b3rn4rd Sep 24 '12 at 11:27
    
Thanks bernard - I'll try this when I get back home – user784637 Sep 24 '12 at 15:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.