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
@returnannotation as described here.