1 | <?php |
||
13 | class Signature |
||
14 | { |
||
15 | |||
16 | CONST ALGORITHM = "AWS4-HMAC-SHA256"; |
||
17 | CONST SERVICE = "s3"; |
||
18 | CONST REQUEST_TYPE = "aws4_request"; |
||
19 | |||
20 | /** |
||
21 | * Default options, these can be overwritten within the constructor. |
||
22 | * |
||
23 | * @var array |
||
24 | */ |
||
25 | protected $options = [ |
||
26 | |||
27 | // If the upload is a success, this is the http code we get back from S3. |
||
28 | // By default this will be a 201 Created. |
||
29 | 'success_status' => 201, |
||
30 | |||
31 | // If the file should be private/public-read/public-write. |
||
32 | // This is file specific, not bucket. More info: http://amzn.to/1SSOgwO |
||
33 | 'acl' => 'private', |
||
34 | |||
35 | // The file's name on s3, can be set with JS by changing the input[name="key"]. |
||
36 | // ${filename} will just mean the original filename of the file being uploaded. |
||
37 | 'default_filename' => '${filename}', |
||
38 | |||
39 | // The maximum file size of an upload in MB. Will refuse with a EntityTooLarge |
||
40 | // and 400 Bad Request if you exceed this limit. |
||
41 | 'max_file_size' => 500, |
||
42 | |||
43 | // Request expiration time, specified in relative time format or in seconds. |
||
44 | // minimum of 1 (+1 second), maximum of 604800 (+7 days) |
||
45 | 'expires' => '+6 hours', |
||
46 | |||
47 | // Server will check that the filename starts with this prefix and fail |
||
48 | // with a AccessDenied 403 if not. |
||
49 | 'valid_prefix' => '', |
||
50 | |||
51 | // Strictly only allow a single content type, blank will allow all. Will fail |
||
52 | // with a AccessDenied 403 is this condition is not met. |
||
53 | 'content_type' => '', |
||
54 | |||
55 | // Sets whether AWS server side encryption should be applied to the uploaded files, |
||
56 | // so that files will be encrypted with AES256 when at rest. |
||
57 | 'encryption' => false, |
||
58 | |||
59 | // |
||
60 | 'custom_url' => null, |
||
61 | |||
62 | // Any additional inputs to add to the form. This is an array of name => value |
||
63 | // pairs e.g. ['Content-Disposition' => 'attachment'] |
||
64 | 'additional_inputs' => [] |
||
65 | |||
66 | ]; |
||
67 | |||
68 | /** |
||
69 | * @var string the AWS Key |
||
70 | */ |
||
71 | private $key; |
||
72 | |||
73 | /** |
||
74 | * @var string the AWS Secret |
||
75 | */ |
||
76 | private $secret; |
||
77 | |||
78 | /** |
||
79 | * @var string |
||
80 | */ |
||
81 | private $bucket; |
||
82 | |||
83 | /** |
||
84 | * @var Region |
||
85 | */ |
||
86 | private $region; |
||
87 | |||
88 | /** |
||
89 | * @var int the current unix timestamp |
||
90 | */ |
||
91 | private $time = null; |
||
92 | |||
93 | private $credentials = null; |
||
94 | private $base64Policy = null; |
||
95 | private $signature = null; |
||
96 | |||
97 | /** |
||
98 | * Signature constructor. |
||
99 | * |
||
100 | * @param string $key the AWS API Key to use. |
||
101 | * @param string $secret the AWS API Secret to use. |
||
102 | * @param string $bucket the bucket to upload the file into. |
||
103 | * @param string $region the s3 region this bucket is within. More info: http://amzn.to/1FtPG6r |
||
104 | * @param array $options any additional options, like acl and success status. |
||
105 | */ |
||
106 | public function __construct($key, $secret, $bucket, $region = "us-east-1", $options = []) |
||
116 | |||
117 | /** |
||
118 | * Set the AWS Credentials |
||
119 | * |
||
120 | * @param string $key the AWS API Key to use. |
||
121 | * @param string $secret the AWS API Secret to use. |
||
122 | */ |
||
123 | protected function setAwsCredentials($key, $secret) |
||
137 | |||
138 | /** |
||
139 | * Build the form url for sending files, this will include the bucket and the region name. |
||
140 | * |
||
141 | * @return string the s3 bucket's url. |
||
142 | */ |
||
143 | public function getFormUrl() |
||
151 | |||
152 | private function buildCustomUrl() |
||
164 | |||
165 | private function buildAmazonUrl() |
||
178 | |||
179 | /** |
||
180 | * Get all options. |
||
181 | * |
||
182 | * @return array |
||
183 | */ |
||
184 | public function getOptions() |
||
188 | |||
189 | /** |
||
190 | * Set/overwrite any default options. |
||
191 | * |
||
192 | * @param array $options any options to override. |
||
193 | */ |
||
194 | public function setOptions($options) |
||
204 | |||
205 | /** |
||
206 | * Get an AWS Signature V4 generated. |
||
207 | * |
||
208 | * @return string the aws v4 signature. |
||
209 | */ |
||
210 | public function getSignature() |
||
219 | |||
220 | /** |
||
221 | * Generate the necessary hidden inputs to go within the form. These inputs should match what's being send in |
||
222 | * the policy. |
||
223 | * |
||
224 | * @param bool $addKey whether to add the 'key' input (filename), defaults to yes. |
||
225 | * |
||
226 | * @return array of the form inputs. |
||
227 | */ |
||
228 | public function getFormInputs($addKey = true) |
||
257 | |||
258 | /** |
||
259 | * Based on getFormInputs(), this will build up the html to go within the form. |
||
260 | * |
||
261 | * @param bool $addKey whether to add the 'key' input (filename), defaults to yes. |
||
262 | * |
||
263 | * @return string html of hidden form inputs. |
||
264 | */ |
||
265 | public function getFormInputsAsHtml($addKey = true) |
||
273 | |||
274 | |||
275 | // Where the magic begins ;) |
||
276 | |||
277 | /** |
||
278 | * Step 1: Generate the Scope |
||
279 | */ |
||
280 | protected function generateScope() |
||
291 | |||
292 | /** |
||
293 | * Step 2: Generate a Base64 Policy |
||
294 | */ |
||
295 | protected function generatePolicy() |
||
314 | |||
315 | private function getPolicyContentTypeArray() |
||
324 | |||
325 | private function addAdditionalInputs($policy) |
||
332 | |||
333 | /** |
||
334 | * Step 3: Generate and sign the Signature (v4) |
||
335 | */ |
||
336 | protected function generateSignature() |
||
354 | |||
355 | |||
356 | // Helper functions |
||
357 | |||
358 | private function keyHash($date, $key, $raw = true) |
||
362 | |||
363 | private function populateTime() |
||
369 | |||
370 | private function mbToBytes($megaByte) |
||
377 | |||
378 | |||
379 | // Dates |
||
380 | |||
381 | private function getShortDateFormat() |
||
385 | |||
386 | private function getFullDateFormat() |
||
390 | |||
391 | private function getExpirationDate() |
||
404 | |||
405 | |||
406 | } |
||
407 |
Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a
@return
annotation as described here.