Как загрузить большие архивы в Amazon Glacier, используя PHP и aws-sdk v3?

Я впервые работаю с Amazon. Я пытаюсь загрузить несколько файлов в Amazon Glacier с помощью PHP SDK V3. Затем файлы должны быть объединены Amazon в один.

Файлы хранятся в домашнем каталоге cPanel и должны быть загружены через задание cron в Amazon Glacier.

Я знаю, что должен использовать метод загрузки нескольких частей, но я не совсем уверен, какие другие функции необходимы для его работы. Я также не уверен, правильно ли я рассчитал и передал переменные.

Это код, который я получил до сих пор:

<?php
require 'aws-autoloader.php';

use Aws\Glacier\GlacierClient;
use Aws\Glacier\TreeHash;

//############################################
//DEFAULT VARIABLES
//############################################
$key = 'XXXXXXXXXXXXXXXXXXXX';
$secret = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
$accountId = '123456789123';
$vaultName = 'VaultName';
$partSize = '4194304';
$fileLocation = 'path/to/files/';

//############################################
//DECLARE THE AMAZON CLIENT
//############################################
$client = new GlacierClient([
'region' => 'us-west-2',
'version' => '2012-06-01',
'credentials' => array(
'key'    => $key,
'secret' => $secret,
)
]);

//############################################
//GET THE UPLOAD ID
//############################################
$result = $client->initiateMultipartUpload([
'partSize' => $partSize,
'vaultName' => $vaultName
]);
$uploadId = $result['uploadId'];

//############################################
//GET ALL FILES INTO AN ARRAY
//############################################
$files = scandir($fileLocation);
unset($files[0]);
unset($files[1]);
sort($files);

//############################################
//GET SHA256 TREE HASH (CHECKSUM)
//############################################
$th = new TreeHash();
//GET TOTAL FILE SIZE
foreach($files as $part){
$filesize = filesize($fileLocation.$part);
$total = $filesize;
$th = $th->update(file_get_contents($fileLocation.$part));
}
$totalchecksum = $th->complete();

//############################################
//UPLOAD FILES
//############################################
foreach ($files as $key => $part) {
//HASH CONTENT
$filesize = filesize($fileLocation.$part);
$rangeSize = $filesize-1;
$range = 'bytes 0-'.$rangeSize.'/*';
$sourcefile = $fileLocation.$part;

$result = $client->uploadMultipartPart([
'accountId' => $accountId,
'checksum' => '',
'range' => $range,
'sourceFile' => $sourcefile,
'uploadId' => $uploadId,
'vaultName' => $vaultName
]);
}

//############################################
//COMPLETE MULTIPART UPLOAD
//############################################
$result = $client->completeMultipartUpload([
'accountId' => $accountId,
'archiveSize' => $total,
'checksum' => $totalchecksum,
'uploadId' => $uploadId,
'vaultName' => $vaultName,
]);
?>

Кажется, что объявление нового клиента Glacier работает, и я получаю UploadID, но с остальным я не на 100%, если я делаю это правильно. Хранилище Amazon Glacier Vault, куда файлы нужно загрузить, а затем объединить, остается пустым, и я не уверен, будут ли файлы отображать только те файлы, которые CompleteMultipartUpload успешно выполнил.

Я также получаю следующую ошибку при запуске кода:

