Download large files from s3 via php - php

I have managed to upload large files to s3 using multiPart Upload, but I can't download them again using the getObject function. Is there another way I can achieve this?
Here my code:
$keyname= 'key';
$bucket = 'bucketname';
$fileName = 'filename.txt';
$result = $s3->getObject([
'Bucket' => $bucket,
'Key' => $keyname
]);
var_dump($fileName);
$result['ContentDisposition'] = 'attachment; filename="'.$fileName.'"';
$result['fileName'] = $result['ContentDisposition'];
header("Content-Type: {$result['ContentType']}");
header("Content-Disposition: {$result['ContentDisposition']}");
header("Content-Length: {$result['ContentLength']}");
echo $result['Body'];
Thanks For the help. This is my solution:
$keyname= 'key';
$bucket = 'bucketname';
$fileName = 'filename.txt';
#create S3 Client
$s3 = new S3Client([
'version' => 'latest',
'region' => 'eu-central-1',
'credentials' => [
]
]);
$cmd = $s3->getCommand('GetObject', [
'Bucket' => $bucket,
'Key' => $keyname,
'ResponseContentDisposition' => 'attachment; filename="'.$fileName.'"'
]);
$request = $s3->createPresignedRequest($cmd, '+15 min');
$presignedUrl = (string)$request->getUri();
echo $presignedUrl;
after this, I download it in my frontend with an a tag via js

you can create a Presigned connection with S3 like this
$keyname= 'key';
$bucket = 'bucketname';
$fileName = 'filename.txt';
$command = $s3->getCommand('GetObject', array(
'Bucket' => $bucket,
'Key' => $keyname
'ResponseContentDisposition' => 'attachment; filename="'.$fileName.'"'
));
$signedUrl = $command->createPresignedUrl('+15 minutes');
header('Location: '.$signedUrl);

Related

Laravel s3 upload file with metadata using pre-signed url

I am implementing S3 file uploads and downloads using pre-signed urls. I have one s3 bucket (versioning enabled) and one AWS user but I want to track the history of each file in terms of which of my application users modified the file.
I have a versioned S3 bucket and my thought is that I can append metadata to every file to identify my application user and possibly other data too.
Here is my code:
public function presignedUpload(Request $request)
{
$this->validate($request, [
'name' => 'string|required'
]);
$s3 = Storage::disk('s3');
$client = $s3->getDriver()->getAdapter()->getClient();
$expiry = "+10 minutes";
$options = ['user-data' => 'user-meta-value'];
$cmd = $client->getCommand('PutObject', [
'Bucket' => \Config::get('filesystems.disks.s3.bucket'),
'Key' => 'path/to/file/' . $request->name,
'ACL' => 'public-read',
], $options);
$request = $client->createPresignedRequest($cmd, $expiry);
$presignedUrl = (string)$request->getUri();
return response()->json(['url' => $presignedUrl], 201);
}
I deduced that I can pass an $options array from the FilesystemAdapter::class. This code does upload the file, but the metadata in AWS looks empty.
Is my $options array in the wrong format?
Appreciate any help on this.
The selected answer doesn't work anymore after Laravel 9. Flysystem recommends you to use S3 SDK instead of Storage driver.
https://github.com/thephpleague/flysystem/issues/1423
Use the S3 SDK instead to create a resigned upload URL.
$uploadDisk = 's3';
$s3Client = new S3Client([
'credentials' => [
'key' => config('filesystems.disks.' . $uploadDisk . '.key'),
'secret' => config('filesystems.disks.' . $uploadDisk . '.secret'),
],
'region' => config('filesystems.disks.' . $uploadDisk . '.region'),
'version' => 'latest',
]);
$s3Bucket = config('filesystems.disks.' . $uploadDisk . '.bucket');
$s3Key = \Illuminate\Support\Str::uuid(); // your file name
$s3Options = [];
$command = $s3Client->getCommand('PutObject', [
'Bucket' => $s3Bucket,
'Key' => $s3Key,
'MetaData' => $s3Options,
]);
$request = $s3Client->createPresignedRequest($command, '+20 minutes');
$url = (string) $request->getUri();
Metadata can be uploaded like this:
public function presignedUpload(Request $request)
{
$this->validate($request, [
'name' => 'string|required'
]);
$s3 = Storage::disk('s3');
$client = $s3->getDriver()->getAdapter()->getClient();
$expiry = "+10 minutes";
$options = ['user-data' => 'user-meta-value'];
$cmd = $client->getCommand('PutObject', [
'Bucket' => \Config::get('filesystems.disks.s3.bucket'),
'Key' => 'path/to/file/' . $request->name,
'ACL' => 'public-read',
'Metadata' => $options,
]);
$request = $client->createPresignedRequest($cmd, $expiry);
$presignedUrl = (string)$request->getUri();
return response()->json(['url' => $presignedUrl], 201);
}

Use pre-signed url to get objects

I'm trying to get the objects in AWS S3 by listObjects but I need to do this with a pre-signed url.
The following code gives me the objects:
$objects = $s3Client->listObjects([
'Bucket' => $bucket,
'Prefix' => $prefix
]);
The problem is that I need to do it with a presigned url. I get the url with following:
$cmd = $s3Client->getCommand('ListObjects', [
'Bucket' => $bucket,
'Prefix' => $prefix
]);
$request = $s3Client->createPresignedRequest($cmd, '+20 minutes');
$url = (string)$request->getUri();
And I retrieve the objects when accessing the URL through the browser but I need to get objects in PHP instead of a link to them. How do I do that?
$s3Client = Aws::createClient('s3');
$result = $s3Client->getObject(array(
'Bucket' => $bucket,
'Key' => $path
));
$metadata = $result->get("#metadata");
$statusCode = $metadata["statusCode"];
if ($statusCode == 200) {
header("Content-type: text/image");
header("Content-Disposition: attachment; filename=".$path);
header("Pragma: no-cache");
header("Expires: 0");
return $result['Body'];//echo $result['Body'];
}

How to customize s3 uploaded files url in yii2?

I have used vlaim\fileupload\FileUpload; and yii\web\UploadedFile;
$image = UploadedFile::getInstance($model, 'flag');
$model->flag = new FileUpload(FileUpload::S_S3, [
'version' => 'latest',
'region' => 'us-west-2',
'credentials' => [
'key' => 'KEY',
'secret' => 'SECRET'
],
'bucket' => 'mybucket/uploads/flags/'.$model->code
]);
$uploader = $model->flag;
$model->flag = $uploader->uploadFromFile($image)->path;
In db i'm saving the path. How to customize the url?
Now my url looks like https://s3-us-west-2.amazonaws.com/mybucket%2Fuploads%2Fflags%2Fus/uploads%5C9f%5C7e%5Cc093ad5a.png
I need the url like https://mybucket.s3.amazonaws.com/uploads/flags/us.png
S3 does not have the concept of folders, It is an object store, with key/value pairs. They key for your file would be uploads/flags/us.png
with the PHP SDK it's easy to set the key of the object.
$USAGE = "\n" .
"To run this example, supply the name of an S3 bucket and a file to\n" .
"upload to it.\n" .
"\n" .
"Ex: php PutObject.php <bucketname> <filename>\n";
if (count($argv) <= 2){
echo $USAGE;
exit();
}
$bucket = $argv[1];
$file_Path = $argv[2];
$key = basename($argv[2]);
try{
//Create a S3Client
$s3Client = new S3Client([
'region' => 'us-west-2',
'version' => '2006-03-01'
]);
$result = $s3Client->putObject([
'Bucket' => $bucket,
'Key' => $key,
'SourceFile' => $file_Path,
]);
} catch (S3Exception $e) {
echo $e->getMessage() . "\n";
}
yii2 i think you need to set setFsUrl()
http://www.yiiframework.com/extension/yii2-file-upload/#hh8
setFsUrl(string $url)
(Only for Local mode)
Sets url. For example, if you set path to 'http://static.example.com' file after uploading will have URL http://static.example.com/path/to/your/file
Default to /
php $uploader->setFsPath('http://pathtoyoursite.com');

