123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- <?php
- namespace Aws\S3;
- use Aws\Arn\ArnParser;
- use Aws\Arn\S3\AccessPointArn;
- use Aws\Exception\MultipartUploadException;
- use Aws\Result;
- use Aws\S3\Exception\S3Exception;
- use GuzzleHttp\Promise\Coroutine;
- use GuzzleHttp\Promise\PromiseInterface;
- use GuzzleHttp\Promise\PromisorInterface;
- use InvalidArgumentException;
- /**
- * Copies objects from one S3 location to another, utilizing a multipart copy
- * when appropriate.
- */
- class ObjectCopier implements PromisorInterface
- {
- const DEFAULT_MULTIPART_THRESHOLD = MultipartUploader::PART_MAX_SIZE;
- private $client;
- private $source;
- private $destination;
- private $acl;
- private $options;
- private static $defaults = [
- 'before_lookup' => null,
- 'before_upload' => null,
- 'concurrency' => 5,
- 'mup_threshold' => self::DEFAULT_MULTIPART_THRESHOLD,
- 'params' => [],
- 'part_size' => null,
- 'version_id' => null,
- ];
- /**
- * @param S3ClientInterface $client The S3 Client used to execute
- * the copy command(s).
- * @param array $source The object to copy, specified as
- * an array with a 'Bucket' and
- * 'Key' keys. Provide a
- * 'VersionID' key to copy a
- * specified version of an object.
- * @param array $destination The bucket and key to which to
- * copy the $source, specified as
- * an array with a 'Bucket' and
- * 'Key' keys.
- * @param string $acl ACL to apply to the copy
- * (default: private).
- * @param array $options Options used to configure the
- * copy process. Options passed in
- * through 'params' are added to
- * the sub commands.
- *
- * @throws InvalidArgumentException
- */
- public function __construct(
- S3ClientInterface $client,
- array $source,
- array $destination,
- $acl = 'private',
- array $options = []
- ) {
- $this->validateLocation($source);
- $this->validateLocation($destination);
- $this->client = $client;
- $this->source = $source;
- $this->destination = $destination;
- $this->acl = $acl;
- $this->options = $options + self::$defaults;
- }
- /**
- * Perform the configured copy asynchronously. Returns a promise that is
- * fulfilled with the result of the CompleteMultipartUpload or CopyObject
- * operation or rejected with an exception.
- *
- * @return Coroutine
- */
- public function promise(): PromiseInterface
- {
- return Coroutine::of(function () {
- $headObjectCommand = $this->client->getCommand(
- 'HeadObject',
- $this->options['params'] + $this->source
- );
- if (is_callable($this->options['before_lookup'])) {
- $this->options['before_lookup']($headObjectCommand);
- }
- $objectStats = (yield $this->client->executeAsync(
- $headObjectCommand
- ));
- if ($objectStats['ContentLength'] > $this->options['mup_threshold']) {
- $mup = new MultipartCopy(
- $this->client,
- $this->getSourcePath(),
- ['source_metadata' => $objectStats, 'acl' => $this->acl]
- + $this->destination
- + $this->options
- );
- yield $mup->promise();
- } else {
- $defaults = [
- 'ACL' => $this->acl,
- 'MetadataDirective' => 'COPY',
- 'CopySource' => $this->getSourcePath(),
- ];
- $params = array_diff_key($this->options, self::$defaults)
- + $this->destination + $defaults + $this->options['params'];
- yield $this->client->executeAsync(
- $this->client->getCommand('CopyObject', $params)
- );
- }
- });
- }
- /**
- * Perform the configured copy synchronously. Returns the result of the
- * CompleteMultipartUpload or CopyObject operation.
- *
- * @return Result
- *
- * @throws S3Exception
- * @throws MultipartUploadException
- */
- public function copy()
- {
- return $this->promise()->wait();
- }
- private function validateLocation(array $location)
- {
- if (empty($location['Bucket']) || empty($location['Key'])) {
- throw new \InvalidArgumentException('Locations provided to an'
- . ' Aws\S3\ObjectCopier must have a non-empty Bucket and Key');
- }
- }
- private function getSourcePath()
- {
- $path = "/{$this->source['Bucket']}/";
- if (ArnParser::isArn($this->source['Bucket'])) {
- try {
- new AccessPointArn($this->source['Bucket']);
- $path = "{$this->source['Bucket']}/object/";
- } catch (\Exception $e) {
- throw new \InvalidArgumentException(
- 'Provided ARN was a not a valid S3 access point ARN ('
- . $e->getMessage() . ')',
- 0,
- $e
- );
- }
- }
- $sourcePath = $path . rawurlencode($this->source['Key']);
- if (isset($this->source['VersionId'])) {
- $sourcePath .= "?versionId={$this->source['VersionId']}";
- }
- return $sourcePath;
- }
- }
|