Amazon S3 setting metadata fails using AWS SDK PHP v2 upload() - php

I'm having problems setting the "Metadata" option when uploading files to Amazon S3 using the AWS SDK PHP v2. The documentation that I'm reading for the upload() method states that the the 5th parameter is an array of options...
*$options Custom options used when executing commands: - params: Custom
parameters to use with the upload. The parameters must map to a
PutObject or InitiateMultipartUpload operation parameters. -
min_part_size: Minimum size to allow for each uploaded part when
performing a multipart upload. - concurrency: Maximum number of
concurrent multipart uploads. - before_upload: Callback to invoke
before each multipart upload. The callback will receive a
Guzzle\Common\Event object with context.*
My upload() code looks like this..
$upload = $client->upload(
'<BUCKETNAME>',
'metadatatest.upload.jpg',
fopen('metadatatest.jpg','r'),
'public-read',
array('Metadata' => array(
'SomeKeyString' => 'SomeValueString'
))
);
...and no meta data is set after upload.
If however I use putObject() as documented here, which I assume is a "lower level" method compared to upload()...
$putObject = $client->putObject(
array(
'Bucket' => '<BUCKETNAME>',
'Key' => 'metadatatest.putobject.jpg',
'Body' => file_get_contents('metadatatest.jpg'),
'ACL' => 'public-read',
'Metadata' => array(
'SomeKeyString' => 'SomeValueString'
)
)
);
The meta data is successfully returned when I call getObject() or view the file directly in my browser when uploaded using putObject()
$getObject = $client->getObject(
array(
'Bucket' => '<BUCKETNAME>',
'Key' => 'metadatatest.putobject.jpg'
)
);
I would prefer to use the $client->upload() method as the documentation states
Upload a file, stream, or string to a bucket. If the upload size exceeds the specified threshold, the upload will be performed using
parallel multipart uploads.
I'm not sure what I've missed?

There's really no difference in using upload() or putObject() if you don't do multipart uploads. You can have a look at the AWS PHP SDK source code but basically the upload method just calls putObject like this:
// Perform a simple PutObject operation
return $this->putObject(array(
'Bucket' => $bucket,
'Key' => $key,
'Body' => $body,
'ACL' => $acl
) + $options['params']);
This isn't very clear in the SDK documentation, but you need to send the last parameter as an array with the key params and its value being a second array with the Metadata key and value like this:
$upload = $client->upload(
'<BUCKETNAME>',
'metadatatest.upload.jpg',
fopen('metadatatest.jpg','r'),
'public-read',
array('params' => array(
'Metadata' => array(
'SomeKeyString' => 'SomeValueString'
)))
);
However, I you could just use the putObject call to achieve the same thing.

Related

Adding Metada and Options to S3 Objects when uploading a directory

I am successfully uploading folders to S3 using ->uploadDirectory(). Several hundred folders have 100's, or 1,000's of images contained within them with so using PutObject() for each file hardly seemed to make sense. The upload works, and all goes well, but the ACL, StorageClass, and metadata is not being included in the upload.
According to the docs at http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-s3.html#uploading-a-directory-to-a-bucket , the following code should accomplished this. It is further documented with the putObject() function that is also cited.
I can find no examples of this function using anything but a directory and bucket, so fail to see what might be wrong with it. Any ideas why the data in $options is being ignored?
$aws = Aws::factory('config.php');
$s3 = $aws->get('S3');
$dir = 'c:\myfolder\myfiles';
$bucket = 'mybucket;
$keyPrefix = "ABC/myfiles/";
$options = array(
'ACL' => 'public-read',
'StorageClass' => 'REDUCED_REDUNDANCY',
'Metadata'=> array(
'MyVal1'=>'Something',
'MyVal2'=>'Something else'
)
);
$result = $s3->uploadDirectory($dir, $bucket, $keyPrefix, $options);
Parameters to provide to putObject or createMultipartUpload should be in the params option, not provided as top-level values in the options array. Try declaring your options as follows:
$options = array(
'params' => array(
'ACL' => 'public-read',
'StorageClass' => 'REDUCED_REDUNDANCY',
'Metadata'=> array(
'MyVal1'=>'Something',
'MyVal2'=>'Something else',
),
),
);

AWS Lambda PHP Create Function with Zip