Post request for S3 image file

I have a php script to pull an image file from amazon S3 called test.php
if I write the html like this <img src="test.php"> The image appears fine.
However when I try to use a get request and set the SRC of the image it doesnt appear correctly. I eventually want to pass params in using post once this works. On inspecting the src its filled with meta data as if header("Content-type: image") hasnt been set.
$.get( "test.php",function( data ) {
$('#image1').attr('src', data);
});
My test.php script:
require '../vendor/autoload.php';
use Aws\S3\S3Client;
$region = 'us-west-2';
$bucket = 'mybucket';
$key = 'mykey';
$secret = 'mysecret';
$s3Client = new S3Client([
'version' => 'latest',
'region' => $region,
'credentials' => [
'key' => $key,
'secret' => $secret,
],
]);
$result = $s3Client->getObject(array(
'Bucket' => $bucket,
'Key' => 'monkey1.jpg'
));
header("Content-type: image");
// Print the body of the result by indexing into the result object.
echo $result['Body'];
//echo '<img src="'.$result['Body'].'">'
get the object URL temporal and load it to the page
$result = $s3->get_object_url($bucket, 'monkey1.jpg', '1 minute');
from this you can load the image to the page!
echo '<img src="'.$result.'">
This worked for me.
PHP script
$s3Client = new S3Client([
'version' => 'latest',
'region' => $region,
'credentials' => [
'key' => $key,
'secret' => $secret,
],
]);
$s3Client->registerStreamWrapper();
if (file_exists('s3://'.$bucket.'/'.$id.'/'.$filepath)) {
//echo 'It exists!';
$result = $s3Client->getObject(array(
'Bucket' => $bucket,
//'Key' => 'monkey1.jpg'
'Key' => $id.'/'.$filepath
));
header("Content-type: image/*");
// Print the body of the result by indexing into the result object.
echo base64_encode($result['Body']);
}
JS
$('#image').attr('src', 'data:image/*;base64,'+data);

Upload file on amazon S3 with PHP SDK

