I have decide to avail of amazons new server-side encryption with s3, however, I have run into a problem which I am unable to resolve.
I am using the s3 PHP class found here : https://github.com/tpyo/amazon-s3-php-class
I had been using this code to put objects originally (and it was working) :
S3::putObjectFile($file, $s3_bucket_name, $file_path, S3::ACL_PRIVATE,
array(),
array(
"Content-Disposition" => "attachment; filename=$filename",
"Content-Type" => "application/octet-stream"
)
);
I then did as instructed here : http://docs.amazonwebservices.com/AmazonS3/latest/API/index.html?RESTObjectPUT.html and added the 'x-amz-server-side-encryption' request header. But now when I try to put an object it fails without error.
My new code is :
S3::putObjectFile($file, $s3_bucket_name, $file_path, S3::ACL_PRIVATE,
array(),
array(
"Content-Disposition" => "attachment; filename=$filename",
"Content-Type" => "application/octet-stream",
"x-amz-server-side-encryption" => "AES256"
)
);
Has anybody experimented with this new feature or can anyone see an error in the code.
Cheers.
That header should be part of the $metaHeaders array and not $requestHeaders array.
S3::putObjectFile($file, $s3_bucket_name, $file_path, S3::ACL_PRIVATE,
array(
"x-amz-server-side-encryption" => "AES256"
),
array(
"Content-Disposition" => "attachment; filename=$filename",
"Content-Type" => "application/octet-stream"
)
);
Here's the method definition from the docs:
putObject (mixed $input,
string $bucket,
string $uri,
[constant $acl = S3::ACL_PRIVATE],
[array $metaHeaders = array()],
[array $requestHeaders = array()])
You might also consider using the SDK for PHP?
We can upload files with encryption using the code following
$s3->create_object($bucket_name,$destination,array(
'acl'=>AmazonS3::ACL_PUBLIC,
'fileUpload' => $file_local,
'encryption'=>"AES256"));
And you can download latest sdk from here
With the official SDK:
use Aws\S3\S3Client;
$bucket = '*** Your Bucket Name ***';
$keyname = '*** Your Object Key ***';
// $filepath should be absolute path to a file on disk
$filepath = '*** Your File Path ***';
// Instantiate the client.
$s3 = S3Client::factory();
// Upload a file with server-side encryption.
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'SourceFile' => $filepath,
'ServerSideEncryption' => 'AES256',
));
Changing Server-Side Encryption of an Existing Object (Copy Operation)
use Aws\S3\S3Client;
$sourceBucket = '*** Your Source Bucket Name ***';
$sourceKeyname = '*** Your Source Object Key ***';
$targetBucket = '*** Your Target Bucket Name ***';
$targetKeyname = '*** Your Target Object Key ***';
// Instantiate the client.
$s3 = S3Client::factory();
// Copy an object and add server-side encryption.
$result = $s3->copyObject(array(
'Bucket' => $targetBucket,
'Key' => $targetKeyname,
'CopySource' => "{$sourceBucket}/{$sourceKeyname}",
'ServerSideEncryption' => 'AES256',
));
Source: http://docs.aws.amazon.com/AmazonS3/latest/dev/SSEUsingPHPSDK.html
With laravel 5+ it can be done easily through filesystems.php config, you don't need to get driver or low level object.
's3' => [
'driver' => 's3',
'key' => "Your Key",
'secret' => "Your Secret",
'region' => "Bucket Region",
'bucket' => "Bucket Name",
'options' => [
'ServerSideEncryption' => 'AES256',
]
],
//Code
$disk->put("filename", "content", "public"); // will have AES for file
Related
I try to upload an image to s3 using Laravel but I receive a runtime error. Using Laravel 5.8, PHP7 and API REST with Postman I send by body base64
I receive an image base64 and I must to upload to s3 and get the request URL.
public function store(Request $request)
{
$s3Client = new S3Client([
'region' => 'us-east-2',
'version' => 'latest',
'credentials' => [
'key' => $key,
'secret' => $secret
]
]);
$base64_str = substr($input['base64'], strpos($input['base64'], ",") + 1);
$image = base64_decode($base64_str);
$result = $s3Client->putObject([
'Bucket' => 's3-galgun',
'Key' => 'saraza.jpg',
'SourceFile' => $image
]);
return $this->sendResponse($result['ObjectURL'], 'message.', 'ObjectURL');
}
Says:
RuntimeException: Unable to open u�Z�f�{��zڱ��� .......
The SourceFile parameter is leading to the path of file to upload to S3, not the binary
You can use Body parameter to replace the SourceFile, or saving the file to local temporary and get the path for SourceFile
Like this:
public function store(Request $request)
{
$s3Client = new S3Client([
'region' => 'us-east-2',
'version' => 'latest',
'credentials' => [
'key' => $key,
'secret' => $secret
]
]);
$base64_str = substr($input['base64'], strpos($input['base64'], ",") + 1);
$image = base64_decode($base64_str);
Storage::disk('local')->put("/temp/saraza.jpg", $image);
$result = $s3Client->putObject([
'Bucket' => 's3-galgun',
'Key' => 'saraza.jpg',
'SourceFile' => Storage::disk('local')->path('/temp/saraza.jpg')
]);
Storage::delete('/temp/saraza.jpg');
return $this->sendResponse($result['ObjectURL'], 'message.', 'ObjectURL');
}
And, if you're using S3 with Laravel, you should consider the S3 filesystem driver instead of access the S3Client manually in your controller
To do this, add the S3 driver composer require league/flysystem-aws-s3-v3, put your S3 IAM settings in .env or config\filesystems.php
Then update the default filesystem in config\filesystems, or indicate the disk driver when using the Storage Storage::disk('s3')
Detail see document here
Instead of SourceFile you have to use Body. SourceFile is a path to a file, but you do not have a file, you have a base64 encoded source of img. That is why you need to use Body which can be a string. More here: https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html#putobject
Fixed version:
public function store(Request $request)
{
$s3Client = new S3Client([
'region' => 'us-east-2',
'version' => 'latest',
'credentials' => [
'key' => $key,
'secret' => $secret
]
]);
$base64_str = substr($input['base64'], strpos($input['base64'], ",") + 1);
$image = base64_decode($base64_str);
$result = $s3Client->putObject([
'Bucket' => 's3-galgun',
'Key' => 'saraza.jpg',
'Body' => $image
]);
return $this->sendResponse($result['ObjectURL'], 'message.', 'ObjectURL');
}
A very simple way to uploads Any file in AWS-S3 Storage.
First, check your ENV setting.
AWS_ACCESS_KEY_ID=your key
AWS_SECRET_ACCESS_KEY= your access key
AWS_DEFAULT_REGION=ap-south-1
AWS_BUCKET=your bucket name
AWS_URL=Your URL
The second FileStorage.php
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
//'visibility' => 'public', // do not use this line for security purpose. try to make bucket private.
],
Now come on main Code.
Upload Binary File from HTML Form.
$fileName = 'sh_'.mt_rand(11111,9999).".".$imageFile->clientExtension();;
$s3path = "/uploads/".$this::$SchoolCode."/";
Storage::disk('s3')->put($s3path, file_get_contents($req->file('userDoc')));
Upload Base64 File
For Public Bucket or if you want to keep file Public
$binary_data = base64_decode($file);
Storage::disk('s3')->put($s3Path, $binary_data, 'public');
For Private Bucket or if you want to keep file Private
$binary_data = base64_decode($file);
Storage::disk('s3')->put($s3Path, $binary_data);
I Recommend you keep your file private... that is a more secure way and safe. for this, you have to use PreSign in URL to access that file.
For Pre sign-In URL check this post. How access image in s3 bucket using pre-signed url
I have used below code
//include the S3 class
if (!class_exists('S3'))require_once('S3.php');
//AWS access info
if (!defined('awsAccessKey')) define('awsAccessKey', '****************');
if (!defined('awsSecretKey')) define('awsSecretKey', '**************************');
//instantiate the class
$s3 = new S3(awsAccessKey, awsSecretKey);
$s3->putBucket($bucket, S3::ACL_PUBLIC_READ);
in this where we put Folder Name
In S3 doesn't exist the concept of folder. What you see as folder in S3 console is just an illusion of folder.
Since each object accept / in the key, you can simulate a folder hierarchy (i.e: images/myphoto.jpg) but the filesystem is still flat.
S3 console simulate for you the folder hierarchy, but this notion is file-related, so you can't use putBucket, but putObject with a proper key:
From AWS Doc:
use Aws\S3\S3Client;
$bucket = '*** Your Bucket Name ***';
$keyname = 'images/photo.jpg';
// $filepath should be absolute path to a file on disk
$filepath = '*** Your File Path ***';
// Instantiate the client.
$s3 = S3Client::factory();
// Upload a file.
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'SourceFile' => $filepath,
'ContentType' => 'text/plain',
'ACL' => 'public-read',
'StorageClass' => 'REDUCED_REDUNDANCY',
'Metadata' => array(
'param1' => 'value 1',
'param2' => 'value 2'
)
));
echo $result['ObjectURL'];
I'm trying to Download Private S3 Object and store it on website Server
Here is what I'm Trying
$s3 = new S3Client([
'version' => 'latest',
'region' => 'ap-south-1',
'credentials' => array(
'key' => '*****',
'secret' => '*******'
)
]);
$command = $s3->getCommand('GetObject', array(
'Bucket' => 'bucket_name',
'Key' => 'object_name_in_s3'
'ResponseContentDisposition' => 'attachment; filename="'.$my_file_name.'"'
));
$signedUrl = $command->createPresignedUrl('+15 minutes');
echo $signedUrl;
How can i save these files on my server
From Get an Object Using the AWS SDK for PHP:
use Aws\S3\S3Client;
$bucket = '*** Your Bucket Name ***';
$keyname = '*** Your Object Key ***';
$filepath = '*** Your File Path ***';
// Instantiate the client.
$s3 = S3Client::factory();
// Save object to a file.
$result = $s3->getObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'SaveAs' => $filepath
));
If you just want to download a file from the command line (instead of an app), you can use the AWS Command-Line Interface (CLI) -- it has an aws s3 cp command.
The Pre-signed URL in your code can be used to grant time-limited access to a private object stored in an Amazon S3 bucket. Typically, your application generates the URL and includes it in a web page for users to click and download the object. There is no need to use it on the server-side, because the server would have credentials that are authorized to access content in Amazon S3.
I am trying to connect to my S3 to upload a file via my server but whenever i try to run the PHP, i encounter the following error below. I included the Version and Region but yet the issue still stands?
Error:
Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Missing required client configuration options: region: (string) A "region" configuration value is required for the "s3" service (e.g., "us-west-2"). A list of available public regions and endpoints can be found at http://docs.aws.amazon.com/general/latest/gr/rande.html. version: (string) A "version" configuration value is required. Specifying a version constraint ensures that your code will not be affected by a breaking change made to the service. For example, when using Amazon S3, you can lock your API version to "2006-03-01". Your build of the SDK has the following version(s) of "s3": * "2006-03-01" You may provide "latest" to the "version" configuration value to utilize the most recent available API version that your client's API provider can find. Note: Using 'latest' in a production application is not recommended. A list of available API versions can be found on each client's API documentation page: http:/ in /srv/http/auploader/include/Aws/ClientResolver.php on line 364
My Code:
<?PHP
require '/srv/http/test/include/aws-autoloader.php';
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
$bucket = 'testbucket';
$keyname = 'sample';
// $filepath should be absolute path to a file on disk
$filepath = '/srv/http/testfile/setup.html';
// Instantiate the client.
$s3 = S3Client::factory(array(
'key' => 'blank',
'secret' => 'blank'
));
try {
// Upload data.
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'SourceFile' => $filepath,
'ACL' => 'public-read',
'Region' => 'eu-west-1',
'Version' => '2006-03-01'
));
// Print the URL to the object.
echo $result['ObjectURL'] . "\n";
} catch (S3Exception $e) {
echo $e->getMessage() . "\n";
}
?>
You have to create an object of S3. And keys you have put is misplaced please do it as following.
$s3 = S3Client::factory([
'version' => 'latest',
'region' => 'eu-west-1',
'credentials' => [
'key' => "your s3 bucket key",
'secret' => "your s3 bucket secret key",
]
]);
By using s3 object you can implement putObject method something like this.
$result = $s3->putObject(array(
'Bucket' => "yourbucket name",
'Key' => $keyName,
'SourceFile' => $filepath,
'ACL' => 'public-read', //for making the public url
'Version' => '2006-03-01'
));
));
Hope it helps!
For SES AWS SDK v3 use
/*
* 1. version as `2010-12-01`
* 2. version as Eg. `us-east-1`.
*/
ini_set("display_errors", 1);
Aws\Ses\SesClient::factory(array(
'credentials' => array(
'key' => "someKey",
'secret' => "someSecret",
),
"region" => "us-east-1",
"version" => "2010-12-01")
);
I tried to upload large file into Amazon s3 using PHP. I have found nice solutions on various forums but these solutions are for SDK version 1 .
http://docs.aws.amazon.com/AmazonS3/latest/dev/LLuploadFilePHP.html
Of course, I have found examples on Amazon API documentation. This example expects file on local disk and can not handle with input stream.
I couldn't find similar examples for the SDK for PHPv2 as shown in first link.
Did someone solved similar problem successfully?
I recently just prepared a code sample for this. In this example I am using a file, but you can use a stream as well.
use Aws\S3\S3Client;
use Aws\Common\Enum\Size;
// Instantiate the client.
$s3 = S3Client::factory(array(
'key' => '*** your-aws-access-key-id ***',
'secret' => '*** your-aws-secret-key ***'
));
$file = fopen($filename, 'r');
// 1. Create a new multipart upload and get the upload ID.
$response = $s3->createMultipartUpload(array(
'Bucket' => $bucket,
'Key' => $keyname
);
$uploadId = $result['UploadId'];
// 2. Upload the data in parts.
$parts = array();
$partNumber = 1;
while (!feof($file)) {
$result = $s3->uploadPart(array(
'Bucket' => $bucket,
'Key' => $key,
'UploadId' => $uploadId,
'PartNumber' => $partNumber,
'Body' => fread($file, 5 * Size::MB),
));
$parts[] = array(
'PartNumber' => $partNumber++,
'ETag' => $result['ETag'],
);
}
// 3. Complete multipart upload.
$result = $s3->completeMultipartUpload(array(
'Bucket' => $bucket,
'Key' => $key,
'UploadId' => $uploadId,
'Parts' => $parts,
));
$url = $result['Location'];
fclose($file);