PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / trunk
Transferito: WP Migration vtrunk
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / vendor / aws / aws-sdk-php / src / S3 / MultipartCopy.php
transferito / vendor / aws / aws-sdk-php / src / S3 Last commit date
Crypto 11 months ago Exception 11 months ago RegionalEndpoint 11 months ago UseArnRegion 11 months ago AmbiguousSuccessParser.php 11 months ago ApplyChecksumMiddleware.php 11 months ago BatchDelete.php 11 months ago BucketEndpointArnMiddleware.php 11 months ago BucketEndpointMiddleware.php 11 months ago CalculatesChecksumTrait.php 11 months ago EndpointRegionHelperTrait.php 11 months ago GetBucketLocationParser.php 11 months ago MultipartCopy.php 11 months ago MultipartUploader.php 11 months ago MultipartUploadingTrait.php 11 months ago ObjectCopier.php 11 months ago ObjectUploader.php 11 months ago PermanentRedirectMiddleware.php 11 months ago PostObject.php 11 months ago PostObjectV4.php 11 months ago PutObjectUrlMiddleware.php 11 months ago RetryableMalformedResponseParser.php 11 months ago S3Client.php 11 months ago S3ClientInterface.php 11 months ago S3ClientTrait.php 11 months ago S3EndpointMiddleware.php 11 months ago S3MultiRegionClient.php 11 months ago S3UriParser.php 11 months ago SSECMiddleware.php 11 months ago StreamWrapper.php 11 months ago Transfer.php 11 months ago ValidateResponseChecksumParser.php 11 months ago
MultipartCopy.php
243 lines
1 <?php
2
3 namespace Aws\S3;
4
5 use Aws\Arn\ArnParser;
6 use Aws\Multipart\AbstractUploadManager;
7 use Aws\ResultInterface;
8 use GuzzleHttp\Psr7;
9
10 class MultipartCopy extends AbstractUploadManager
11 {
12 use MultipartUploadingTrait;
13
14 /** @var string|array */
15 private $source;
16 /** @var string */
17 private $sourceVersionId;
18 /** @var ResultInterface */
19 private $sourceMetadata;
20
21 /**
22 * Creates a multipart upload for copying an S3 object.
23 *
24 * The valid configuration options are as follows:
25 *
26 * - acl: (string) ACL to set on the object being upload. Objects are
27 * private by default.
28 * - before_complete: (callable) Callback to invoke before the
29 * `CompleteMultipartUpload` operation. The callback should have a
30 * function signature like `function (Aws\Command $command) {...}`.
31 * - before_initiate: (callable) Callback to invoke before the
32 * `CreateMultipartUpload` operation. The callback should have a function
33 * signature like `function (Aws\Command $command) {...}`.
34 * - before_upload: (callable) Callback to invoke before `UploadPartCopy`
35 * operations. The callback should have a function signature like
36 * `function (Aws\Command $command) {...}`.
37 * - bucket: (string, required) Name of the bucket to which the object is
38 * being uploaded.
39 * - concurrency: (int, default=int(5)) Maximum number of concurrent
40 * `UploadPart` operations allowed during the multipart upload.
41 * - key: (string, required) Key to use for the object being uploaded.
42 * - params: (array) An array of key/value parameters that will be applied
43 * to each of the sub-commands run by the uploader as a base.
44 * Auto-calculated options will override these parameters. If you need
45 * more granularity over parameters to each sub-command, use the before_*
46 * options detailed above to update the commands directly.
47 * - part_size: (int, default=int(5242880)) Part size, in bytes, to use when
48 * doing a multipart upload. This must between 5 MB and 5 GB, inclusive.
49 * - state: (Aws\Multipart\UploadState) An object that represents the state
50 * of the multipart upload and that is used to resume a previous upload.
51 * When this option is provided, the `bucket`, `key`, and `part_size`
52 * options are ignored.
53 * - source_metadata: (Aws\ResultInterface) An object that represents the
54 * result of executing a HeadObject command on the copy source.
55 *
56 * @param S3ClientInterface $client Client used for the upload.
57 * @param string|array $source Location of the data to be copied (in the
58 * form /<bucket>/<key>). If the key contains a '?'
59 * character, instead pass an array of source_key,
60 * source_bucket, and source_version_id.
61 * @param array $config Configuration used to perform the upload.
62 */
63 public function __construct(
64 S3ClientInterface $client,
65 $source,
66 array $config = []
67 ) {
68 if (is_array($source)) {
69 $this->source = $source;
70 } else {
71 $this->source = $this->getInputSource($source);
72 }
73
74 parent::__construct(
75 $client,
76 array_change_key_case($config) + ['source_metadata' => null]
77 );
78 }
79
80 /**
81 * An alias of the self::upload method.
82 *
83 * @see self::upload
84 */
85 public function copy()
86 {
87 return $this->upload();
88 }
89
90 protected function loadUploadWorkflowInfo()
91 {
92 return [
93 'command' => [
94 'initiate' => 'CreateMultipartUpload',
95 'upload' => 'UploadPartCopy',
96 'complete' => 'CompleteMultipartUpload',
97 ],
98 'id' => [
99 'bucket' => 'Bucket',
100 'key' => 'Key',
101 'upload_id' => 'UploadId',
102 ],
103 'part_num' => 'PartNumber',
104 ];
105 }
106
107 protected function getUploadCommands(callable $resultHandler)
108 {
109 $parts = ceil($this->getSourceSize() / $this->determinePartSize());
110
111 for ($partNumber = 1; $partNumber <= $parts; $partNumber++) {
112 // If we haven't already uploaded this part, yield a new part.
113 if (!$this->state->hasPartBeenUploaded($partNumber)) {
114 $command = $this->client->getCommand(
115 $this->info['command']['upload'],
116 $this->createPart($partNumber, $parts) + $this->getState()->getId()
117 );
118 $command->getHandlerList()->appendSign($resultHandler, 'mup');
119 yield $command;
120 }
121 }
122 }
123
124 private function createPart($partNumber, $partsCount)
125 {
126 $data = [];
127
128 // Apply custom params to UploadPartCopy data
129 $config = $this->getConfig();
130 $params = isset($config['params']) ? $config['params'] : [];
131 foreach ($params as $k => $v) {
132 $data[$k] = $v;
133 }
134 // The source parameter here is usually a string, but can be overloaded as an array
135 // if the key contains a '?' character to specify where the query parameters start
136 if (is_array($this->source)) {
137 $key = str_replace('%2F', '/', rawurlencode($this->source['source_key']));
138 $bucket = $this->source['source_bucket'];
139 } else {
140 list($bucket, $key) = explode('/', ltrim($this->source, '/'), 2);
141 $key = implode(
142 '/',
143 array_map(
144 'urlencode',
145 explode('/', rawurldecode($key))
146 )
147 );
148 }
149
150 $uri = ArnParser::isArn($bucket) ? '' : '/';
151 $uri .= $bucket . '/' . $key;
152 $data['CopySource'] = $uri;
153 $data['PartNumber'] = $partNumber;
154 if (!empty($this->sourceVersionId)) {
155 $data['CopySource'] .= "?versionId=" . $this->sourceVersionId;
156 }
157
158 $defaultPartSize = $this->determinePartSize();
159 $startByte = $defaultPartSize * ($partNumber - 1);
160 $data['ContentLength'] = $partNumber < $partsCount
161 ? $defaultPartSize
162 : $this->getSourceSize() - ($defaultPartSize * ($partsCount - 1));
163 $endByte = $startByte + $data['ContentLength'] - 1;
164 $data['CopySourceRange'] = "bytes=$startByte-$endByte";
165
166 return $data;
167 }
168
169 protected function extractETag(ResultInterface $result)
170 {
171 return $result->search('CopyPartResult.ETag');
172 }
173
174 protected function getSourceMimeType()
175 {
176 return $this->getSourceMetadata()['ContentType'];
177 }
178
179 protected function getSourceSize()
180 {
181 return $this->getSourceMetadata()['ContentLength'];
182 }
183
184 private function getSourceMetadata()
185 {
186 if (empty($this->sourceMetadata)) {
187 $this->sourceMetadata = $this->fetchSourceMetadata();
188 }
189
190 return $this->sourceMetadata;
191 }
192
193 private function fetchSourceMetadata()
194 {
195 if ($this->config['source_metadata'] instanceof ResultInterface) {
196 return $this->config['source_metadata'];
197 }
198 //if the source variable was overloaded with an array, use the inputs for key and bucket
199 if (is_array($this->source)) {
200 $headParams = [
201 'Key' => $this->source['source_key'],
202 'Bucket' => $this->source['source_bucket']
203 ];
204 if (isset($this->source['source_version_id'])) {
205 $this->sourceVersionId = $this->source['source_version_id'];
206 $headParams['VersionId'] = $this->sourceVersionId;
207 }
208 //otherwise, use the default source parsing behavior
209 } else {
210 list($bucket, $key) = explode('/', ltrim($this->source, '/'), 2);
211 $headParams = [
212 'Bucket' => $bucket,
213 'Key' => $key,
214 ];
215 if (strpos($key, '?')) {
216 list($key, $query) = explode('?', $key, 2);
217 $headParams['Key'] = $key;
218 $query = Psr7\Query::parse($query, false);
219 if (isset($query['versionId'])) {
220 $this->sourceVersionId = $query['versionId'];
221 $headParams['VersionId'] = $this->sourceVersionId;
222 }
223 }
224 }
225 return $this->client->headObject($headParams);
226 }
227
228 /**
229 * Get the url decoded input source, starting with a slash if it is not an
230 * ARN to standardize the source location syntax.
231 *
232 * @param string $inputSource The source that was passed to the constructor
233 * @return string The source, starting with a slash if it's not an arn
234 */
235 private function getInputSource($inputSource)
236 {
237 $sourceBuilder = ArnParser::isArn($inputSource) ? '' : '/';
238 $sourceBuilder .= ltrim(rawurldecode($inputSource), '/');
239 return $sourceBuilder;
240 }
241
242 }
243