Search code examples
amazon-s3aws-sdkaws-php-sdk

S3 Batch / Parallel Upload Error with PHP SDK


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);

Solution

  • 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.