Web Programming TutorialsLearn How To Work With S3 Using AWS, PHP & SDK

Learn How To Work With S3 Using AWS, PHP & SDK

 

AWS Cloud Services by Amazon are the most used services by developers today. These services have provided unlimited power and unlimited storage to the Developer. In this article, we talk about how to work with the AWS unlimited storage i.e. AWS S3 with PHP. ‘S3’ stands for ‘Simple Storage Services’.

To store your files in AWS S3, S3 requires you to create ‘Storage Containers’ that are called ‘Buckets’ in AWS’s terminology. These buckets can store all types of Files and Folders. Buckets can have a hierarchy of folders too, just like our local filesystem. Every bucket comes with its own set of ‘Access Permissions’ which by default applies to all the files and folders within that bucket. We can however apply ‘Individual Permissions’ to these files too, in such a case these Individual File Permissions will be applicable rather than the Default Bucket’s Permissions.

In AWS’s terms, all files that are stored in S3 are known as ‘Objects’. Every Object has an ‘Owner’, ‘Owner’ is the account which is used to actually upload that particular file on S3. Every Object can have ‘public’ or ‘private’ access. Public files are available for download via a unique link. Private files are not available to download until the download link is attached to a token. This unique token is created on the fly and expires after the specified time (we specify for how long the token should be valid).

[Basic Setup]
In this article, we will perform CRUD operations on S3 using PHP. AWS has released its official SDK for PHP Developers which makes performing all these tasks very easy. Right now, the official SDK is at ‘3.44.2’ version. We will be using this SDK for all our code examples in this tutorial.

Before proceeding, we first need a working AWS Account itself. AWS offers a ‘Free Tier’ for New Users, which is more than enough to get started and play around with the services without paying a single penny.

Once the account is created and verified, we first create a ‘Bucket’ with ‘public read access’ from the AWS console. We will use this very Bucket for all the uploads and downloads in this tutorial.

Every bucket is kept in a ‘particular region’ of the world where all the files under this particular bucket are stored. For the code samples in this tutorial, we have created our bucket in the ‘Mumbai, India’ region. So all our files gets stored in Amazon’s Mumbai Data Center. You can choose the region that is closer to you.

Now we need to download the official AWS SDK for PHP. The official PHP SDK resides at: https://github.com/aws/aws-sdk-php. You can directly download this SDK from there.
Composer users can install this SDK via this command: ‘composer require aws/aws-sdk-php’. The official repository for this package is at: ‘https://packagist.org/packages/aws/aws-sdk-php‘.

To access S3 services via API, we need to have ‘Access Keys’. These ‘access keys’ can be created from ‘AWS Console’ under ‘My Security Credentials’ section. Once done, we are all set to start writing our code.

[Initializing S3]
The first thing that we are required to do is initialize the S3 Instance. We do this as follows:

<code> 
<?php 
# composer dependencies 
require __DIR__.'/vendor/autoload.php'; 

$config = [ 
	's3-access' => [ 
		'key' => '[key]', 
		'secret' => '[secret]', 
		'bucket' => '[s3.demobucket.eduonix]', 
		'region' => 'ap-south-1', 
		'version' => 'latest', 
		'acl' => 'public-read', 
		'private-acl' => 'private' 
	] 
]; 

# initializing s3 
$s3 = Aws\S3\S3Client::factory([ 
	'credentials' => [ 
		'key' => $config['s3-access']['key'], 
		'secret' => $config['s3-access']['secret'] 
	], 
	'version' => $config['s3-access']['version'], 
	'region' => $config['s3-access']['region'] 
]); 
?> 
</code>

You can keep this code in a single file and name it ‘initialize.php’. We will be including this file in all our code examples. The ‘$config’ variable consists of all the properties that are required to initialize our S3 instance. We then include composer autoload script which initializes our AWS SDK. In the third step, we create the actual S3 object which will be used for all our CRUD operations.

[Uploading file ‘with public read access’ to a Bucket]
In this example, we upload a basic text file to S3 with ‘public read access’. This means that the uploaded file would be available for download via a link. Please have a look at the following code example:

<code> 
<?php 
# initializes everything 
require_once __DIR__.'/initialize.php'; 

# lets upload our file to s3 
try{ 
	# file to upload 
	$file_path = __dir__.'/files/lullaby.txt'; # this is the sample file that we are going to upload 
	$file_name = pathinfo($file_path)['basename']; 
 
	# actual uploading 
	$request_status = $s3->putObject([ 
		'Bucket' => $config['s3-access']['bucket'], 
		'Key' => 'from_php_script/'.$file_name, # 'from_php_script' will be our folder on s3 (this would be automatically created) 
		'Body' => fopen($file_path, 'rb'), # reading the file in the 'binary' mode 
		'ACL' => $config['s3-access']['acl'] 
	]); 

	# printing result 
	print_r($request_status); 
}catch(Exception $ex){ 
	echo "Error Occurred\n", $ex->getMessage(); 
} 
?> 
</code>

