Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\S3;
3
 
4
use Aws\Arn\ArnParser;
5
use Aws\Arn\S3\AccessPointArn;
6
use Aws\Exception\MultipartUploadException;
7
use Aws\Result;
8
use Aws\S3\Exception\S3Exception;
9
use GuzzleHttp\Promise\Coroutine;
10
use GuzzleHttp\Promise\PromisorInterface;
11
use InvalidArgumentException;
12
 
13
/**
14
 * Copies objects from one S3 location to another, utilizing a multipart copy
15
 * when appropriate.
16
 */
17
class ObjectCopier implements PromisorInterface
18
{
19
    const DEFAULT_MULTIPART_THRESHOLD = MultipartUploader::PART_MAX_SIZE;
20
 
21
    private $client;
22
    private $source;
23
    private $destination;
24
    private $acl;
25
    private $options;
26
 
27
    private static $defaults = [
28
        'before_lookup' => null,
29
        'before_upload' => null,
30
        'concurrency'   => 5,
31
        'mup_threshold' => self::DEFAULT_MULTIPART_THRESHOLD,
32
        'params'        => [],
33
        'part_size'     => null,
34
        'version_id'    => null,
35
    ];
36
 
37
    /**
38
     * @param S3ClientInterface $client         The S3 Client used to execute
39
     *                                          the copy command(s).
40
     * @param array             $source         The object to copy, specified as
41
     *                                          an array with a 'Bucket' and
42
     *                                          'Key' keys. Provide a
43
     *                                          'VersionID' key to copy a
44
     *                                          specified version of an object.
45
     * @param array             $destination    The bucket and key to which to
46
     *                                          copy the $source, specified as
47
     *                                          an array with a 'Bucket' and
48
     *                                          'Key' keys.
49
     * @param string            $acl            ACL to apply to the copy
50
     *                                          (default: private).
51
     * @param array             $options        Options used to configure the
52
     *                                          copy process. Options passed in
53
     *                                          through 'params' are added to
54
     *                                          the sub commands.
55
     *
56
     * @throws InvalidArgumentException
57
     */
58
    public function __construct(
59
        S3ClientInterface $client,
60
        array $source,
61
        array $destination,
62
        $acl = 'private',
63
        array $options = []
64
    ) {
65
        $this->validateLocation($source);
66
        $this->validateLocation($destination);
67
 
68
        $this->client = $client;
69
        $this->source = $source;
70
        $this->destination = $destination;
71
        $this->acl = $acl;
72
        $this->options = $options + self::$defaults;
73
    }
74
 
75
    /**
76
     * Perform the configured copy asynchronously. Returns a promise that is
77
     * fulfilled with the result of the CompleteMultipartUpload or CopyObject
78
     * operation or rejected with an exception.
79
     *
80
     * @return Coroutine
81
     */
82
    public function promise()
83
    {
84
        return Coroutine::of(function () {
85
            $headObjectCommand = $this->client->getCommand(
86
                'HeadObject',
87
                $this->options['params'] + $this->source
88
            );
89
            if (is_callable($this->options['before_lookup'])) {
90
                $this->options['before_lookup']($headObjectCommand);
91
            }
92
            $objectStats = (yield $this->client->executeAsync(
93
                $headObjectCommand
94
            ));
95
 
96
            if ($objectStats['ContentLength'] > $this->options['mup_threshold']) {
97
                $mup = new MultipartCopy(
98
                    $this->client,
99
                    $this->getSourcePath(),
100
                    ['source_metadata' => $objectStats, 'acl' => $this->acl]
101
                        + $this->destination
102
                        + $this->options
103
                );
104
 
105
                yield $mup->promise();
106
            } else {
107
                $defaults = [
108
                    'ACL' => $this->acl,
109
                    'MetadataDirective' => 'COPY',
110
                    'CopySource' => $this->getSourcePath(),
111
                ];
112
 
113
                $params = array_diff_key($this->options, self::$defaults)
114
                    + $this->destination + $defaults + $this->options['params'];
115
 
116
                yield $this->client->executeAsync(
117
                    $this->client->getCommand('CopyObject', $params)
118
                );
119
            }
120
        });
121
    }
122
 
123
    /**
124
     * Perform the configured copy synchronously. Returns the result of the
125
     * CompleteMultipartUpload or CopyObject operation.
126
     *
127
     * @return Result
128
     *
129
     * @throws S3Exception
130
     * @throws MultipartUploadException
131
     */
132
    public function copy()
133
    {
134
        return $this->promise()->wait();
135
    }
136
 
137
    private function validateLocation(array $location)
138
    {
139
        if (empty($location['Bucket']) || empty($location['Key'])) {
140
            throw new \InvalidArgumentException('Locations provided to an'
141
                . ' Aws\S3\ObjectCopier must have a non-empty Bucket and Key');
142
        }
143
    }
144
 
145
    private function getSourcePath()
146
    {
147
        $path = "/{$this->source['Bucket']}/";
148
        if (ArnParser::isArn($this->source['Bucket'])) {
149
            try {
150
                new AccessPointArn($this->source['Bucket']);
151
                $path = "{$this->source['Bucket']}/object/";
152
            } catch (\Exception $e) {
153
                throw new \InvalidArgumentException(
154
                    'Provided ARN was a not a valid S3 access point ARN ('
155
                    . $e->getMessage() . ')',
156
                    0,
157
                    $e
158
                );
159
            }
160
        }
161
 
162
        $sourcePath = $path . rawurlencode($this->source['Key']);
163
        if (isset($this->source['VersionId'])) {
164
            $sourcePath .= "?versionId={$this->source['VersionId']}";
165
        }
166
 
167
        return $sourcePath;
168
    }
169
}