Skip to content

Instantly share code, notes, and snippets.

@mmoehrlein
Created March 8, 2017 12:10
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mmoehrlein/c1d9a8500ecc6fd10ab00c2ef2971740 to your computer and use it in GitHub Desktop.
Save mmoehrlein/c1d9a8500ecc6fd10ab00c2ef2971740 to your computer and use it in GitHub Desktop.
s3 upload with dropzone.js
<?php
// AWS data
$bucketName = "BUCKET-NAME";
$AWSAccessKeyId = "XXXXXXXXXXXXXXXXXXXX";
$AWSSecretAccessKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$date = date("Y-m-d");
$dateISO = date("Ymd");
$validTill = date('Y-m-d\TH:i:s.000\Z', time() + (60 * 60 * 4)); // 4 hours
$alg = "sha256";
$region = "REGION";
$service = "s3";
// syntax: hash_hmac(algorithm, string, key, binaryOutput)
$kSecret = 'AWS4' . $AWSSecretAccessKey;
$kDate = hash_hmac($alg, $dateISO, $kSecret, true);
$kRegion = hash_hmac($alg, $region, $kDate, true);
$kService = hash_hmac($alg, $service, $kRegion, true);
$secretSignatureKey = hash_hmac($alg, 'aws4_request', $kService, true);
// user specific data
$IdOne = "1";
$IdTwo = "1234";
$keyPrefix = "new/" . $IdOne . "/" . $IdTwo . "/" . date("Y-m-d_H-i-s_");
$keyFilename = '${filename}';
// fields to be used within form
$url = "https://" . $bucketName . ".s3.amazonaws.com/";
$key = $keyPrefix . $keyFilename;
$acl = "private";
$success_action_redirect = "";
$ContentType = "image/jpeg"; // can be empty, if there shouldn't be any restrictions
$amzMetaTag = ""; // optional tags
$maxFilesize = 1048576; // 1 MB
$policy = '{
"expiration": "' . $validTill . '",
"conditions": [
{"bucket": "' . $bucketName . '"},
["starts-with", "$key", "' . $keyPrefix . '"],
{"acl": "' . $acl . '"},
{"success_action_redirect": "' . $success_action_redirect . '"},
["starts-with", "$Content-Type", "' . $ContentType . '"],
["content-length-range", 0, ' . $maxFilesize . '],
{"x-amz-server-side-encryption": "AES256"},
["starts-with", "$x-amz-meta-tag", "' . $amzMetaTag . '"],
{"x-amz-credential": "' . $AWSAccessKeyId . '/' . $dateISO . '/us-east-2/s3/aws4_request"},
{"x-amz-algorithm": "AWS4-HMAC-SHA256"},
{"x-amz-date": "' . $dateISO . 'T000000Z" }
]
}';
$policyBase64 = base64_encode($policy);
$signature = hash_hmac($alg, $policyBase64, $secretSignatureKey);
?>
<html>
<head>
<title>S3 Dropzone</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="https://rawgit.com/enyo/dropzone/master/dist/dropzone.css">
<script src="https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"></script>
</head>
<body>
<br><br><br>
<h1 style="text-align: center">ImageUpload to "<?=$bucketName?>" - S3Bucket</h1>
<div id="test" class="dropzone dz-clickable"></div>
<script type="text/javascript">
Dropzone.options.test = {
url: "<?= $url ?>",
method: "post",
uploadMultiple: false,
sending: function (file, xhr, data) {
data.append("key", "<?= $key ?>");
data.append("acl", "<?= $acl ?>");
data.append("success_action_redirect", "<?= $success_action_redirect ?>");
data.append("Content-Type", "<?= $ContentType ?>");
data.append("x-amz-server-side-encryption", "AES256");
data.append("X-Amz-Credential", "<?= $AWSAccessKeyId ?>/<?= $dateISO ?>/us-east-2/s3/aws4_request");
data.append("X-Amz-Algorithm", "AWS4-HMAC-SHA256");
data.append("X-Amz-Date", "<?= $dateISO ?>T000000Z");
data.append("x-amz-meta-tag", "");
data.append("X-Amz-Signature", "<?= $signature ?>");
data.append("Policy", "<?= $policyBase64 ?>");
}
};
</script>
</body>
</html>
@MourIdri
Copy link

MourIdri commented Apr 5, 2017

Hi This is amazing !! This what I was looking for !!
I am using an alternate S3 ( cheaper than aws ... ) provider. I tried to change some parameters ( Bucket AWSAccessKeyId, AWSSecretAccessKey ) but it did not work, any idea ? the aws4 signature maybe ?

@treii28
Copy link

treii28 commented Jun 13, 2019

I'm getting a 403 trying this. I've verified via a php app that the IAM settings work fine. I generated a key/secret and added them to the script. I have been using the same us-east-2 in my other tests. I even tried changing the acl setting with no luck.

@andresdeco
Copy link

@treii28 did you solve it?

@scottw-finao
Copy link

I'm using a different method in the browser with aws-sdk and retrieving a signed upload url via the sdk multipart upload. But now I'm running into another problem where if I add more than 10 or so files to the process queue, not all of them finish.

@serdarde
Copy link

Wow, that help really a lot! Thank you!

There are 2 small bugs, if you fix them, it will be perfect. You use 2 time hard-coded region "us-east-2". that doesn't work for everyone.

One more hint for the newcomers, open your S3 permissions tab and put that code peace under CORS section:

[
  {
    "AllowedHeaders": [
      "*"
    ],
    "AllowedMethods": [
      "GET",
      "POST",
      "PUT",
      "DELETE"
    ],
    "AllowedOrigins": [
      "*"
    ],
    "ExposeHeaders": []
  }
]

@surath-gunawardena
Copy link

@mmoehrlein @serdarde
Thank you very much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment