将大对象上传到Cloudfiles会返回不同的md5

时间:2014-07-31 22:20:09

标签: php cloud md5 rackspace-cloud php-opencloud

所以我有这个代码,我试图按照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 个答案:

答案 0 :(得分:0)

建议您仅将multipart uploads用于超过5GB 的文件。对于低于此阈值的文件,您可以使用常规uploadObject方法。

使用转移构建器时,它会将您的大文件分割成较小的片段(您提供部件大小)并同时上传每个片段。完成此过程后,将创建一个清单文件,其中包含所有这些段的列表。下载清单文件时,它会将它们全部整理在一起,实际上假装自己就是大文件。但它真的是一个组织者。

要回到回答您的问题,清单文件的ETag标头不会计算您的想法。您当前正在做的是获取整个700MB文件的MD5校验和,并将其与清单文件的MD5校验和进行比较。但这些都不具有可比性。引用documentation

  

ETag标头是通过获取每个段的ETag值,将它们连接在一起,然后返回结果的MD5校验和来计算的。

使用此DLO操作也有一些缺点需要注意:

  

无法保证端到端的完整性。最终的一致性模型意味着虽然您已上传了一个细分对象,但可能不会立即显示在容器列表中。如果在对象出现在容器中之前下载清单,则该对象将不是响应GET请求而返回的内容的一部分。

如果您认为传输中存在错误,可能是因为HTTP请求在此过程中失败了。您可以使用retry strategies(使用退避插件)重试失败的请求。

您还可以打开HTTP logging来检查每个网络事务以帮助调试。但是要小心,使用上面的方法将HTTP请求体(> 25MB)回显到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);

如您所见,您正在使用模板来指示输出的内容。有一个完整的模板变量列表here