Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
namespace Aws\S3;
3
 
4
use Aws\HashingStream;
5
use Aws\Multipart\AbstractUploader;
6
use Aws\PhpHash;
7
use Aws\ResultInterface;
8
use GuzzleHttp\Psr7;
9
use Psr\Http\Message\StreamInterface as Stream;
10
use Aws\S3\Exception\S3MultipartUploadException;
11
 
12
/**
13
 * Encapsulates the execution of a multipart upload to S3 or Glacier.
14
 */
15
class MultipartUploader extends AbstractUploader
16
{
17
    use MultipartUploadingTrait;
18
 
19
    const PART_MIN_SIZE = 5242880;
20
    const PART_MAX_SIZE = 5368709120;
21
    const PART_MAX_NUM = 10000;
22
 
23
    /**
24
     * Creates a multipart upload for an S3 object.
25
     *
26
     * The valid configuration options are as follows:
27
     *
28
     * - acl: (string) ACL to set on the object being upload. Objects are
29
     *   private by default.
30
     * - before_complete: (callable) Callback to invoke before the
31
     *   `CompleteMultipartUpload` operation. The callback should have a
32
     *   function signature like `function (Aws\Command $command) {...}`.
33
     * - before_initiate: (callable) Callback to invoke before the
34
     *   `CreateMultipartUpload` operation. The callback should have a function
35
     *   signature like `function (Aws\Command $command) {...}`.
36
     * - before_upload: (callable) Callback to invoke before any `UploadPart`
37
     *   operations. The callback should have a function signature like
38
     *   `function (Aws\Command $command) {...}`.
39
     * - bucket: (string, required) Name of the bucket to which the object is
40
     *   being uploaded, or an S3 access point ARN.
41
     * - concurrency: (int, default=int(5)) Maximum number of concurrent
42
     *   `UploadPart` operations allowed during the multipart upload.
43
     * - key: (string, required) Key to use for the object being uploaded.
44
     * - params: (array) An array of key/value parameters that will be applied
45
     *   to each of the sub-commands run by the uploader as a base.
46
     *   Auto-calculated options will override these parameters. If you need
47
     *   more granularity over parameters to each sub-command, use the before_*
48
     *   options detailed above to update the commands directly.
49
     * - part_size: (int, default=int(5242880)) Part size, in bytes, to use when
50
     *   doing a multipart upload. This must between 5 MB and 5 GB, inclusive.
51
     * - prepare_data_source: (callable) Callback to invoke before starting the
52
     *   multipart upload workflow. The callback should have a function
53
     *   signature like `function () {...}`.
54
     * - state: (Aws\Multipart\UploadState) An object that represents the state
55
     *   of the multipart upload and that is used to resume a previous upload.
56
     *   When this option is provided, the `bucket`, `key`, and `part_size`
57
     *   options are ignored.
1441 ariadna 58
     * - track_upload: (boolean) Set true to track status in 1/8th increments
59
     *   for upload.
1 efrain 60
     *
61
     * @param S3ClientInterface $client Client used for the upload.
62
     * @param mixed             $source Source of the data to upload.
63
     * @param array             $config Configuration used to perform the upload.
64
     */
65
    public function __construct(
66
        S3ClientInterface $client,
67
        $source,
68
        array $config = []
69
    ) {
70
        parent::__construct($client, $source, array_change_key_case($config) + [
71
            'bucket' => null,
72
            'key'    => null,
73
            'exception_class' => S3MultipartUploadException::class,
74
        ]);
1441 ariadna 75
 
76
        if ($this->displayProgress) {
77
            $this->getState()->setProgressThresholds($this->source->getSize());
78
        }
1 efrain 79
    }
80
 
81
    protected function loadUploadWorkflowInfo()
82
    {
83
        return [
84
            'command' => [
85
                'initiate' => 'CreateMultipartUpload',
86
                'upload'   => 'UploadPart',
87
                'complete' => 'CompleteMultipartUpload',
88
            ],
89
            'id' => [
90
                'bucket'    => 'Bucket',
91
                'key'       => 'Key',
92
                'upload_id' => 'UploadId',
93
            ],
94
            'part_num' => 'PartNumber',
95
        ];
96
    }
97
 
98
    protected function createPart($seekable, $number)
99
    {
100
        // Initialize the array of part data that will be returned.
101
        $data = [];
102
 
103
        // Apply custom params to UploadPart data
104
        $config = $this->getConfig();
105
        $params = isset($config['params']) ? $config['params'] : [];
106
        foreach ($params as $k => $v) {
107
            $data[$k] = $v;
108
        }
109
 
110
        $data['PartNumber'] = $number;
111
 
112
        // Read from the source to create the body stream.
113
        if ($seekable) {
114
            // Case 1: Source is seekable, use lazy stream to defer work.
115
            $body = $this->limitPartStream(
116
                new Psr7\LazyOpenStream($this->source->getMetadata('uri'), 'r')
117
            );
118
        } else {
119
            // Case 2: Stream is not seekable; must store in temp stream.
120
            $source = $this->limitPartStream($this->source);
121
            $source = $this->decorateWithHashes($source, $data);
122
            $body = Psr7\Utils::streamFor();
123
            Psr7\Utils::copyToStream($source, $body);
124
        }
125
 
126
        $contentLength = $body->getSize();
127
 
128
        // Do not create a part if the body size is zero.
129
        if ($contentLength === 0) {
130
            return false;
131
        }
132
 
133
        $body->seek(0);
134
        $data['Body'] = $body;
135
 
136
        if (isset($config['add_content_md5'])
137
            && $config['add_content_md5'] === true
138
        ) {
139
            $data['AddContentMD5'] = true;
140
        }
141
 
142
        $data['ContentLength'] = $contentLength;
143
 
144
        return $data;
145
    }
146
 
147
    protected function extractETag(ResultInterface $result)
148
    {
149
        return $result['ETag'];
150
    }
151
 
152
    protected function getSourceMimeType()
153
    {
154
        if ($uri = $this->source->getMetadata('uri')) {
155
            return Psr7\MimeType::fromFilename($uri)
156
                ?: 'application/octet-stream';
157
        }
158
    }
159
 
160
    protected function getSourceSize()
161
    {
162
        return $this->source->getSize();
163
    }
164
 
165
    /**
166
     * Decorates a stream with a sha256 linear hashing stream.
167
     *
168
     * @param Stream $stream Stream to decorate.
169
     * @param array  $data   Part data to augment with the hash result.
170
     *
171
     * @return Stream
172
     */
173
    private function decorateWithHashes(Stream $stream, array &$data)
174
    {
175
        // Decorate source with a hashing stream
176
        $hash = new PhpHash('sha256');
177
        return new HashingStream($stream, $hash, function ($result) use (&$data) {
178
            $data['ContentSHA256'] = bin2hex($result);
179
        });
180
    }
181
}