DEV Community

Jay @ Designly
Jay @ Designly

Posted on • Originally published at awstip.com on

Automating S3 + CloudFront CDN Using PHP

Featured

If you’ve read my last article, How to Use AWS CloudFront to Create Your Own Free CDN, you hopefully have your own practically-free CDN for your website assets. But maintaining all of your assets manually via the aws cli tool can be cumbersome. In my last article, I showed you how to use the aws sync and aws cp commands to move files from your local drive to your S3 bucket, which is the back-end for your CloudFront CDN.

Now I’m going to show you how to fully automate this process using PHP. Amazon Web Services has SDKs for several programming platforms, such as C++, Go, Java, JavaScript, .NET, NodeJS, PHP, Python and Ruby. This guide will largely focus on the PHP SDK.

Ok, enough babble, let’s et started!

The first thing we need to do is install the SDK in the root directory of your webserver. If you are familiar with and already have composer packages installed on your webserver, then this should be pretty straight-forward. Since this article is not a guide on how to implement composer, I’m going to assume you already have your bearings on it. If, not, please refer to the Composer Website.

Install the AWS SDK for PHP via Composer

In a BASH session on your webserver, navigate your your web root directory (wherever your composer.json file is located) and enter:

$ composer require aws/aws-sdk-php-resources
Enter fullscreen mode Exit fullscreen mode

This should install the latest version of the AWS-SDK-PHP in your vendor folder. And if you’re already a composer user, you’ll already have your autoload.php included in your project.

Test Your Installation

Now that it’s installed, let’s try a little test. First we need to create a configuration. You’ll need your security credentials from the IAM user you created for your webserver. This includes your Access Key and Secret Key. Hopefully, you have your secret key saved in a secure location, as you cannot view it again from the IAM console. If you’ve forgotten or lost it, you’ll need to revoke your old keys and generate new ones.

One thing you want to avoid doing is hard-coding your credentials into your code. This is a security vulnerability and should be avoided, if possible. Instead, you can use a key provider service, environment variables or store them in your SQL database.

Here’s an example of a basic AWS configuration in PHP:

$config = [
      'version' => 'latest',
      'region' => 'us-east-1,
      'credentials' => [
         'key' => 'YOUR_AWS_ACCESS_KEY',
         'secret' => 'YOUR_AWS_SECREY_KEY'
   ]
];
Enter fullscreen mode Exit fullscreen mode

Again, do not hard-code your credentials here. Personally, I pull them from a MySQL database and assign them to a variable, but there are plenty of other methods to store them.

Ok, let’s get right into it. We’ll start of with something simple. Let’s include the AWS S3 class and list all of the S3 buckets on our account:

<?php
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;

try {
   $s3 = new S3Client($config);

   $buckets = $s3->listBuckets();

   foreach ($buckets as $bucket) {
      echo $bucket['Name']."\n";
   }
}
catch (S3Exception $e)
{
   echo $e->getMessage();
}
?>
Enter fullscreen mode Exit fullscreen mode

Ok, that’s pretty basic, but hopefully your code printed out a list of your S3 buckets. Ideally, you’ll already know which bucket you want to upload your files to, so let continue with uploading objects to your preferred S3 bucket.

But first, I’d like to elaborate on how AWS’s Simple Storage Service (S3) works. Amazon S3 calls “files” stored in your bucket objects. This concept can take some getting used to. If you’re familiar with Object-oriented Programming , then you know that objects are a collection of properties and methods to manipulate data. Well, S3 works in a very similar capacity. So when you want to refer to a “file” or “S3 Object,” you’ll refer to it’s key , just as you would programmatically with an object. That being said, instead of file path , AWS S3 calls it a key. The key is a relative path to your S3 bucket’s root, without the preceding slash.

Upload an S3 Object

Ok, let’s upload an image file to our S3 bucket:

<?php
require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Exception\AwsException;

