Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save the-evgenii/16c672d7154e0ba158c9ac99fcb121b0 to your computer and use it in GitHub Desktop.
Save the-evgenii/16c672d7154e0ba158c9ac99fcb121b0 to your computer and use it in GitHub Desktop.
AWS S3: Pre-sign Upload & Download Requests [PHP]
<?php
function AWS_S3_PresignDownload($AWSAccessKeyId, $AWSSecretAccessKey, $BucketName, $AWSRegion, $canonical_uri, $expires = 8400) {
// Creates a signed download link for an AWS S3 file
// Based on https://gist.github.com/kelvinmo/d78be66c4f36415a6b80
$encoded_uri = str_replace('%2F', '/', rawurlencode($canonical_uri));
// Specify the hostname for the S3 endpoint
if($AWSRegion == 'us-east-1') {
$hostname = trim($BucketName .".s3.amazonaws.com");
$header_string = "host:" . $hostname . "\n";
$signed_headers_string = "host";
} else {
$hostname = trim($BucketName . ".s3-" . $AWSRegion . ".amazonaws.com");
$header_string = "host:" . $hostname . "\n";
$signed_headers_string = "host";
}
$date_text = gmdate('Ymd', time());
$time_text = $date_text . 'T000000Z';
$algorithm = 'AWS4-HMAC-SHA256';
$scope = $date_text . "/" . $AWSRegion . "/s3/aws4_request";
$x_amz_params = array(
'X-Amz-Algorithm' => $algorithm,
'X-Amz-Credential' => $AWSAccessKeyId . '/' . $scope,
'X-Amz-Date' => $time_text,
'X-Amz-SignedHeaders' => $signed_headers_string
);
if ($expires > 0) {
// 'Expires' is the number of seconds until the request becomes invalid
$x_amz_params['X-Amz-Expires'] = $expires;
}
ksort($x_amz_params);
$query_string = "";
foreach ($x_amz_params as $key => $value) {
$query_string .= rawurlencode($key) . '=' . rawurlencode($value) . "&";
}
$query_string = substr($query_string, 0, -1);
$canonical_request = "GET\n" . $encoded_uri . "\n" . $query_string . "\n" . $header_string . "\n" . $signed_headers_string . "\nUNSIGNED-PAYLOAD";
$string_to_sign = $algorithm . "\n" . $time_text . "\n" . $scope . "\n" . hash('sha256', $canonical_request, false);
$signing_key = hash_hmac('sha256', 'aws4_request', hash_hmac('sha256', 's3', hash_hmac('sha256', $AWSRegion, hash_hmac('sha256', $date_text, 'AWS4' . $AWSSecretAccessKey, true), true), true), true);
$signature = hash_hmac('sha256', $string_to_sign, $signing_key);
return 'https://' . $hostname . $encoded_uri . '?' . $query_string . '&X-Amz-Signature=' . $signature;
}
?>
<?php
function AWS_S3_hmac_sha256($key, $msg, $binary = true) {
return hash_hmac("sha256", $msg, $key, $binary);
}
function AWS_S3_PresignUpload($BucketName, $AWSAccessKeyId, $AWSSecretAccessKey, $AWSRegion, $UploadFilenameStartsWith) {
/* Function to presign an AWS S3 file upload.
This method of uploading can allow clients to securely upload files
directly to S3, while ensuring certian conditions are enforced (e.g. upload filename)
Written by Anthony Eden http://mediarealm.com.au/
*/
$AWSService = "s3";
$AWSRequest = "aws4_request";
$date = date("Ymd");
$AWSPolicy = '{ "expiration": "'.gmdate("Y-m-d", strtotime("tomorrow")).'T12:00:00.000Z",
"conditions": [
{"bucket": "'.$BucketName.'"},
["starts-with", "$key", "'.$UploadFilenameStartsWith.'"],
{"x-amz-server-side-encryption": "AES256"},
{"x-amz-credential": "'.$AWSAccessKeyId.'/'.$date.'/'.$AWSRegion.'/'.$AWSService.'/'.$AWSRequest.'"},
{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
{"x-amz-date": "'.$date.'T000000Z" }
]
}';
$StringToSign = base64_encode($AWSPolicy);
$DateKey = AWS_S3_hmac_sha256("AWS4" . $AWSSecretAccessKey, $date);
$DateRegionKey = AWS_S3_hmac_sha256($DateKey, $AWSRegion);
$DateRegionServiceKey = AWS_S3_hmac_sha256($DateRegionKey, $AWSService);
$SigningKey = AWS_S3_hmac_sha256($DateRegionServiceKey, $AWSRequest);
$Signature = AWS_S3_hmac_sha256($SigningKey, $StringToSign, false);
return array(
"BucketName" => $BucketName,
"KeyPrefix" => $UploadFilenameStartsWith,
"x-amz-server-side-encryption" => "AES256",
"X-Amz-Credential" => $AWSAccessKeyId.'/'.$date.'/'.$AWSRegion.'/'.$AWSService.'/'.$AWSRequest,
"X-Amz-Algorithm" => "AWS4-HMAC-SHA256",
"X-Amz-Date" => $date.'T000000Z',
"Policy" => $StringToSign,
"X-Amz-Signature" => $Signature
);
}
?>
import os
import requests
def uploadS3(srcFilename, S3Upload):
# This method uploads a file to a S3 bucket using pre-signed credentials
# S3Upload is a dictionary returned by AWS_S3_Presign_Upload.php
# Determine the extension of the original file
filename, file_extension = os.path.splitext(srcFilename)
# Perform the upload
r = requests.post(
'http://' + S3Upload['BucketName'] + '.s3.amazonaws.com/',
files = {
'file': open(srcFilename, 'rb')
},
data = {
"key": S3Upload['KeyPrefix'] + file_extension,
"x-amz-server-side-encryption": S3Upload['x-amz-server-side-encryption'],
"X-Amz-Algorithm": S3Upload['X-Amz-Algorithm'],
"X-Amz-Credential": S3Upload['X-Amz-Credential'],
"X-Amz-Date": S3Upload['X-Amz-Date'],
"Policy": S3Upload['Policy'],
"X-Amz-Signature": S3Upload['X-Amz-Signature']
}
)
if r.status_code == 200 or r.status_code == 204:
# Success!
return True
else:
# Debug output
print "ERROR: Cannot upload file to S3", srcFilename
print r.status_code, r.reason
print r.text
return False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment