| 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;
 
- /**
 
-  * Encapsulates the execution of a multipart upload to Glacier.
 
-  */
 
- class MultipartUploader extends AbstractUploader
 
- {
 
-     const PART_MIN_SIZE = 1048576;
 
-     private static $validPartSizes = [
 
-         1048576,    //   1 MB
 
-         2097152,    //   2 MB
 
-         4194304,    //   4 MB
 
-         8388608,    //   8 MB
 
-         16777216,   //  16 MB
 
-         33554432,   //  32 MB
 
-         67108864,   //  64 MB
 
-         134217728,  // 128 MB
 
-         268435456,  // 256 MB
 
-         536870912,  // 512 MB
 
-         1073741824, //   1 GB
 
-         2147483648, //   2 GB
 
-         4294967296, //   4 GB
 
-     ];
 
-     /**
 
-      * Creates an UploadState object for a multipart upload by querying the
 
-      * service for the specified upload's information.
 
-      *
 
-      * @param GlacierClient $client    GlacierClient object to use.
 
-      * @param string        $vaultName Vault name for the multipart upload.
 
-      * @param string        $uploadId  Upload ID for the multipart upload.
 
-      * @param string        $accountId Account ID for the multipart upload.
 
-      *
 
-      * @return UploadState
 
-      */
 
-     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) {
 
-             // Get the part size from the first part in the first result.
 
-             if (!$state->getPartSize()) {
 
-                 $state->setPartSize($result['PartSizeInBytes']);
 
-             }
 
-             // Mark all the parts returned by ListParts as uploaded.
 
-             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;
 
-     }
 
-     /**
 
-      * Creates a multipart upload for a Glacier archive.
 
-      *
 
-      * The valid configuration options are as follows:
 
-      *
 
-      * - account_id: (string, default=string('-')) Account ID for the archive
 
-      *   being uploaded, if different from the account making the request.
 
-      * - archive_description: (string) Description of the archive.
 
-      * - before_complete: (callable) Callback to invoke before the
 
-      *   `CompleteMultipartUpload` operation. The callback should have a
 
-      *   function signature like `function (Aws\Command $command) {...}`.
 
-      * - before_initiate: (callable) Callback to invoke before the
 
-      *   `InitiateMultipartUpload` operation. The callback should have a
 
-      *   function signature like `function (Aws\Command $command) {...}`.
 
-      * - before_upload: (callable) Callback to invoke before any
 
-      *   `UploadMultipartPart` operations. The callback should have a function
 
-      *   signature like `function (Aws\Command $command) {...}`.
 
-      * - concurrency: (int, default=int(3)) Maximum number of concurrent
 
-      *   `UploadMultipartPart` operations allowed during the multipart upload.
 
-      * - part_size: (int, default=int(1048576)) Part size, in bytes, to use when
 
-      *   doing a multipart upload. This must between 1 MB and 4 GB, and must be
 
-      *   a power of 2 (in megabytes).
 
-      * - prepare_data_source: (callable) Callback to invoke before starting the
 
-      *   multipart upload workflow. The callback should have a function
 
-      *   signature like `function () {...}`.
 
-      * - state: (Aws\Multipart\UploadState) An object that represents the state
 
-      *   of the multipart upload and that is used to resume a previous upload.
 
-      *   When this options is provided, the `account_id`, `key`, and `part_size`
 
-      *   options are ignored.
 
-      * - vault_name: (string, required) Vault name to use for the archive being
 
-      *   uploaded.
 
-      *
 
-      * @param GlacierClient $client Client used for the upload.
 
-      * @param mixed         $source Source of the data to upload.
 
-      * @param array         $config Configuration used to perform the upload.
 
-      */
 
-     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()
 
-     {
 
-         // Make sure the part size is set.
 
-         $partSize = $this->config['part_size'] ?: self::PART_MIN_SIZE;
 
-         // Ensure that the part size is valid.
 
-         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();
 
-         // Read from the source to create the body stream. This also
 
-         // calculates the linear and tree hashes as the data is read.
 
-         if ($seekable) {
 
-             // Case 1: Stream is seekable, can make stream from new handle.
 
-             $body = Psr7\Utils::tryFopen($this->source->getMetadata('uri'), 'r');
 
-             $body = $this->limitPartStream(Psr7\Utils::streamFor($body));
 
-             // Create another stream decorated with hashing streams and read
 
-             // through it, so we can get the hash values for the part.
 
-             $decoratedBody = $this->decorateWithHashes($body, $data);
 
-             while (!$decoratedBody->eof()) $decoratedBody->read(1048576);
 
-             // Seek the original source forward to the end of the range.
 
-             $this->source->seek($this->source->tell() + $body->getSize());
 
-         } else {
 
-             // Case 2: Stream is not seekable, must store part in temp stream.
 
-             $source = $this->limitPartStream($this->source);
 
-             $source = $this->decorateWithHashes($source, $data);
 
-             $body = Psr7\Utils::streamFor();
 
-             Psr7\Utils::copyToStream($source, $body);
 
-         }
 
-         // Do not create a part if the body size is zero.
 
-         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()),
 
-         ];
 
-     }
 
-     /**
 
-      * Decorates a stream with a tree AND linear sha256 hashing stream.
 
-      *
 
-      * @param Stream $stream Stream to decorate.
 
-      * @param array  $data   Data bag that results are injected into.
 
-      *
 
-      * @return Stream
 
-      */
 
-     private function decorateWithHashes(Stream $stream, array &$data)
 
-     {
 
-         // Make sure that a tree hash is calculated.
 
-         $stream = new HashingStream($stream, new TreeHash(),
 
-             function ($result) use (&$data) {
 
-                 $data['checksum'] = bin2hex($result);
 
-             }
 
-         );
 
-         // Make sure that a linear SHA256 hash is calculated.
 
-         $stream = new HashingStream($stream, new PhpHash('sha256'),
 
-             function ($result) use (&$data) {
 
-                 $data['ContentSHA256'] = bin2hex($result);
 
-             }
 
-         );
 
-         return $stream;
 
-     }
 
-     /**
 
-      * Parses a Glacier range string into a size and part number.
 
-      *
 
-      * @param string $range    Glacier range string (e.g., "bytes 5-5000/*")
 
-      * @param int    $partSize The chosen part size
 
-      *
 
-      * @return array
 
-      */
 
-     private static function parseRange($range, $partSize)
 
-     {
 
-         // Strip away the prefix and suffix.
 
-         if (strpos($range, 'bytes') !== false) {
 
-             $range = substr($range, 6, -2);
 
-         }
 
-         // Split that range into it's parts.
 
-         list($firstByte, $lastByte) = explode('-', $range);
 
-         // Calculate and return range index and range size
 
-         return [
 
-             intval($firstByte / $partSize) + 1,
 
-             $lastByte - $firstByte + 1,
 
-         ];
 
-     }
 
- }
 
 
  |