Complex classes like Signature often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Signature, and based on these observations, apply Extract Interface, too.
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 | // Allow S3 compatible solutions by specifying the domain it should POST to. Must be |
||
60 | // a valid url (inc. http/https) otherwise will throw InvalidOptionException. |
||
61 | 'custom_url' => null, |
||
62 | |||
63 | // Set Amazon S3 Transfer Acceleration |
||
64 | 'accelerate' => false, |
||
65 | |||
66 | // Any additional inputs to add to the form. This is an array of name => value |
||
67 | // pairs e.g. ['Content-Disposition' => 'attachment'] |
||
68 | 'additional_inputs' => [] |
||
69 | |||
70 | ]; |
||
71 | |||
72 | /** |
||
73 | * @var string the AWS Key |
||
74 | */ |
||
75 | private $key; |
||
76 | |||
77 | /** |
||
78 | * @var string the AWS Secret |
||
79 | */ |
||
80 | private $secret; |
||
81 | |||
82 | /** |
||
83 | * @var string |
||
84 | */ |
||
85 | private $bucket; |
||
86 | |||
87 | /** |
||
88 | * @var Region |
||
89 | */ |
||
90 | private $region; |
||
91 | |||
92 | /** |
||
93 | * @var int the current unix timestamp |
||
94 | */ |
||
95 | private $time = null; |
||
96 | |||
97 | private $credentials = null; |
||
98 | private $base64Policy = null; |
||
99 | private $signature = null; |
||
100 | |||
101 | /** |
||
102 | * Signature constructor. |
||
103 | * |
||
104 | * @param string $key the AWS API Key to use. |
||
105 | * @param string $secret the AWS API Secret to use. |
||
106 | * @param string $bucket the bucket to upload the file into. |
||
107 | * @param string $region the s3 region this bucket is within. More info: http://amzn.to/1FtPG6r |
||
108 | * @param array $options any additional options, like acl and success status. |
||
109 | */ |
||
110 | public function __construct($key, $secret, $bucket, $region = "us-east-1", $options = []) |
||
120 | |||
121 | /** |
||
122 | * Set the AWS Credentials |
||
123 | * |
||
124 | * @param string $key the AWS API Key to use. |
||
125 | * @param string $secret the AWS API Secret to use. |
||
126 | */ |
||
127 | protected function setAwsCredentials($key, $secret) |
||
141 | |||
142 | /** |
||
143 | * Build the form url for sending files, this will include the bucket and the region name. |
||
144 | * |
||
145 | * @return string the s3 bucket's url. |
||
146 | */ |
||
147 | public function getFormUrl() |
||
155 | |||
156 | private function buildCustomUrl() |
||
168 | |||
169 | private function buildAmazonUrl() |
||
186 | |||
187 | /** |
||
188 | * Get all options. |
||
189 | * |
||
190 | * @return array |
||
191 | */ |
||
192 | public function getOptions() |
||
196 | |||
197 | /** |
||
198 | * Set/overwrite any default options. |
||
199 | * |
||
200 | * @param array $options any options to override. |
||
201 | */ |
||
202 | public function setOptions($options) |
||
218 | |||
219 | /** |
||
220 | * Get an AWS Signature V4 generated. |
||
221 | * |
||
222 | * @return string the aws v4 signature. |
||
223 | */ |
||
224 | public function getSignature() |
||
233 | |||
234 | /** |
||
235 | * Generate the necessary hidden inputs to go within the form. These inputs should match what's being send in |
||
236 | * the policy. |
||
237 | * |
||
238 | * @param bool $addKey whether to add the 'key' input (filename), defaults to yes. |
||
239 | * |
||
240 | * @return array of the form inputs. |
||
241 | */ |
||
242 | public function getFormInputs($addKey = true) |
||
267 | |||
268 | /** |
||
269 | * Based on getFormInputs(), this will build up the html to go within the form. |
||
270 | * |
||
271 | * @param bool $addKey whether to add the 'key' input (filename), defaults to yes. |
||
272 | * |
||
273 | * @return string html of hidden form inputs. |
||
274 | */ |
||
275 | public function getFormInputsAsHtml($addKey = true) |
||
283 | |||
284 | |||
285 | // Where the magic begins ;) |
||
286 | |||
287 | /** |
||
288 | * Step 1: Generate the Scope |
||
289 | */ |
||
290 | protected function generateScope() |
||
301 | |||
302 | /** |
||
303 | * Step 2: Generate a Base64 Policy |
||
304 | */ |
||
305 | protected function generatePolicy() |
||
324 | |||
325 | private function getPolicyContentTypeArray() |
||
334 | |||
335 | private function addAdditionalInputs($policy) |
||
342 | |||
343 | /** |
||
344 | * Step 3: Generate and sign the Signature (v4) |
||
345 | */ |
||
346 | protected function generateSignature() |
||
364 | |||
365 | public function setTime($time = null) |
||
373 | |||
374 | |||
375 | // Helper functions |
||
376 | |||
377 | private function keyHash($date, $key, $raw = true) |
||
381 | |||
382 | private function mbToBytes($megaByte) |
||
389 | |||
390 | |||
391 | // Dates |
||
392 | |||
393 | private function getShortDateFormat() |
||
397 | |||
398 | private function getFullDateFormat() |
||
402 | |||
403 | private function getExpirationDate() |
||
416 | |||
417 | |||
418 | } |
||
419 |
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.