Неустранимая ошибка: необработанное исключение
«Aws \ Glacier \ Exception \ GlacierException» с сообщением «Ошибка выполнения
«CompleteMultipartUpload» в
«https://glacier.us-west-2.amazonaws.com/XXXXXXXXXXXX/vaults/XXXXXXXXXX/multipart-uploads/cTI0Yfk6xBYIQ0V-rhq6AcdHqd3iivRJfyYzK6-NV1yn9GQvJyYCoSrXrrrx4kfyGm6m9PUEAq4M0x6duXm5MD8abn-M«;
Ошибка HTTP AWS: ошибка клиента: 403 InvalidSignatureException (client):
Рассчитанная нами подпись запроса не соответствует вашей подписи
предоставлена. Проверьте свой секретный ключ доступа AWS и метод подписи. советоваться
Сервисная документация для деталей. Каноническая строка для этого
запрос должен был быть ‘POST
/ XXXXXXXXXXX / своды / XXXXXXXXX / многокомпонентные-добавления / cTI0Yfk6xBYIQ0V-rhq6AcdHqd3iivRJfyYzK6-NV1yn9GQvJyYCoSrXrrrx4kfyGm6m9PUEAq4M0x6duXm5MD8abn-M
хост: glacier.us-west-2.amazonaws.com x-amz-archive-size: 1501297
x-amz-date: 20151016T081455Z x-amz-glacier-version: 2012-06-01
x-amz-sha256-tree-hash:? [qiuã ° ²åÁ¹ý + ¤Üª? ¤? [; K & times; T
хост; x-amz-archive-size; x-amz-date; x-amz-glacier-version; x-am in
/home/XXXXXXXXXXXX/public_html/XXXXXXXXXXX/Aws/WrappedHttpHandler.php
по линии 152

Может быть, есть более простой способ сделать это? У меня есть полный доступ к SSH, если это поможет.

0

Решение

Я думаю, что вы неправильно поняли uploadMultipartPart.
uploadMultipartPart означает, что вы загружаете 1 большой файл, состоящий из нескольких частей.
а затем выполните completeMultipartUpload, чтобы отметить, что вы завершили загрузку одного файла.

из вашего кода похоже, что вы загружаете несколько файлов.

Возможно, вам не нужно использовать uploadMultipartPart.

Может быть, вы могли бы использовать обычный «uploadArchive»?

ссылка:

https://blogs.aws.amazon.com/php/post/Tx7PFHT4OJRJ42/Uploading-Archives-to-Amazon-Glacier-from-PHP

1

Другие решения

Мне удалось это сделать в PHP SDK V3 (версия 3), и я продолжал находить этот вопрос в своих исследованиях, поэтому я решил опубликовать свое решение тоже. Используйте на свой страх и риск, и при этом очень мало проверок или обработки ошибок.

<?php
require 'vendor/autoload.php';

use Aws\Glacier\GlacierClient;
use Aws\Glacier\TreeHash;


// Create the glacier client to connect with
$glacier = new GlacierClient(array(
'profile' => 'default',
'region' => 'us-east-1',
'version' => '2012-06-01'
));

$fileName = '17mb_test_file';         // this is the file to upload
$chunkSize = 1024 * 1024 * pow(2,2);  // 1 MB times a power of 2
$fileSize = filesize($fileName);      // we will need the file size (in bytes)

// initiate the multipart upload
// it is dangerous to send the filename without escaping it first
$result = $glacier->initiateMultipartUpload(array(
'archiveDescription' => 'A multipart-upload for file: '.$fileName,
'partSize' => $chunkSize,
'vaultName' => 'MyVault'
));

// we need the upload ID when uploading the parts
$uploadId = $result['uploadId'];

// we need to generate the SHA256 tree hash
// open the file so we can get a hash from its contents
$fp = fopen($fileName, 'r');
// This class can generate the hash
$th = new TreeHash();
// feed in all of the data
$th->update(fread($fp, $fileSize));
// generate the hash (this comes out as binary data)...
$hash = $th->complete();
// but the API needs hex (thanks). PHP to the rescue!
$hash = bin2hex($hash);

// reset the file position indicator
fseek($fp, 0);

// the part counter
$partNumber = 0;

print("Uploading: '".$fileName
."' (".$fileSize." bytes) in ".(ceil($fileSize/$chunkSize))." parts...\n");
while ($partNumber * $chunkSize < ($fileSize + 1))
{
// while we haven't written everything out yet
// figure out the offset for the first and last byte of this chunk
$firstByte = $partNumber * $chunkSize;
// the last byte for this piece is either the last byte in this chunk, or
// the end of the file, whichever is less
// (watch for those Obi-Wan errors)
$lastByte = min((($partNumber + 1) * $chunkSize) - 1, $fileSize - 1);

// upload the next piece
$result = $glacier->uploadMultipartPart(array(
'body' => fread($fp, $chunkSize),  // read the next chunk
'uploadId' => $uploadId,          // the multipart upload this is for
'vaultName' => 'MyVault',
'range' => 'bytes '.$firstByte.'-'.$lastByte.'/*' // weird string
));

// this is where one would check the results for error.
// This is left as an exercise for the reader ;)

// onto the next piece
$partNumber++;
print("\tpart ".$partNumber." uploaded...\n");
}
print("...done\n");

// and now we can close off this upload
$result = $glacier->completeMultipartUpload(array(
'archiveSize' => $fileSize,         // the total file size
'uploadId' => $uploadId,            // the upload id
'vaultName' => 'MyVault',
'checksum' => $hash                 // here is where we need the tree hash
));

// this is where one would check the results for error.
// This is left as an exercise for the reader ;)


// get the archive id.
// You will need this to refer to this upload in the future.
$archiveId = $result->get('archiveId');

print("The archive Id is: ".$archiveId."\n");


?>
1