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\Api\Parser\PayloadParserTrait;
5
use Aws\CommandInterface;
6
use Aws\Exception\AwsException;
7
use Aws\HandlerList;
8
use Aws\ResultInterface;
9
use Aws\S3\Exception\PermanentRedirectException;
10
use Aws\S3\Exception\S3Exception;
11
use GuzzleHttp\Promise\PromiseInterface;
12
use GuzzleHttp\Promise\RejectedPromise;
13
use Psr\Http\Message\ResponseInterface;
14
 
15
/**
16
 * A trait providing S3-specific functionality. This is meant to be used in
17
 * classes implementing \Aws\S3\S3ClientInterface
18
 */
19
trait S3ClientTrait
20
{
21
    use PayloadParserTrait;
22
 
23
    /**
24
     * @see S3ClientInterface::upload()
25
     */
26
    public function upload(
27
        $bucket,
28
        $key,
29
        $body,
30
        $acl = 'private',
31
        array $options = []
32
    ) {
33
        return $this
34
            ->uploadAsync($bucket, $key, $body, $acl, $options)
35
            ->wait();
36
    }
37
 
38
    /**
39
     * @see S3ClientInterface::uploadAsync()
40
     */
41
    public function uploadAsync(
42
        $bucket,
43
        $key,
44
        $body,
45
        $acl = 'private',
46
        array $options = []
47
    ) {
48
        return (new ObjectUploader($this, $bucket, $key, $body, $acl, $options))
49
            ->promise();
50
    }
51
 
52
    /**
53
     * @see S3ClientInterface::copy()
54
     */
55
    public function copy(
56
        $fromB,
57
        $fromK,
58
        $destB,
59
        $destK,
60
        $acl = 'private',
61
        array $opts = []
62
    ) {
63
        return $this->copyAsync($fromB, $fromK, $destB, $destK, $acl, $opts)
64
            ->wait();
65
    }
66
 
67
    /**
68
     * @see S3ClientInterface::copyAsync()
69
     */
70
    public function copyAsync(
71
        $fromB,
72
        $fromK,
73
        $destB,
74
        $destK,
75
        $acl = 'private',
76
        array $opts = []
77
    ) {
78
        $source = [
79
            'Bucket' => $fromB,
80
            'Key' => $fromK,
81
        ];
82
        if (isset($opts['version_id'])) {
83
            $source['VersionId'] = $opts['version_id'];
84
        }
85
        $destination = [
86
            'Bucket' => $destB,
87
            'Key' => $destK
88
        ];
89
 
90
        return (new ObjectCopier($this, $source, $destination, $acl, $opts))
91
            ->promise();
92
    }
93
 
94
    /**
95
     * @see S3ClientInterface::registerStreamWrapper()
96
     */
97
    public function registerStreamWrapper()
98
    {
99
        StreamWrapper::register($this);
100
    }
101
 
102
    /**
103
     * @see S3ClientInterface::registerStreamWrapperV2()
104
     */
105
    public function registerStreamWrapperV2()
106
    {
107
        StreamWrapper::register(
108
            $this,
109
            's3',
110
            null,
111
            true
112
        );
113
    }
114
 
115
    /**
116
     * @see S3ClientInterface::deleteMatchingObjects()
117
     */
118
    public function deleteMatchingObjects(
119
        $bucket,
120
        $prefix = '',
121
        $regex = '',
122
        array $options = []
123
    ) {
124
        $this->deleteMatchingObjectsAsync($bucket, $prefix, $regex, $options)
125
            ->wait();
126
    }
127
 
128
    /**
129
     * @see S3ClientInterface::deleteMatchingObjectsAsync()
130
     */
131
    public function deleteMatchingObjectsAsync(
132
        $bucket,
133
        $prefix = '',
134
        $regex = '',
135
        array $options = []
136
    ) {
137
        if (!$prefix && !$regex) {
138
            return new RejectedPromise(
139
                new \RuntimeException('A prefix or regex is required.')
140
            );
141
        }
142
 
143
        $params = ['Bucket' => $bucket, 'Prefix' => $prefix];
144
        $iter = $this->getIterator('ListObjects', $params);
145
 
146
        if ($regex) {
147
            $iter = \Aws\filter($iter, function ($c) use ($regex) {
148
                return preg_match($regex, $c['Key']);
149
            });
150
        }
151
 
152
        return BatchDelete::fromIterator($this, $bucket, $iter, $options)
153
            ->promise();
154
    }
155
 
156
    /**
157
     * @see S3ClientInterface::uploadDirectory()
158
     */
159
    public function uploadDirectory(
160
        $directory,
161
        $bucket,
162
        $keyPrefix = null,
163
        array $options = []
164
    ) {
165
        $this->uploadDirectoryAsync($directory, $bucket, $keyPrefix, $options)
166
            ->wait();
167
    }
168
 
169
    /**
170
     * @see S3ClientInterface::uploadDirectoryAsync()
171
     */
172
    public function uploadDirectoryAsync(
173
        $directory,
174
        $bucket,
175
        $keyPrefix = null,
176
        array $options = []
177
    ) {
178
        $d = "s3://$bucket" . ($keyPrefix ? '/' . ltrim($keyPrefix, '/') : '');
179
        return (new Transfer($this, $directory, $d, $options))->promise();
180
    }
181
 
182
    /**
183
     * @see S3ClientInterface::downloadBucket()
184
     */
185
    public function downloadBucket(
186
        $directory,
187
        $bucket,
188
        $keyPrefix = '',
189
        array $options = []
190
    ) {
191
        $this->downloadBucketAsync($directory, $bucket, $keyPrefix, $options)
192
            ->wait();
193
    }
194
 
195
    /**
196
     * @see S3ClientInterface::downloadBucketAsync()
197
     */
198
    public function downloadBucketAsync(
199
        $directory,
200
        $bucket,
201
        $keyPrefix = '',
202
        array $options = []
203
    ) {
204
        $s = "s3://$bucket" . ($keyPrefix ? '/' . ltrim($keyPrefix, '/') : '');
205
        return (new Transfer($this, $s, $directory, $options))->promise();
206
    }
207
 
208
    /**
209
     * @see S3ClientInterface::determineBucketRegion()
210
     */
211
    public function determineBucketRegion($bucketName)
212
    {
213
        return $this->determineBucketRegionAsync($bucketName)->wait();
214
    }
215
 
216
    /**
217
     * @see S3ClientInterface::determineBucketRegionAsync()
218
     *
219
     * @param string $bucketName
220
     *
221
     * @return PromiseInterface
222
     */
223
    public function determineBucketRegionAsync($bucketName)
224
    {
225
        $command = $this->getCommand('HeadBucket', ['Bucket' => $bucketName]);
226
        $handlerList = clone $this->getHandlerList();
227
        $handlerList->remove('s3.permanent_redirect');
228
        $handlerList->remove('signer');
229
        $handler = $handlerList->resolve();
230
 
231
        return $handler($command)
232
            ->then(static function (ResultInterface $result) {
233
                return $result['@metadata']['headers']['x-amz-bucket-region'];
234
            }, function (AwsException $e) {
235
                $response = $e->getResponse();
236
                if ($response === null) {
237
                    throw $e;
238
                }
239
 
240
                if ($e->getAwsErrorCode() === 'AuthorizationHeaderMalformed') {
241
                    $region = $this->determineBucketRegionFromExceptionBody(
242
                        $response
243
                    );
244
                    if (!empty($region)) {
245
                        return $region;
246
                    }
247
                    throw $e;
248
                }
249
 
250
                return $response->getHeaderLine('x-amz-bucket-region');
251
            });
252
    }
253
 
254
    private function determineBucketRegionFromExceptionBody(ResponseInterface $response)
255
    {
256
        try {
257
            $element = $this->parseXml($response->getBody(), $response);
258
            if (!empty($element->Region)) {
259
                return (string)$element->Region;
260
            }
261
        } catch (\Exception $e) {
262
            // Fallthrough on exceptions from parsing
263
        }
264
        return false;
265
    }
266
 
267
    /**
268
     * @see S3ClientInterface::doesBucketExist()
269
     */
270
    public function doesBucketExist($bucket)
271
    {
272
        return $this->checkExistenceWithCommand(
273
            $this->getCommand('HeadBucket', ['Bucket' => $bucket])
274
        );
275
    }
276
 
277
    /**
278
     * @see S3ClientInterface::doesBucketExistV2()
279
     */
280
    public function doesBucketExistV2($bucket, $accept403 = false)
281
    {
282
        $command = $this->getCommand('HeadBucket', ['Bucket' => $bucket]);
283
 
284
        try {
285
            $this->execute($command);
286
            return true;
287
        } catch (S3Exception $e) {
288
            if (
289
                ($accept403 && $e->getStatusCode() === 403)
290
                || $e instanceof PermanentRedirectException
291
            ) {
292
                return true;
293
            }
294
            if ($e->getStatusCode() === 404)  {
295
                return false;
296
            }
297
            throw $e;
298
        }
299
    }
300
 
301
    /**
302
     * @see S3ClientInterface::doesObjectExist()
303
     */
304
    public function doesObjectExist($bucket, $key, array $options = [])
305
    {
306
        return $this->checkExistenceWithCommand(
307
            $this->getCommand('HeadObject', [
308
                    'Bucket' => $bucket,
309
                    'Key'    => $key
310
                ] + $options)
311
        );
312
    }
313
 
314
    /**
315
     * @see S3ClientInterface::doesObjectExistV2()
316
     */
317
    public function doesObjectExistV2(
318
        $bucket,
319
        $key,
320
        $includeDeleteMarkers = false,
321
        array $options = []
322
    ){
323
        $command = $this->getCommand('HeadObject', [
324
                'Bucket' => $bucket,
325
                'Key'    => $key
326
            ] + $options
327
        );
328
 
329
        try {
330
            $this->execute($command);
331
            return true;
332
        } catch (S3Exception $e) {
333
            if ($includeDeleteMarkers
334
                && $this->useDeleteMarkers($e)
335
            ) {
336
                return true;
337
            }
338
            if ($e->getStatusCode() === 404) {
339
                return false;
340
            }
341
            throw $e;
342
        }
343
    }
344
 
345
    private function useDeleteMarkers($exception)
346
    {
347
        $response = $exception->getResponse();
348
        return !empty($response)
349
            && $response->getHeader('x-amz-delete-marker');
350
    }
351
 
352
    /**
353
     * Determines whether or not a resource exists using a command
354
     *
355
     * @param CommandInterface $command Command used to poll for the resource
356
     *
357
     * @return bool
358
     * @throws S3Exception|\Exception if there is an unhandled exception
359
     */
360
    private function checkExistenceWithCommand(CommandInterface $command)
361
    {
362
        try {
363
            $this->execute($command);
364
            return true;
365
        } catch (S3Exception $e) {
366
            if ($e->getAwsErrorCode() == 'AccessDenied') {
367
                return true;
368
            }
369
            if ($e->getStatusCode() >= 500) {
370
                throw $e;
371
            }
372
            return false;
373
        }
374
    }
375
 
376
    /**
377
     * @see S3ClientInterface::execute()
378
     */
379
    abstract public function execute(CommandInterface $command);
380
 
381
    /**
382
     * @see S3ClientInterface::getCommand()
383
     */
384
    abstract public function getCommand($name, array $args = []);
385
 
386
    /**
387
     * @see S3ClientInterface::getHandlerList()
388
     *
389
     * @return HandlerList
390
     */
391
    abstract public function getHandlerList();
392
 
393
    /**
394
     * @see S3ClientInterface::getIterator()
395
     *
396
     * @return \Iterator
397
     */
398
    abstract public function getIterator($name, array $args = []);
399
}