I'm trying to create a PHP script that creates a function from some code that i zip up on our server. I uploaded the file manually to lambda, and it works fine. But when i try to use the aws sdk to create the function, it fails with an error message. Anyone got any clue?
Code:
private function createLambdaFunction() {
$result = $this->lambdaConn->createFunction(array(
'FunctionName' => $this->lambdaFunctionName,
'Runtime' => $this->runtime,
'Role' => $this->role,
'Handler' => $this->lambdaFunctionName.".".$this->handler,
'Description' => $this->description,
'Timeout' => $this->timeout,
'MemorySize' => $this->memorySize,
'Code' => array(
'ZipFile' => 'fileb://test.zip'
)
));
Error:
PHP Fatal error: Uncaught Aws\Lambda\Exception\LambdaException: AWS
Error Code: InvalidParameterValueException,
Status Code: 400, AWS Request ID: asdf, AWS Error Type: user,
AWS Error Message: Could not unzip uploaded file. Please check
your file, then try to upload again., User-Agent:
aws-sdk-php2/2.8.10 Guzzle/3.9.3 curl/7.35.0 PHP/5.5.9-1ubuntu4.9
I can't seem to find a good example on google, and the documentation is...less than ideal. I created the zip file with php, so I've tried passing that var, the full path to the file, relative path to file, etc. Finally learned you have to use fileb:// preface, but that didn't end up fixing anything.
Okay, I'm not sure why this is the case, but you need to base64 encode your zip file like:
$result = $this->lambdaConn->createFunction(array(
'FunctionName' => $this->lambdaFunctionName,
'Runtime' => $this->runtime,
'Role' => $this->role,
'Handler' => $this->lambdaFunctionName . "." . $this->handler,
'Description' => $this->description,
'Timeout' => $this->timeout,
'MemorySize' => $this->memorySize,
'Code' => array(
'ZipFile' => 'fileb://'.base64_encode(file_get_contents('test.zip'))
)
));
I'm not sure why this is required, as accourding to the doumentation and a post by an AWS employee, you dont have to have base64 encoding for create function. They must have mixed up something or another.

SourceFile Amazon AWS S3

I'm trying to upload a file to my bucket. I am able to upload with Body but not SourceFile. Here's my method:
$pathToFile='/explicit/path/to/file.jpg'
// Upload an object by streaming the contents of a file
$result = $s3Client->putObject(array(
'Bucket' => $bucket,
'Key' => 'test.jpg',
'SourceFile' => $pathToFile,
'ACL' => 'public-read',
'ContentType' => 'image/jpeg'
));
but I get this error:
You must specify a non-null value for the Body or SourceFile parameters.
I've tried different types of files and keep getting this error.
The issue had to do with not giving a good path. Looks like file_exists() only checks locally, meaning that it had to be within localhost's index.
Change
'SourceFile' => $pathToFile,
to
'Body' => $pathToFile,

Set Cache-Control HTTP Header for S3 Objects from PHP AWS SDK

I using the Amazon SDK for PHP and trying to set Cache-control Header on the image. When I try to add it via MetaData = array("Cache-Control") it changes it to be x-amz-meta-cache-control when I login to the S3 bucket, and when I download the file, there is no Cache-control set. But if I manually change this setting, the Cache-control works perfectly. Is there some parameter I missing that I can use to set HTTP Request Headers programmatically on upload? I'm using the PutObject method. I believe the AWS SDK is from 2013.
The cache control isn't set via the "MetaData" index, "CacheControl" is at the same level as "MetaData", not contained within it.
http://docs.aws.amazon.com/aws-sdk-php-2/latest/class-Aws.S3.S3Client.html#_putObject
You'd use something like this as your configuration array for the putObject() method...
$s3client->putObject(array(
'Bucket' => '...',
'key' => '...',
'body' => '...',
'CacheControl' => 'max-age=172800',
'MetaData' => array(
'metaKey' => 'metaValue',
'metaKey' => 'metaValue'
)));
For the upload() method...
$s3client->upload(
'bucket',
'key',
fopen('sourcefile','r'),
'public-read',
array('params' => array(
'CacheControl' => 'max-age=172800',
'Metadata' => array(
'metaKey' => 'metaValue',
'metaKey' => 'metaValue'
))));
Also, it's worth pointing out that upload() will wrap putObject() for files of 5MB in size, otherwise it will initiate a multipart upload request.
If you want to add the CacheControl header to an item already in your bucket, use the SDK's copyObject method. Set the MetadataDirective param to REPLACE to make the item overwrite itself.
I noticed one weird thing: I had to set the ContentType header too, even though it was already set. Otherwise the image would not display inline in the browser but be offered as a download.
$result = $s3->copyObject(array(
'ACL' => 'public-read',
'Bucket' => $bucket, // target bucket
'CacheControl' => 'public, max-age=86400',
'ContentType' => 'image/jpeg', // !!
'CopySource' => urlencode($bucket . '/' . $key),
'Key' => $key, // target file name
'MetadataDirective' => 'REPLACE'
));

How to define ContentMD5 parameter for AWS S3 PHP SDK 2 method call

Maybe I'm missing something, but I've been looking everywhere and can't find a decent explanation for the ContentMD5 required parameter in the PHP SDK 2 for deleteObjects (http://docs.aws.amazon.com/aws-sdk-php-2/latest/class-Aws.S3.S3Client.html#_deleteObjects)
Docs say it "defaults to true", however that makes me assume it's a boolean value - however, I'm always getting a 4** response when executing the command with a Boolean - I think it's something else.
It's a simple call:
$s3 = S3Client::factory(array(
'key' => S3_KEY,
'secret' => S3_SECRET
));
$response = $s3->deleteObjects(array(
'Bucket' => $bucket,
'Objects' => $array_of_keys,
'ContentMD5' => ???????????
));
Any help on how I define the ContentMD5 param would be super helpful.
Thanks!
The correct usage for the deleteObjects method in the AWS PHP SDK v2 is this one:
$s3->deleteObjects(array(
'Bucket' => 'your-bucket-name',
'Objects' => array(
array('Key'=>'first-file.ext'),
array('Key'=>'second-file.ext')
)
);
You do not need to define the ContentMD5 parameter.

Categories