Before running the above code, make sure to create the file ‘lullaby.txt’ first to avoid possible errors. We have created our file ‘lullaby.txt’ with the following contents (you can create this file with the contents of your choice):

<code> 
Lullaby, and good night, in the skies stars are bright. 
May the moon's silvery beams bring you sweet dreams. 
Close your eyes now and rest, may these hours be blessed. 
'Til the sky's bright with dawn, when you wake with a yawn. 

Lullaby, and good night, you are mother's delight. 
I'll protect you from harm, and you'll wake in my arms. 

Sleepyhead, close your eyes, for I'm right beside you. 
Guardian angels are near, so sleep without fear. 
Lullaby, and good night, with roses bedight. 
Lilies o'er head, lay thee down in thy bed. 

Lullaby, and good night, you are mother's delight. 
I'll protect you from harm, and you'll wake in my arms. 

Lullaby, and sleep tight, my darling sleeping. 
On sheets white as cream, with a head full of dreams. 
Sleepyhead, close your eyes, I'm right beside you. 
Lay thee down now and rest, may your slumber be blessed. 

Go to sleep, little one, think of puppies and kittens. 
Go to sleep, little one, think of butterflies in spring. 
Go to sleep, little one, think of sunny bright mornings. 
Hush, darling one, sleep through the night, 
Sleep through the night, 
Sleep through the night. 

Listen to this lullaby! 
</code>

The php code is pretty much self explanatory. One thing worth noting is that we provide a ‘File Resource’ to the S3 object to upload this file on S3. This resource has the ‘file mode’ set to ‘rb’, which asks PHP to ‘open the file for reading in the binary mode’. This is the preferred mode to upload files to S3 (unless you know what you are doing).

Once the upload is successful, an AWS Object is returned which consists of ‘Meta Data’, ‘Upload Status’ along with the ‘Object URL’. In this example, we have printed all the information that is returned after the successful upload.

[Uploading file ‘with private read access’ to a Bucket]
In this example, we upload a basic text file to S3 with ‘private access’. This means that the uploaded file would be available for download via a ‘tokenized link’ (we will later see how to create a tokenized link for private files). Please have a look at the following code example:

<code> 
<?php 
# initializes everything 
require_once __DIR__.'/initialize.php'; 

# lets upload our file to s3 
try{ 
	# file to upload 
	$file_path = __dir__.'/files/lullaby-private.txt'; 
	$file_name = pathinfo($file_path)['basename']; 

	# actual uploading 
	$request_status = $s3->putObject([ 
		'Bucket' => $config['s3-access']['bucket'], 
		'Key' => 'from_php_script/'.$file_name, # 'from_php_script' will be our folder on s3 (this would be automatically created) 
		'Body' => fopen($file_path, 'rb'), 
		'ACL' => $config['s3-access']['private-acl'] 
	]); 

	# printing result 
	print_r($request_status); 
}catch(Exception $ex){ 
	echo "Error Occurred\n", $ex->getMessage(); 
} 
?> 
</code>

The only change in the above code compared to the previous code sample is the actual ‘file name’ along with the applied ‘ACL’, which is now set to ‘private’. ACL stands for ‘Access Control List’. In this example, we are asking S3 to create a private file in our S3 Bucket.

The returned object is the same ‘Result Object’ with ‘similar properties’ as in the previous code example. You can check these uploaded files in your AWS S3 Console.

[Listing all files in the AWS Bucket]
In this example, we fetch information of all the files which exist in our S3 Bucket. We also create the download links for these files. Please have a look at the following code example:

<code> 
<?php 
# initializes everything 
require_once __DIR__.'/initialize.php'; 

# lets list our files on s3 
try{ 
	# initializing our object 
	$files = $s3->getIterator('ListObjects', [ # this is a Generator Object (its yields data rather than returning) 
		'Bucket' => $config['s3-access']['bucket'] 
	]); 

	# printing our data 
	foreach($files as $file){ 
		print_r($file); 
		echo 'Download link would be: ', $s3->getObjectUrl($config['s3-access']['bucket'], $file['Key']), "\n\n"; 
	} 
}catch(Exception $ex){ 
	echo "Error Occurred\n", $ex->getMessage(); 
} 
?> 
</code>

The above code, simply fetches the properties of all the files in our S3 Bucket. We then iterate over the returned ‘Generator’ and print out the information for every file. This returned Object consists of ‘Meta Data’ among other information about the files in our Bucket. S3 SDK provides a method to generate download links for these files named ‘getObjectUrl’, which we are using to create our download links.

