Загрузка большого объекта в Cloudfiles возвращает другой md5

Итак, у меня есть этот код, и я пытаюсь загрузить большие файлы в соответствии с https://github.com/rackspace/php-opencloud/blob/master/docs/userguide/ObjectStore/Storage/Object.md в Rackspace:

$src_path = 'pathtofile.zip'; //about 700MB
$md5_checksum = md5_file($src_path); //result is f210775ccff9b0e4f686ea49ac4932c2
$trans_opts = array(
      'name' => $md5_checksum,
      'concurrency' => 6,
      'partSize'    => 25000000
 );
$trans_opts['path'] = $src_path;
$transfer = $container->setupObjectTransfer($trans_opts);
$response = $transfer->upload();

Который якобы загружает файл просто отлично

Однако, когда я пытаюсь загрузить файл, как рекомендовано здесь, https://github.com/rackspace/php-opencloud/blob/master/docs/userguide/ObjectStore/USERGUIDE.md:

$name = 'f210775ccff9b0e4f686ea49ac4932c2';
$object = $container->getObject($name);
$objectContent = $object->getContent();
$pathtofile = 'destinationpathforfile.zip';
$objectContent->rewind();
$stream = $objectContent->getStream();
file_put_contents($pathtofile, $stream);
$md5 = md5_file($pathtofile);

Результат md5_file заканчивается тем, что он отличается от 'f210775ccff9b0e4f686ea49ac4932c2'.... более того, загруженный zip-файл оказывается недоступным / поврежденным

Что я сделал не так?

1 ответ

Решение

Рекомендуется использовать только несколько загрузок для файлов размером более 5 ГБ. Для файлов ниже этого порога вы можете использовать обычный метод uploadObject.

Когда вы используете построитель переноса, он разбивает ваш большой файл на более мелкие сегменты (вы указываете размер детали) и одновременно загружает каждый из них. Когда этот процесс завершен, создается файл манифеста, который содержит список всех этих сегментов. Когда вы загружаете файл манифеста, он объединяет их все вместе, фактически притворяясь большим файлом. Но это просто организатор.

Чтобы вернуться к ответу на ваш вопрос, заголовок ETag файла манифеста не рассчитывается, как вы думаете. В данный момент вы берете контрольную сумму MD5 всего файла размером 700 МБ и сравниваете ее с контрольной суммой MD5 файла манифеста. Но они не сопоставимы. Цитировать документацию:

заголовок ETag вычисляется путем взятия значения ETag каждого сегмента, объединения их вместе, а затем возврата контрольной суммы MD5 результата.

У этой операции DLO есть и недостатки, о которых вам необходимо знать:

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

Если вы считаете, что произошла ошибка при передаче, возможно, это связано с тем, что HTTP-запрос не удался. Вы можете использовать стратегии повтора (используя плагин backoff), чтобы повторить неудачные запросы.

Вы также можете включить ведение журнала HTTP, чтобы проверить каждую сетевую транзакцию, чтобы помочь с отладкой. Однако будьте осторожны, используя вышеприведенное с выводом тела HTTP-запроса (>25 МБ) в STDOUT. Вы можете использовать это вместо:

use Guzzle\Plugin\Log\LogPlugin;
use Guzzle\Log\ClosureLogAdapter;

$stream = fopen('php://output', 'w');

$logSubscriber = new LogPlugin(new ClosureLogAdapter(function($m) use ($stream) {
    fwrite($stream, $m . PHP_EOL);
}), "# Request:\n{url} {method}\n\n# Response:\n{code} {phrase}\n\n# Connect time: {connect_time}\n\n# Total time: {total_time}", false);

$client->addSubscriber($logSubscriber);

Как видите, вы используете шаблон, чтобы диктовать, что выводится. Здесь есть полный список переменных шаблона.

Другие вопросы по тегам