Php 如何将doesObjectExist()请求批处理到Amazon S3?

Php 如何将doesObjectExist()请求批处理到Amazon S3?,php,amazon-web-services,amazon-s3,Php,Amazon Web Services,Amazon S3,我需要检查S3中是否存在大量项中的每一项的一组键。(每组钥匙与大量物品中的一个有关) 我正在使用PHPSDK(v2) 目前我正在为每个键调用$client->doesObjectExist(BUCKET,$key),这是一个瓶颈(每次调用到S3的往返时间) 我更愿意做一些类似于$client->doesObjectExist(BUCKET,$batch)的事情,其中$batch=array($key1,$key2…$keyn),让客户端检查所有这些键,然后返回一个响应数组(或其他类似结构) 我遇

我需要检查S3中是否存在大量项中的每一项的一组键。(每组钥匙与大量物品中的一个有关)

我正在使用PHPSDK(v2)

目前我正在为每个键调用
$client->doesObjectExist(BUCKET,$key)
,这是一个瓶颈(每次调用到S3的往返时间)

我更愿意做一些类似于
$client->doesObjectExist(BUCKET,$batch)
的事情,其中
$batch=array($key1,$key2…$keyn)
,让客户端检查所有这些键,然后返回一个响应数组(或其他类似结构)


我遇到了一个“批处理api”,它听起来很有希望,但没有什么具体内容。我猜这可能只出现在v1sdk中。

进行批量检查以查看是否存在某些键的唯一方法是列出bucket中的对象

对于AWS,每个键最多可返回1000个键/调用,因此比对每个键执行
doesObjectExist
调用要快得多。但是,如果您有大量的键,并且只想检查其中的几个,那么列出bucket中的所有对象将是不实际的,因此在这种情况下,您唯一的选择仍然是单独检查每个对象


问题不在于PHPV2SDK缺少批量功能,而在于S3API没有实现这种批量处理

通过利用底层Guzzle库功能,您可以使用AWS SDK for PHP执行并行请求。由于
doesObjectExist
方法实际上在该引擎罩下执行
HeadObject
操作。可以通过执行以下操作来创建HeadObject命令组:

use Aws\S3\S3Client;
use Guzzle\Service\Exception\CommandTransferException;

function doObjectsExist(S3Client $s3, $bucket, array $objectKeys)
{
    $headObjectCommands = array();
    foreach ($objectKeys as $key) {
        $headObjectCommands[] = $s3->getCommand('HeadObject', array(
            'Bucket' => $bucket,
            'Key'    => $key
        ));
    }

    try {
        $s3->execute($headObjectCommands); // Executes in parallel
        return true;
    } catch (CommandTransferException $e) {
        return false;
    }
}

$s3 = S3Client::factory(array(
    'key'    => 'your_aws_access_key_id',
    'bucket' => 'your_aws_secret_key',
));
$bucket = 'your_bucket_name';
$objectKeys = array('object_key_1', 'object_key_2','object_key_3');

// Returns true only if ALL of the objects exist
echo doObjectsExist($s3, $bucket, $objectKeys) ? 'YES' : 'NO';
如果您需要来自响应的数据,而不仅仅是键是否存在,那么您可以更改try-catch块来执行类似的操作

try {
    $executedCommands = $s3->execute($headObjectCommands);
} catch (CommandTransferException $e) {
    $executedCommands = $e->getAllCommands();
}

// Do stuff with the command objects
foreach ($executedCommands as $command) {
    $exists = $command->getResponse()->isSuccessful() ? "YES" : "NO";
    echo "{$command['Bucket']}/{$command['Key']}: {$exists}\n";
}

在中提到了并行发送命令,但我也要看一看。

我是在Jeremy Lindblom的答案的基础上构建的

只想指出可以在每个命令上设置的
OnComplete
回调

$bucket = 'my-bucket';
$keys = array('page1.txt', 'page2.txt');

$commands = array();
foreach ($keys as $key) {
    $commands[] = $s3Client->getCommand('HeadObject', array('Bucket' => $bucket, 'Key' => $key))
        ->setOnComplete(
            function($command) use ($bucket, $key)
            {
                echo "\nBucket: $bucket\n";
                echo "\nKey: $key\n";

                // see http://goo.gl/pIWoYr for more detail on command objects
                var_dump($command->getResult());
            }
        );
}

try {
    $ex_commands = $s3Client->execute($commands);
}
catch (\Guzzle\Service\Exception\CommandTransferException $e) {
    $ex_commands = $e->getAllCommands();
}

// this is necesary; without this, the OnComplete handlers wouldn't get called (strange?!?)
foreach ($ex_commands as $command)
{
    $command->getResult();
}

如果有人能解释为什么我需要调用
$command->getResult()
来调用
OnComplete
处理程序,那就太好了。

谢谢,是的,我知道列表调用和1000键/调用限制;然而,问题是存储桶很大(有100万个密钥),并且不断变化,因此检索密钥列表并对照它进行检查是相当不切实际的(最终可能不会比当前的解决方案快!)如果实现并行检查的解决方案并确保启用持久连接,则可以大大加快检查速度。即使PHP不允许这样做,您也可以使用另一种编程语言,并以某种方式将其与PHP代码集成。非常感谢-这正是我想要的-我必须查看
$executedCommand->getResponse()->GetInfo()
返回的数组,以便最终将键与http代码结果匹配,但是你的回答给了我我需要的重要线索。谢谢@杰里米,
$command->setOnComplete(…)
是一种糟糕的方法吗。有关详细信息,请参见下面的答案。还想知道为什么调用
$command->getResult()
对于触发
OnComplete
处理程序至关重要。