Please note, that these links would perfectly work for Public Files, but for the Private Files, these URLs when accessed, will show an XML ‘Access Denied’ error. This is because, Private Files require URLs to be tokenized first. We see how to tokenize our URLs in the next example.

[Creating Download Links for ‘Private Files’]
We have created both Public Files as well as Private Files in our S3 Bucket. Creating Download Links for our Public Files is straight forward. But this is not the same case for private files. Of course, we don’t want our private files to be downloadable without our knowledge, so this is a very important feature. In this example, we modify the above code by listing all the information of the files from our S3 Bucket, with an addition to create a ‘Tokenized URL’ for the ‘Private Files’. Please have a look at the following code snippet:

<code> 
<?php 
# initializes everything 
require_once __DIR__.'/initialize.php'; 

# lets list our files on s3 
try{ 
	# initializing our object 
	$files = $s3->getIterator('ListObjects', [ # this is a Generator Object (its yields data rather than returning) 
		'Bucket' => $config['s3-access']['bucket'] 
	]); 

	# printing our data 
	foreach($files as $file){ 
		# whether file is private or not 
		$file_acl = $s3->getObjectAcl([ 
			'Bucket' => $config['s3-access']['bucket'], 
			'Key' => $file['Key'] 
		]); 
		$is_private = true; 
		foreach($file_acl['Grants'] as $grant){ 
			if( 
				isset($grant['Grantee']['URI']) && 
				$grant['Grantee']['URI'] == 'http://acs.amazonaws.com/groups/global/AllUsers' && 
				$grant['Permission'] == 'READ' 
			) $is_private = false; # this file is not private 
		} 

		# applicable url 
		if($is_private == false){ 
			$file_url = $s3->getObjectUrl($config['s3-access']['bucket'], $file['Key']); 
		}else{ 
			$url_creator = $s3->getCommand('GetObject', [ 
				'Bucket' => $config['s3-access']['bucket'], 
				'Key' => $file['Key'] 
			]); 
			$file_url = $s3->createPresignedRequest($url_creator, '+2 minutes')->getUri(); 
		} 

		# printing all 
		printf("File Name: %s\nFile ACL: %s\nFile URL: %s\n\n", 
			$file['Key'], 
			$is_private ? 'private' : 'public', 
			$file_url 
		); 
	} 
}catch(Exception $ex){ 
	echo "Error Occurred\n", $ex->getMessage(); 
} 
?> 
</code>

In the above code example, we simply request all the files that are in our S3 Bucket. We are supplied with a Generator which we initialize to the variable named ‘$files’. Using this Generator, we then iterate over the returned files properties. While iterating, we first figure out the ACL (Access Control List) of these files. Using this access list, we check whether or not this list consists of ‘READ’ access to ‘All Users’ If such an access is found, the file is ‘public’ otherwise it is a ‘private file’. Once we know that the file is private, we create a ‘Tokenized URL’ using the SDK method named ‘createPresignedRequest’. We are setting the expiry of this tokenized url to ‘2 minutes’. This means, using this newly generated tokenized URL, the file can be downloaded, but the request needs to be made within 2 minutes. If this Tokenized URL is accessed after 2 minutes, it will simply throw an XML ‘Access Denied’ error as the token is no longer valid.

[Download files from S3 Bucket using S3 SDK]
Rather than downloading files from S3 via a link, there is also an option to download files directly to the filesystem using the AWS SDK, programmatically. This is a useful feature when you don’t want to provide the S3 Bucket URL to your users, so you simply download file to the server first and then make it available for your users to download from the server’s filesystem.

So, to download files from your S3 Bucket directly to your Filesystem, you can use the AWS SDK method called ‘getObject’. Please note that you need to have ‘READ’ access to the file before using this method. If you uploaded the file in the first place, you already have ‘Full Permissions’ to access this file. The working of this method is demonstrated below:

<code> 
<?php 
# initializes everything 
require_once __DIR__.'/initialize.php'; 

# lets download our file 
$file_to_download = 'from_php_script/lullaby.txt'; # private file: 'from_php_script/lullaby-private.txt' 
$download_as_path = __dir__.'/downloads/lullaby.txt'; 

# save object to a file 
$result = $s3->getObject([ 
	'Bucket' => $config['s3-access']['bucket'], 
	'Key' => $file_to_download, 
	'SaveAs' => $download_as_path 
]); 
?> 
</code>

The above code example, simply uses the ‘getObject’ method with the parameters set to the ‘Bucket Name’, ‘The actual File Path’ on S3 Bucket’ and the ‘Local Filesystem Path’ to which the file should be saved. On successful download, the ‘Aws\Result Object’ is also returned which contains the downloaded file information.

1 COMMENT

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Exclusive content

- Advertisement -

Latest article

21,501FansLike
4,106FollowersFollow
106,000SubscribersSubscribe

More article

- Advertisement -