123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- <?php
- namespace Aws\Glacier;
- use Aws\CommandInterface;
- use Aws\HashingStream;
- use Aws\Multipart\AbstractUploader;
- use Aws\Multipart\UploadState;
- use Aws\PhpHash;
- use Aws\ResultInterface;
- use GuzzleHttp\Psr7;
- use Psr\Http\Message\StreamInterface as Stream;
- class MultipartUploader extends AbstractUploader
- {
- const PART_MIN_SIZE = 1048576;
- private static $validPartSizes = [
- 1048576,
- 2097152,
- 4194304,
- 8388608,
- 16777216,
- 33554432,
- 67108864,
- 134217728,
- 268435456,
- 536870912,
- 1073741824,
- 2147483648,
- 4294967296,
- ];
-
- public static function getStateFromService(
- GlacierClient $client,
- $vaultName,
- $uploadId,
- $accountId = '-'
- ) {
- $state = new UploadState([
- 'accountId' => $accountId,
- 'vaultName' => $vaultName,
- 'uploadId' => $uploadId,
- ]);
- foreach ($client->getPaginator('ListParts', $state->getId()) as $result) {
-
- if (!$state->getPartSize()) {
- $state->setPartSize($result['PartSizeInBytes']);
- }
-
- foreach ($result['Parts'] as $part) {
- list($rangeIndex, $rangeSize) = self::parseRange(
- $part['RangeInBytes'],
- $state->getPartSize()
- );
- $state->markPartAsUploaded($rangeIndex, [
- 'size' => $rangeSize,
- 'checksum' => $part['SHA256TreeHash'],
- ]);
- }
- }
- $state->setStatus(UploadState::INITIATED);
- return $state;
- }
-
- public function __construct(GlacierClient $client, $source, array $config = [])
- {
- parent::__construct($client, $source, $config + [
- 'account_id' => '-',
- 'vault_name' => null,
- ]);
- }
- protected function loadUploadWorkflowInfo()
- {
- return [
- 'command' => [
- 'initiate' => 'InitiateMultipartUpload',
- 'upload' => 'UploadMultipartPart',
- 'complete' => 'CompleteMultipartUpload',
- ],
- 'id' => [
- 'account_id' => 'accountId',
- 'vault_name' => 'vaultName',
- 'upload_id' => 'uploadId',
- ],
- 'part_num' => 'range',
- ];
- }
- protected function determinePartSize()
- {
-
- $partSize = $this->config['part_size'] ?: self::PART_MIN_SIZE;
-
- if (!in_array($partSize, self::$validPartSizes)) {
- throw new \InvalidArgumentException('The part_size must be a power '
- . 'of 2, in megabytes, such that 1 MB <= PART_SIZE <= 4 GB.');
- }
- return $partSize;
- }
- protected function createPart($seekable, $number)
- {
- $data = [];
- $firstByte = $this->source->tell();
-
-
- if ($seekable) {
-
- $body = Psr7\Utils::tryFopen($this->source->getMetadata('uri'), 'r');
- $body = $this->limitPartStream(Psr7\Utils::streamFor($body));
-
-
- $decoratedBody = $this->decorateWithHashes($body, $data);
- while (!$decoratedBody->eof()) $decoratedBody->read(1048576);
-
- $this->source->seek($this->source->tell() + $body->getSize());
- } else {
-
- $source = $this->limitPartStream($this->source);
- $source = $this->decorateWithHashes($source, $data);
- $body = Psr7\Utils::streamFor();
- Psr7\Utils::copyToStream($source, $body);
- }
-
- if ($body->getSize() === 0) {
- return false;
- }
- $body->seek(0);
- $data['body'] = $body;
- $lastByte = $this->source->tell() - 1;
- $data['range'] = "bytes {$firstByte}-{$lastByte}/*";
- return $data;
- }
- protected function handleResult(CommandInterface $command, ResultInterface $result)
- {
- list($rangeIndex, $rangeSize) = $this->parseRange(
- $command['range'],
- $this->state->getPartSize()
- );
- $this->state->markPartAsUploaded($rangeIndex, [
- 'size' => $rangeSize,
- 'checksum' => $command['checksum']
- ]);
- }
- protected function getInitiateParams()
- {
- $params = ['partSize' => $this->state->getPartSize()];
- if (isset($this->config['archive_description'])) {
- $params['archiveDescription'] = $this->config['archive_description'];
- }
- return $params;
- }
- protected function getCompleteParams()
- {
- $treeHash = new TreeHash();
- $archiveSize = 0;
- foreach ($this->state->getUploadedParts() as $part) {
- $archiveSize += $part['size'];
- $treeHash->addChecksum($part['checksum']);
- }
- return [
- 'archiveSize' => $archiveSize,
- 'checksum' => bin2hex($treeHash->complete()),
- ];
- }
-
- private function decorateWithHashes(Stream $stream, array &$data)
- {
-
- $stream = new HashingStream($stream, new TreeHash(),
- function ($result) use (&$data) {
- $data['checksum'] = bin2hex($result);
- }
- );
-
- $stream = new HashingStream($stream, new PhpHash('sha256'),
- function ($result) use (&$data) {
- $data['ContentSHA256'] = bin2hex($result);
- }
- );
- return $stream;
- }
-
- private static function parseRange($range, $partSize)
- {
-
- if (strpos($range, 'bytes') !== false) {
- $range = substr($range, 6, -2);
- }
-
- list($firstByte, $lastByte) = explode('-', $range);
-
- return [
- intval($firstByte / $partSize) + 1,
- $lastByte - $firstByte + 1,
- ];
- }
- }
|