I'm trying to upload a picture on my amazon S3 via their PHP SDK. So I made a little script to do so. However, my script doesn't work and my exception doesn't send me back any error message.
I'm new with AWS thank you for your help.
Here is the code :
Config.php
<?php
return array(
'includes' => array('_aws'),
'services' => array(
'default_settings' => array(
'params' => array(
'key' => 'PUBLICKEY',
'secret' => 'PRIVATEKEY',
'region' => 'eu-west-1'
)
)
)
);
?>
Index.php
<?php
//Installing AWS SDK via phar
require 'aws.phar';
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
$bucket = 'infact';
$keyname = 'myImage';
// $filepath should be absolute path to a file on disk
$filepath = 'image.jpg';
// Instantiate the client.
$s3 = S3Client::factory('config.php');
// Upload a file.
try {
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'SourceFile' => $filePath,
'ContentType' => 'text/plain',
'ACL' => 'public-read',
'StorageClass' => 'REDUCED_REDUNDANCY'
));
// Print the URL to the object.
echo $result['ObjectURL'] . "\n";
} catch (S3Exception $e) {
echo $e->getMessage() . "\n";
}
?>
EDIT : I'm now using this code but its still not working. I don't even have error or exception message.
<?php
require 'aws.phar';
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
$bucket = 'infactr';
$keyname = 'sample';
// $filepath should be absolute path to a file on disk
$filepath = 'image.jpg';
// Instantiate the client.
$s3 = S3Client::factory(array(
'key' => 'key',
'secret' => 'privatekey',
'region' => 'eu-west-1'
));
try {
// Upload data.
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'SourceFile' => $filePath,
'ACL' => 'public-read',
'ContentType' => 'image/jpeg'
));
// Print the URL to the object.
echo $result['ObjectURL'] . "\n";
} catch (S3Exception $e) {
echo $e->getMessage() . "\n";
}
?>
Try something like this (from the AWS docs):
<?php
require 'aws.phar';
use Aws\S3\S3Client;
use Aws\S3\Exception\S3Exception;
$bucket = '<your bucket name>';
$keyname = 'sample';
// $filepath should be absolute path to a file on disk
$filepath = '/path/to/image.jpg';
// Instantiate the client.
$s3 = S3Client::factory(array(
'key' => 'your AWS access key',
'secret' => 'your AWS secret access key'
));
try {
// Upload data.
$result = $s3->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'SourceFile' => $filepath,
'ACL' => 'public-read'
));
// Print the URL to the object.
echo $result['ObjectURL'] . "\n";
} catch (S3Exception $e) {
echo $e->getMessage() . "\n";
}
?>
It works fine for me as long as you have the right credentials. Keep in mind that the key name is the name of your file in S3 so if you want to have your key have the same name of your file you have to do something like: $keyname = 'image.jpg'; . Also, a jpg is generally not a plain/text file type, you can ommit that Content-type field or you can just simply specify: image/jpeg
$s3 = S3Client::factory('config.php');
should be
$s3 = S3Client::factory(include 'config.php');
For those looking an up to date working version, this is what I am using
// Instantiate the client.
$s3 = S3Client::factory(array(
'credentials' => [
'key' => $s3Key,
'secret' => $s3Secret,
],
'region' => 'us-west-2',
'version' => "2006-03-01"
));
try {
// Upload data.
$result = $s3->putObject(array(
'Bucket' => $s3Bucket,
'Key' => $fileId,
'SourceFile' => $filepath."/".$fileName
));
return $result['ObjectURL'];
} catch (S3Exception $e) {
return false;
}
An alternative way to explain is by showing the curl, and how to build it in php - the pragmatic approach.
Please don't stone me for ugly code, just thought that this example is easy to follow for uploading to Azure from PHP, or other language.
$azure1 ='https://viperprodstorage1.blob.core.windows.net/bucketnameAtAzure/';
$azure3 ='?sr=c&si=bucketnameAtAzure-policy&sig=GJ_verySecretHashFromAzure_aw%3D';
$shellCmd='ls -la '.$outFileName;
$lsOutput=shell_exec($shellCmd);
#print_r($lsOutput);
$exploded=explode(' ', $lsOutput);
#print_r($exploded);
$fileLength=$exploded[7];
$curlAzure1="curl -v -X PUT -T '" . $outFileName . "' -H 'Content-Length: " . $fileLength . "' ";
$buildedCurlForUploading=$curlAzure1."'".$azure1.$outFileName.$azure3."'";
var_dump($buildedCurlForUploading);
shell_exec($buildedCurlForUploading);
This is the actual curl
shell_exec("curl -v -X PUT -T 'fileName' -H 'Content-Length: fileSize' 'https://viperprodstorage1.blob.core.windows.net/bucketnameAtAzure/fileName?sr=c&si=bucketNameAtAzure-policy&sig=GJ_verySecretHashFromAzure_aw%3D'")
Below are the code for upload image/file in amazon s3 bucket.
function upload_agreement_data($target_path, $source_path, $file_name, $content_type)
{
$fileup_flag = false;
/*------------- call global settings helper function starts ----------------*/
$bucketName = "pilateslogic";
//$global_setting_option = '__cloud_front_bucket__';
//$bucketName = get_global_settings($global_setting_option);
/*------------- call global settings helper function ends ----------------*/
if(!$bucketName)
{
die("ERROR: Template bucket name not found!");
}
// Amazon profile_template template js upload URL
$target_profile_template_js_url = "/".$bucketName."/".$target_path;
// Chatching profile_template template js upload URL
//$source_profile_template_js_url = dirname(dirname(dirname(__FILE__))).$source_path."/".$file_name;
// file name
$template_js_file = $file_name;
$this->s3->setEndpoint("s3-ap-southeast-2.amazonaws.com");
if($this->s3->putObjectFile($source_path, $target_profile_template_js_url, $template_js_file, S3::ACL_PUBLIC_READ, array(), array("Content-Type" => $content_type)))
{
$fileup_flag = true;
}
return $fileup_flag;
}

Categories