PluginProbe
Media Cloud Sync / 1.4.2
Media Cloud Sync v1.4.2
1.4.2 1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 All 36 releases
← All changes | includes/sdk/s3/Aws/S3/S3Client.php +101 -21 1.2.13 → 1.4.2 View file →
@@ -40,8 +40,12 @@
40 40 * @method \Aws\Result copyObject(array $args = [])
41 41 * @method \GuzzleHttp\Promise\Promise copyObjectAsync(array $args = [])
42 42 * @method \Aws\Result createBucket(array $args = [])
43 43 * @method \GuzzleHttp\Promise\Promise createBucketAsync(array $args = [])
44 + * @method \Aws\Result createBucketMetadataConfiguration(array $args = [])
45 + * @method \GuzzleHttp\Promise\Promise createBucketMetadataConfigurationAsync(array $args = [])
46 + * @method \Aws\Result createBucketMetadataTableConfiguration(array $args = [])
47 + * @method \GuzzleHttp\Promise\Promise createBucketMetadataTableConfigurationAsync(array $args = [])
44 48 * @method \Aws\Result createMultipartUpload(array $args = [])
45 49 * @method \GuzzleHttp\Promise\Promise createMultipartUploadAsync(array $args = [])
46 50 * @method \Aws\Result createSession(array $args = [])
47 51 * @method \GuzzleHttp\Promise\Promise createSessionAsync(array $args = [])
@@ -58,8 +62,12 @@
58 62 * @method \Aws\Result deleteBucketInventoryConfiguration(array $args = [])
59 63 * @method \GuzzleHttp\Promise\Promise deleteBucketInventoryConfigurationAsync(array $args = [])
60 64 * @method \Aws\Result deleteBucketLifecycle(array $args = [])
61 65 * @method \GuzzleHttp\Promise\Promise deleteBucketLifecycleAsync(array $args = [])
66 + * @method \Aws\Result deleteBucketMetadataConfiguration(array $args = [])
67 + * @method \GuzzleHttp\Promise\Promise deleteBucketMetadataConfigurationAsync(array $args = [])
68 + * @method \Aws\Result deleteBucketMetadataTableConfiguration(array $args = [])
69 + * @method \GuzzleHttp\Promise\Promise deleteBucketMetadataTableConfigurationAsync(array $args = [])
62 70 * @method \Aws\Result deleteBucketMetricsConfiguration(array $args = [])
63 71 * @method \GuzzleHttp\Promise\Promise deleteBucketMetricsConfigurationAsync(array $args = [])
64 72 * @method \Aws\Result deleteBucketOwnershipControls(array $args = [])
65 73 * @method \GuzzleHttp\Promise\Promise deleteBucketOwnershipControlsAsync(array $args = [])
@@ -100,8 +108,12 @@
100 108 * @method \Aws\Result getBucketLocation(array $args = [])
101 109 * @method \GuzzleHttp\Promise\Promise getBucketLocationAsync(array $args = [])
102 110 * @method \Aws\Result getBucketLogging(array $args = [])
103 111 * @method \GuzzleHttp\Promise\Promise getBucketLoggingAsync(array $args = [])
112 + * @method \Aws\Result getBucketMetadataConfiguration(array $args = [])
113 + * @method \GuzzleHttp\Promise\Promise getBucketMetadataConfigurationAsync(array $args = [])
114 + * @method \Aws\Result getBucketMetadataTableConfiguration(array $args = [])
115 + * @method \GuzzleHttp\Promise\Promise getBucketMetadataTableConfigurationAsync(array $args = [])
104 116 * @method \Aws\Result getBucketMetricsConfiguration(array $args = [])
105 117 * @method \GuzzleHttp\Promise\Promise getBucketMetricsConfigurationAsync(array $args = [])
106 118 * @method \Aws\Result getBucketNotification(array $args = [])
107 119 * @method \GuzzleHttp\Promise\Promise getBucketNotificationAsync(array $args = [])
@@ -220,12 +232,18 @@
220 232 * @method \Aws\Result putObjectTagging(array $args = [])
221 233 * @method \GuzzleHttp\Promise\Promise putObjectTaggingAsync(array $args = [])
222 234 * @method \Aws\Result putPublicAccessBlock(array $args = [])
223 235 * @method \GuzzleHttp\Promise\Promise putPublicAccessBlockAsync(array $args = [])
236 + * @method \Aws\Result renameObject(array $args = [])
237 + * @method \GuzzleHttp\Promise\Promise renameObjectAsync(array $args = [])
224 238 * @method \Aws\Result restoreObject(array $args = [])
225 239 * @method \GuzzleHttp\Promise\Promise restoreObjectAsync(array $args = [])
226 240 * @method \Aws\Result selectObjectContent(array $args = [])
227 241 * @method \GuzzleHttp\Promise\Promise selectObjectContentAsync(array $args = [])
242 + * @method \Aws\Result updateBucketMetadataInventoryTableConfiguration(array $args = [])
243 + * @method \GuzzleHttp\Promise\Promise updateBucketMetadataInventoryTableConfigurationAsync(array $args = [])
244 + * @method \Aws\Result updateBucketMetadataJournalTableConfiguration(array $args = [])
245 + * @method \GuzzleHttp\Promise\Promise updateBucketMetadataJournalTableConfigurationAsync(array $args = [])
228 246 * @method \Aws\Result uploadPart(array $args = [])
229 247 * @method \GuzzleHttp\Promise\Promise uploadPartAsync(array $args = [])
230 248 * @method \Aws\Result uploadPartCopy(array $args = [])
231 249 * @method \GuzzleHttp\Promise\Promise uploadPartCopyAsync(array $args = [])
@@ -233,17 +251,20 @@
233 251 * @method \GuzzleHttp\Promise\Promise writeGetObjectResponseAsync(array $args = [])
234 252 */
235 253 class S3Client extends AwsClient implements S3ClientInterface
236 254 {
255 + private const DIRECTORY_BUCKET_REGEX = '/^[a-zA-Z0-9_-]+--[a-z0-9]+-az\\d+--x-s3' . '(?!.*(?:-s3alias|--ol-s3|\\.mrap))$/';
237 256 use S3ClientTrait;
238 257 /** @var array */
239 258 private static $mandatoryAttributes = ['Bucket', 'Key'];
259 + /** @var array */
260 + private static $checksumOptionEnum = ['when_supported' => \true, 'when_required' => \true];
240 261 public static function getArguments()
241 262 {
242 263 $args = parent::getArguments();
243 264 $args['retries']['fn'] = [__CLASS__, '_applyRetryConfig'];
244 265 $args['api_provider']['fn'] = [__CLASS__, '_applyApiProvider'];
245 - return $args + ['bucket_endpoint' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to send requests to a hardcoded ' . 'bucket endpoint rather than create an endpoint as a ' . 'result of injecting the bucket into the URL. This ' . 'option is useful for interacting with CNAME endpoints.'], 'use_arn_region' => ['type' => 'config', 'valid' => ['bool', Configuration::class, CacheInterface::class, 'callable'], 'doc' => 'Set to true to allow passed in ARNs to override' . ' client region. Accepts...', 'fn' => [__CLASS__, '_apply_use_arn_region'], 'default' => [UseArnRegionConfigurationProvider::class, 'defaultProvider']], 'use_accelerate_endpoint' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to send requests to an S3 Accelerate' . ' endpoint by default. Can be enabled or disabled on' . ' individual operations by setting' . ' \'@use_accelerate_endpoint\' to true or false. Note:' . ' you must enable S3 Accelerate on a bucket before it can' . ' be accessed via an Accelerate endpoint.', 'default' => \false], 'use_path_style_endpoint' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to send requests to an S3 path style' . ' endpoint by default.' . ' Can be enabled or disabled on individual operations by setting' . ' \'@use_path_style_endpoint\' to true or false.', 'default' => \false], 'disable_multiregion_access_points' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to disable the usage of' . ' multi region access points. These are enabled by default.' . ' Can be enabled or disabled on individual operations by setting' . ' \'@disable_multiregion_access_points\' to true or false.', 'default' => \false], 'disable_express_session_auth' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to disable the usage of' . ' s3 express session authentication. This is enabled by default.', 'default' => [__CLASS__, '_default_disable_express_session_auth']], 's3_express_identity_provider' => ['type' => 'config', 'valid' => ['bool', 'callable'], 'doc' => 'Specifies the provider used to generate identities to sign s3 express requests. ' . 'Set to `false` to disable s3 express auth, or a callable provider used to create s3 express ' . 'identities or return null.', 'default' => [__CLASS__, '_default_s3_express_identity_provider']]];
266 + return ['request_checksum_calculation' => ['type' => 'config', 'valid' => ['string'], 'doc' => 'Valid values are `when_supported` and `when_required`. Default is `when_supported`.' . ' `when_supported` results in checksum calculation when an operation has modeled checksum support.' . ' `when_required` results in checksum calculation when an operation has modeled checksum support and' . ' request checksums are modeled as required.', 'fn' => [__CLASS__, '_apply_request_checksum_calculation'], 'default' => [__CLASS__, '_default_request_checksum_calculation']], 'response_checksum_validation' => ['type' => 'config', 'valid' => ['string'], 'doc' => 'Valid values are `when_supported` and `when_required`. Default is `when_supported`.' . ' `when_supported` results in checksum validation when an operation has modeled checksum support.' . ' `when_required` results in checksum validation when an operation has modeled checksum support and' . ' `CheckSumMode` is set to `enabled`.', 'fn' => [__CLASS__, '_apply_response_checksum_validation'], 'default' => [__CLASS__, '_default_response_checksum_validation']]] + $args + ['bucket_endpoint' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to send requests to a hardcoded ' . 'bucket endpoint rather than create an endpoint as a ' . 'result of injecting the bucket into the URL. This ' . 'option is useful for interacting with CNAME endpoints.'], 'use_arn_region' => ['type' => 'config', 'valid' => ['bool', Configuration::class, CacheInterface::class, 'callable'], 'doc' => 'Set to true to allow passed in ARNs to override' . ' client region. Accepts...', 'fn' => [__CLASS__, '_apply_use_arn_region'], 'default' => [UseArnRegionConfigurationProvider::class, 'defaultProvider']], 'use_accelerate_endpoint' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to send requests to an S3 Accelerate' . ' endpoint by default. Can be enabled or disabled on' . ' individual operations by setting' . ' \'@use_accelerate_endpoint\' to true or false. Note:' . ' you must enable S3 Accelerate on a bucket before it can' . ' be accessed via an Accelerate endpoint.', 'default' => \false], 'use_path_style_endpoint' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to send requests to an S3 path style' . ' endpoint by default.' . ' Can be enabled or disabled on individual operations by setting' . ' \'@use_path_style_endpoint\' to true or false.', 'default' => \false], 'disable_multiregion_access_points' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to disable the usage of' . ' multi region access points. These are enabled by default.' . ' Can be enabled or disabled on individual operations by setting' . ' \'@disable_multiregion_access_points\' to true or false.', 'default' => \false], 'disable_express_session_auth' => ['type' => 'config', 'valid' => ['bool'], 'doc' => 'Set to true to disable the usage of' . ' s3 express session authentication. This is enabled by default.', 'default' => [__CLASS__, '_default_disable_express_session_auth']], 's3_express_identity_provider' => ['type' => 'config', 'valid' => ['bool', 'callable'], 'doc' => 'Specifies the provider used to generate identities to sign s3 express requests. ' . 'Set to `false` to disable s3 express auth, or a callable provider used to create s3 express ' . 'identities or return null.', 'default' => [__CLASS__, '_default_s3_express_identity_provider']]];
246 267 }
247 268 /**
248 269 * {@inheritdoc}
249 270 *
@@ -306,13 +327,14 @@
306 327 }
307 328 $this->addBuiltIns($args);
308 329 parent::__construct($args);
309 330 $stack = $this->getHandlerList();
331 + $config = $this->getConfig();
310 332 $stack->appendInit(SSECMiddleware::wrap($this->getEndpoint()->getScheme()), 's3.ssec');
311 - $stack->appendBuild(ApplyChecksumMiddleware::wrap($this->getApi()), 's3.checksum');
333 + $stack->appendBuild(ApplyChecksumMiddleware::wrap($this->getApi(), $this->getConfig()), 's3.checksum');
312 334 $stack->appendBuild(Middleware::contentType(['PutObject', 'UploadPart']), 's3.content_type');
313 335 if ($this->getConfig('bucket_endpoint')) {
314 - $stack->appendBuild(BucketEndpointMiddleware::wrap(), 's3.bucket_endpoint');
336 + $stack->appendBuild(BucketEndpointMiddleware::wrap($this->isUseEndpointV2(), $args['endpoint'] ?? null), 's3.bucket_endpoint');
315 337 } elseif (!$this->isUseEndpointV2()) {
316 338 $stack->appendBuild(S3EndpointMiddleware::wrap($this->getRegion(), $this->getConfig('endpoint_provider'), ['accelerate' => $this->getConfig('use_accelerate_endpoint'), 'path_style' => $this->getConfig('use_path_style_endpoint'), 'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'), 'dual_stack' => $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint()]), 's3.endpoint_middleware');
317 339 }
318 340 $stack->appendBuild(BucketEndpointArnMiddleware::wrap($this->getApi(), $this->getRegion(), ['use_arn_region' => $this->getConfig('use_arn_region'), 'accelerate' => $this->getConfig('use_accelerate_endpoint'), 'path_style' => $this->getConfig('use_path_style_endpoint'), 'dual_stack' => $this->getConfig('use_dual_stack_endpoint')->isUseDualStackEndpoint(), 'use_fips_endpoint' => $this->getConfig('use_fips_endpoint'), 'disable_multiregion_access_points' => $this->getConfig('disable_multiregion_access_points'), 'endpoint' => $args['endpoint'] ?? null], $this->isUseEndpointV2()), 's3.bucket_endpoint_arn');
@@ -369,13 +391,63 @@
369 391 // The Configuration class itself will validate other inputs
370 392 $args['use_arn_region'] = new Configuration($value);
371 393 }
372 394 }
395 + public static function _default_request_checksum_calculation(array $args) : string
396 + {
397 + return ConfigurationResolver::resolve('request_checksum_calculation', ApplyChecksumMiddleware::DEFAULT_CALCULATION_MODE, 'string', $args);
398 + }
399 + public static function _apply_request_checksum_calculation(string $value, array &$args) : void
400 + {
401 + $value = \strtolower($value);
402 + if (\array_key_exists($value, self::$checksumOptionEnum)) {
403 + $args['request_checksum_calculation'] = $value;
404 + } else {
405 + $validValues = \implode(' | ', \array_keys(self::$checksumOptionEnum));
406 + throw new \InvalidArgumentException('invalid value provided for `request_checksum_calculation`.' . ' valid values are: ' . $validValues . '.');
407 + }
408 + }
409 + public static function _default_response_checksum_validation(array $args) : string
410 + {
411 + return ConfigurationResolver::resolve('response_checksum_validation', ValidateResponseChecksumResultMutator::DEFAULT_VALIDATION_MODE, 'string', $args);
412 + }
413 + public static function _apply_response_checksum_validation($value, array &$args) : void
414 + {
415 + $value = \strtolower($value);
416 + if (\array_key_exists($value, self::$checksumOptionEnum)) {
417 + $args['response_checksum_validation'] = $value;
418 + } else {
419 + $validValues = \implode(' | ', \array_keys(self::$checksumOptionEnum));
420 + throw new \InvalidArgumentException('invalid value provided for `response_checksum_validation`.' . ' valid values are: ' . $validValues . '.');
421 + }
422 + }
423 + public static function _default_disable_express_session_auth(array &$args)
424 + {
425 + return ConfigurationResolver::resolve('s3_disable_express_session_auth', \false, 'bool', $args);
426 + }
427 + public static function _default_s3_express_identity_provider(array $args)
428 + {
429 + if ($args['config']['disable_express_session_auth']) {
430 + return \false;
431 + }
432 + return new S3ExpressIdentityProvider($args['region']);
433 + }
373 434 public function createPresignedRequest(CommandInterface $command, $expires, array $options = [])
374 435 {
375 436 $command = clone $command;
376 - $command->getHandlerList()->remove('signer');
437 + $list = $command->getHandlerList();
438 + $list->remove('signer');
439 + //Removes checksum calculation behavior by default
440 + if (empty($command['ChecksumAlgorithm']) && empty($command['AddContentMD5'])) {
441 + $list->remove('s3.checksum');
442 + }
377 443 $request = \Dudlewebs\WPMCS\s3\Aws\serialize($command);
444 + //Applies ContentSHA256 parameter, if provided and not applied
445 + // by middleware
446 + $commandName = $command->getName();
447 + if (!empty($command['ContentSHA256'] && isset(ApplyChecksumMiddleware::$sha256[$commandName]) && !$request->hasHeader('X-Amz-Content-Sha256'))) {
448 + $request = $request->withHeader('X-Amz-Content-Sha256', $command['ContentSHA256']);
449 + }
378 450 $signing_name = $command['@context']['signing_service'] ?? $this->getSigningName($request->getUri()->getHost());
379 451 $signature_version = $this->getSignatureVersionFromCommand($command);
380 452 /** @var \Aws\Signature\SignatureInterface $signer */
381 453 $signer = \call_user_func($this->getSignatureProvider(), $signature_version, $signing_name, $this->getConfig('signing_region'));
@@ -425,14 +497,18 @@
425 497 {
426 498 $region = $this->getRegion();
427 499 return static function (callable $handler) use($region) {
428 500 return function (Command $command, $request = null) use($handler, $region) {
429 - if ($command->getName() === 'CreateBucket') {
501 + if ($command->getName() === 'CreateBucket' && !self::isDirectoryBucket($command['Bucket'])) {
430 502 $locationConstraint = $command['CreateBucketConfiguration']['LocationConstraint'] ?? null;
431 503 if ($locationConstraint === 'us-east-1') {
432 504 unset($command['CreateBucketConfiguration']);
433 505 } elseif ('us-east-1' !== $region && empty($locationConstraint)) {
434 - $command['CreateBucketConfiguration'] = ['LocationConstraint' => $region];
506 + if (isset($command['CreateBucketConfiguration'])) {
507 + $command['CreateBucketConfiguration']['LocationConstraint'] = $region;
508 + } else {
509 + $command['CreateBucketConfiguration'] = ['LocationConstraint' => $region];
510 + }
435 511 }
436 512 }
437 513 return $handler($command, $request);
438 514 };
@@ -463,9 +539,9 @@
463 539 */
464 540 private function getHeadObjectMiddleware()
465 541 {
466 542 return static function (callable $handler) {
467 - return function (CommandInterface $command, RequestInterface $request = null) use($handler) {
543 + return function (CommandInterface $command, ?RequestInterface $request = null) use($handler) {
468 544 if ($command->getName() === 'HeadObject' && !isset($command['@http']['decode_content'])) {
469 545 $command['@http']['decode_content'] = \false;
470 546 }
471 547 return $handler($command, $request);
@@ -538,9 +614,9 @@
538 614 */
539 615 private function getDisableExpressSessionAuthMiddleware()
540 616 {
541 617 return function (callable $handler) {
542 - return function (CommandInterface $command, RequestInterface $request = null) use($handler) {
618 + return function (CommandInterface $command, ?RequestInterface $request = null) use($handler) {
543 619 if (!empty($command['@context']['signature_version']) && $command['@context']['signature_version'] === 'v4-s3express') {
544 620 $command['@context']['signature_version'] = 's3v4';
545 621 }
546 622 return $handler($command, $request);
@@ -560,19 +636,8 @@
560 636 return 's3-object-lambda';
561 637 }
562 638 return $this->getConfig('signing_name');
563 639 }
564 - public static function _default_disable_express_session_auth(array &$args)
565 - {
566 - return ConfigurationResolver::resolve('s3_disable_express_session_auth', \false, 'bool', $args);
567 - }
568 - public static function _default_s3_express_identity_provider(array $args)
569 - {
570 - if ($args['config']['disable_express_session_auth']) {
571 - return \false;
572 - }
573 - return new S3ExpressIdentityProvider($args['region']);
574 - }
575 640 /**
576 641 * If EndpointProviderV2 is used, removes `Bucket` from request URIs.
577 642 * This is now handled by the endpoint ruleset.
578 643 *
@@ -594,8 +659,12 @@
594 659 if ($requestUri === "/{Bucket}") {
595 660 $requestUri = \str_replace('/{Bucket}', '/', $requestUri);
596 661 } else {
597 662 $requestUri = \str_replace('/{Bucket}', '', $requestUri);
663 + // If we're left with just a query string, prepend '/'
664 + if (\str_starts_with($requestUri, '?')) {
665 + $requestUri = '/' . $requestUri;
666 + }
598 667 }
599 668 $operation['http']['requestUri'] = $requestUri;
600 669 }
601 670 }
@@ -601,9 +670,9 @@
601 670 }
602 671 }
603 672 foreach ($definition['shapes'] as $key => &$value) {
604 673 $suffix = 'Output';
605 - if (\substr($key, -\strlen($suffix)) === $suffix) {
674 + if (\str_ends_with($key, $suffix)) {
606 675 if (isset($value['members']['Expires'])) {
607 676 $value['members']['Expires']['deprecated'] = \true;
608 677 $value['members']['ExpiresString'] = ['shape' => 'ExpiresString', 'location' => 'header', 'locationName' => 'Expires'];
609 678 }
@@ -646,8 +715,19 @@
646 715 }
647 716 }
648 717 $this->clientBuiltIns[$key] = $value;
649 718 }
719 + /**
720 + * Determines whether a bucket is a directory bucket.
721 + * Only considers the availability zone/suffix format
722 + *
723 + * @param string $bucket
724 + * @return bool
725 + */
726 + public static function isDirectoryBucket(string $bucket) : bool
727 + {
728 + return \preg_match(self::DIRECTORY_BUCKET_REGEX, $bucket) === 1;
729 + }
650 730 /** @internal */
651 731 public static function _applyRetryConfig($value, $args, HandlerList $list)
652 732 {
653 733 if ($value) {
@@ -697,9 +777,9 @@
697 777 {
698 778 ClientResolver::_apply_api_provider($value, $args);
699 779 $s3Parser = new S3Parser($args['parser'], $args['error_parser'], $args['api'], $args['exception_class']);
700 780 $s3Parser->addS3ResultMutator('get-bucket-location', new GetBucketLocationResultMutator());
701 - $s3Parser->addS3ResultMutator('validate-response-checksum', new ValidateResponseChecksumResultMutator($args['api']));
781 + $s3Parser->addS3ResultMutator('validate-response-checksum', new ValidateResponseChecksumResultMutator($args['api'], ['response_checksum_validation' => $args['response_checksum_validation']]));
702 782 $args['parser'] = $s3Parser;
703 783 }
704 784 /**
705 785 * @internal