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;
- 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,
- ];
-
- 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;
- }
-
- 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)
- );
- }
- });
- }
-
- 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;
- }
- }
|