S3 Batch / Parallel Upload Error with PHP SDK
Asked Answered
Y

1

7

I followed these codes to batch PutObject into S3. I am using the latest PHP SDK (3.x). But I am getting:

Argument 1 passed to Aws\AwsClient::execute() must implement interface Aws\CommandInterface, array given

$commands = array();
$commands[] = $s3->getCommand('PutObject', array(
    'Bucket' => $bucket,
    'Key'    => 'images/1.jpg',
    'Body' => base64_decode( 'xxx' ),
    'ACL' => 'public-read',
    'ContentType' => 'image/jpeg'
));

$commands[] = $s3->getCommand('PutObject', array(
    'Bucket' => $bucket,
    'Key'    => 'images/2.jpg',
    'Body' => base64_decode( 'xxx' ),
    'ACL' => 'public-read',
    'ContentType' => 'image/jpeg'
));

// Execute the commands in parallel
$s3->execute($commands);
Yate answered 10/7, 2015 at 6:38 Comment(0)
B
6

If you're using a modern version of the SDK, try building the command this way, instead. Taken straight from the docs; it should work. This is called the "chaining" method.

$commands = array();


$commands[] = $s3->getCommand('PutObject')
                ->set('Bucket', $bucket)
                ->set('Key', 'images/1.jpg')
                ->set('Body', base64_decode('xxx'))
                ->set('ACL', 'public-read')
                ->set('ContentType', 'image/jpeg');

$commands[] = $s3->getCommand('PutObject')
                ->set('Bucket', $bucket)
                ->set('Key', 'images/2.jpg')
                ->set('Body', base64_decode('xxx'))
                ->set('ACL', 'public-read')
                ->set('ContentType', 'image/jpeg');

// Execute the commands in parallel
$s3->execute($commands);

// Loop over the commands, which have now all been executed
foreach ($commands as $command)
{
    $result = $command->getResult();

    // Use the result.
}

Make sure you're using the latest version of the SDK.

Edit

It appears that the SDK's API has changed significantly in Version 3.x. The above example should work correctly in Version 2.x of the AWS SDK. For 3.x, you need to use CommandPool()s and promise():

$commands = array();

$commands[] = $s3->getCommand('PutObject', array(
    'Bucket' => $bucket,
    'Key'    => 'images/1.jpg',
    'Body' => base64_decode ( 'xxx' ),
    'ACL' => 'public-read',
    'ContentType' => 'image/jpeg'
));
$commands[] = $s3->getCommand('PutObject', array(
    'Bucket' => $bucket,
    'Key'    => 'images/2.jpg',
    'Body' => base64_decode ( 'xxx' ),
    'ACL' => 'public-read',
    'ContentType' => 'image/jpeg'
));


$pool = new CommandPool($s3, $commands);

// Initiate the pool transfers
$promise = $pool->promise();

// Force the pool to complete synchronously
try {
    $result = $promise->wait();
} catch (AwsException $e) {
    // handle the error.
}

Then, $result should be an array of command results.

Blancmange answered 10/7, 2015 at 7:24 Comment(10)
Isn't this the same as I have coded? The error is failing at $s3->execute($commands);Yate
The difference is the ->set() chaining rather than the array() of parameters. What version are you using?Blancmange
Didn't work. Using ## 3.0.4 - 2015-06-11. Call to undefined method Aws\Command::set()Yate
I just added a new example for AWS SDK 3.x. They've made significant changes. Let me know if this works for you.Blancmange
The example will still fail at ->set('Bucket', $bucket)??Yate
Sorry, an oversight on my part. Fixed!Blancmange
Sweet! How shall I get the ObjectURL for each object?Yate
I don't have an environment with the 3.0 SDK set up to test with, but, I believe $result will be an array of result arrays, so, something like $result[0]['ObjectURL'] for the first one, and so on. Maybe var_dump() out $result to see what it contains, as I'm not totally sure about this part.Blancmange
var_dump($result); shows NULL. will try to google :)Yate
What happens if you change $promise->wait() to $promise->wait(true)?Blancmange

© 2022 - 2024 — McMap. All rights reserved.