try {
   $s3 = new S3Client($config);

   $fileData = file_get_contents("/path/to/your/image.jpg");
   $mimeType = mime_content_type("/path/to/your/image.jpg");

   $s3->putObject([
      'Key' => 'images/image.jpg',
      'Body' => $fileData,
      'ContentType' => $mimeType
   ]);

}
catch (S3Exception $e)
{
   echo $e->getMessage();
}
?>
Enter fullscreen mode Exit fullscreen mode

Now you should be able to access your object via your CloudFront Distribution Domain Name. If you’re unsure about this, please refer to my previous article. Your full URL path will look something like this:

https://sdf934r3iruihi3u4h.cloudfront.net/images/image.jpg
Enter fullscreen mode Exit fullscreen mode

Invalidate Object from the CloudFront Cache

Files stored in your S3 bucket are automatically cached on the CloudFront edge server’s cache. Unless you want to wait for the TTL (time to live) to expire, you may want to invalidate newly-uploaded objects to get the latest version in your browser. Here’s how to do it in the PHP-SDK:

<?php
use Aws\CloudFront\CloudFrontClient;
use Aws\Exception\AwsException;

try {
   $cf = new CloudFrontClient($config);
   $cf->createInvalidation([
      'DistributionId' => "YOUR_CLOUDFRONT_DISTID',
      'InvalidationBatch' => [
         'CallerReference' => "UNIQUE_CALLER_IDENTIFIER',
         'Paths' => [
            'Items' => [
               'images/images.jpg'
             ],
            'Quantity' => 1
         ]
      ]
   ]);
}
catch (AwsException $e)
{
   echo $e->getAwsErrorMessage();
}
?>
Enter fullscreen mode Exit fullscreen mode

This code will invalidate the cached version of image.jpg and pull the current version from your S3 bucket. The CallerReference property is a unique identifier you need to come up with to identify the source of the request. This is mainly used for logging purposes.

Advanced Example: Concatenating and Minifying JavaScript Code

Ok, let’s get serious. In this example, I’ll show you how to automate concatenating your JavaScript code, minifying it, and then uploading it to your CDN.

You’ll first need to install Mathias Mullie’s Minify library:

$ composer require matthiasmullie/minify
Enter fullscreen mode Exit fullscreen mode

And here’s the code:

<?php
use MatthiasMullie\Minify;
use Aws\Resource\Aws;
use Aws\CloudFront\CloudFrontClient;
use Aws\S3\S3Client;

// Instantiate the Minify/JS class
$m = new Minify\JS;

// Iterate through our array of JavaScript files and concatenate them
foreach ($jsFiles as $file)
{
   $m->add($file);
}

// Minify the code
$out = $m->minify();

// Upload the minified code to our S3 bucket

try {
   $s3 = new S3Client($config);

   $s3->putObject([
      'Key' => 'js/main.min.js',
      'Body' => $out,
      'ContentType' => 'text/javascript'
   ]);

}
catch (S3Exception $e)
{
   echo $e->getMessage();
}

// Invalidate the existing file
try {
   $cf = new CloudFrontClient($config);
   $cf->createInvalidation([
      'DistributionId' => "YOUR_CLOUDFRONT_DISTID',
      'InvalidationBatch' => [
         'CallerReference' => "UNIQUE_CALLER_IDENTIFIER',
         'Paths' => [
            'Items' => [
               'js/main.min.js'
             ],
            'Quantity' => 1
         ]
      ]
   ]);
}
catch (AwsException $e)
{
   echo $e->getAwsErrorMessage();
}
Enter fullscreen mode Exit fullscreen mode

As you can see, this setup can be very powerful for speeding up your web design process by automating things that would normally take a lot of time to do manually. You can use this same code to concatenate and upload CSS as well. Just call Minify/CSS instead of Minify/JS.

I hope you found this guide useful! For more great information, please visit our Blog.

See also: How to Use AWS CloudFront to Create Your Own Free CDN.


Discussion (2)

Collapse
stormytalent profile image
StormyTalent

Really interesting.
Thanks for sharing!

Collapse
designly profile image
Jay @ Designly Author

You bet!