Using S3 with Laravel

https://laravelnews.imgix.net/images/aws-s3-1644204940.jpg?ixlib=php-3.3.1

AWS S3 provides a place for us to store files off of our servers. There are some big benefits to this:

  1. Backup/redundancy – S3 and similar have built-in backups and redundancy
  2. Scaling – Savings files off-server becomes necessary in modern hosting, such as serverless or containerized environments, as well as in traditional load-balanced environments
  3. Disk usage – You won’t need as much disk space when storing files in the cloud
  4. Features – S3 (and other clouds) have some great features, such as versioning support for files, lifecycle rules for deleting old files (or storing them in a cheaper way), deletion protection, and more

Using S3 now (even in single-server setups) can reduce headaches in the long run. Here’s what you should know!

Configuration

There’s two places to configure things for S3:

  1. Within Laravel – usually via .env but potentially also within config/filesystem.php
  2. Within your AWS account

Laravel Config

If you check your config/filesystem.php file, you’ll see that s3 is an option already. It’s setup to use environment variables from your .env file!

Unless you need to customize this, then you can likely leave it alone and just set values in the .env file:

1# Optionally Set the default filesystem driver to S3

2FILESYSTEM_DRIVER=sqs

3 

4# Add items needed for S3-based filesystem to work

5AWS_ACCESS_KEY_ID=xxxzzz

6AWS_SECRET_ACCESS_KEY=xxxyyy

7AWS_DEFAULT_REGION=us-east-2

8AWS_BUCKET=my-awesome-bucket

9AWS_USE_PATH_STYLE_ENDPOINT=false

The config/filesystem.php file contains options like the following:

1return [

2 'disks' => [

3 // 'local' and 'public' ommitted...

4 

5 's3' => [

6 'driver' => 's3',

7 'key' => env('AWS_ACCESS_KEY_ID'),

8 'secret' => env('AWS_SECRET_ACCESS_KEY'),

9 'region' => env('AWS_DEFAULT_REGION'),

10 'bucket' => env('AWS_BUCKET'),

11 'url' => env('AWS_URL'),

12 'endpoint' => env('AWS_ENDPOINT'),

13 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),

14 ],

15 ],

16];

There’s a few options there we didn’t use in the .env file. For example, the AWS_URL can be set, which is useful for using other file storage clouds that have an S3 compatible API such as CloudFlare’s R2 or Digital Ocean’s Spaces.

AWS Configuration

Within AWS, you need to do 2 things:

  1. Create a bucket within the S3 service
  2. Create an IAM User to get a Key/Secret Key, and then attach a Policy to that user that allows access to the S3 API.

Like anything in AWS, creating a bucket in S3 involves looking at a ton of configuration options and wondering if you need any of them. For most use cases, you don’t!

Head to the S3 console, create a bucket name (it has to be globally unique, not just unique to your AWS account), choose the region you operate in, and leave all the defaults (including the ones that labeled “Block Public Access settings for this bucket”).

Yes, some of these options are ones you may want to use, but you can choose them later.

After creating a bucket, we need permission to do things to it. Let’s pretend we created a bucket named “my-awesome-bucket“.

We can create an IAM User, select “programmatic access”, but don’t attach any policies or setup anything else. Make sure to record the secret access key, as they’ll only show it once.

I’ve created a video showing the process of creating a bucket and setting up IAM permissions here: https://www.youtube.com/watch?v=FLIp6BLtwjk

The Access Key and Secret Access Key should be put into your .env file.

Next, click into the IAM User and add an Inline Policy. Edit it using the JSON editor, and add the following (straight from the Flysystem docs):

1{

2 "Version": "2012-10-17",

3 "Statement": [

4 {

5 "Sid": "Stmt1420044805001",

6 "Effect": "Allow",

7 "Action": [

8 "s3:ListBuckets",

9 "s3:GetObject",

10 "s3:GetObjectAcl",

11 "s3:PutObject",

12 "s3:PutObjectAcl",

13 "s3:ReplicateObject",

14 "s3:DeleteObject"

15 ],

16 "Resource": [

17 "arn:aws:s3:::my-awesome-bucket",

18 "arn:aws:s3:::my-awesome-bucket/*"

19 ]

20 }

21 ]

22}

This allows us to perform the needed S3 API actions on our new bucket.

Laravel Usage

Within Laravel, you can use the file storage like so:

1# If you set S3 as your default:

2$contents = Storage::get('path/to/file.ext');

3Storage::put('path/to/file.ext', 'some-content');

4 

5# If you do not have S3 as your default:

6$contents = Storage::disk('s3')->get('path/to/file.ext');

7Storage::disk('s3')->put('path/to/file.ext', 'some-content');

The path to the file (within S3) gets appended to the bucket name, so a file named path/to/file.ext will exist in s3://my-awesome-bucket/path/to/file.ext.

Directories technically do not exist within S3. Within S3, a file is called an “object” and the file path + name is the “object key”. So, within bucket my-awesome-bucket, we just created an object with key path/to/file.ext.

Be sure to check out the Storage area of the Laravel docs to find more useful ways to use Storage, including file streaming and temporary URL’s.

Pricing

S3 is fairly cheap – most of us will spend pennies to a few dollars a month. This is especially true if you delete files from S3 after you’re done with them, or setup Lifecycle rules to delete files after a set period of time.

The pricing is (mostly) driven by 3 dimensions. The prices vary by region and usage. Here’s an example based on usage for a real application in a given month for Chipper CI (my CI for Laravel application), which stores a lot of data in S3:

  1. Storage: $0.023 per GB, ~992GB ~= $22.82
  2. Number of API Calls: ~7 million requests ~= $12
  3. Bandwidth usage: This is super imprecise. Data transfer for this was about $23, but this excludes EC2 based bandwidth charges.

Useful Bits about S3

  1. If your AWS setup has servers in a private network, and uses NAT Gateways, be sure to create an S3 Endpoint (type of Gateway). This is done within the Endpoints section in the VPC service. This allows calls to/from S3 to bypass the NAT Gateway and thus get around extra bandwidth charges. It doesn’t cost extra to use this.
  2. Considering enabling Versioning in your S3 bucket if you’re worried about files being overwritten or deleted
  3. Consider enabling Intelligent Tiering in your S3 bucket to help save on storage costs of files you likely won’t interact with again after they are old
  4. Be aware that deleting large buckets (lots of files) can cost money! This is due to the number of API calls you’d have to make to delete files.

Laravel News

Rudy Giuliani Shocker: Revealed as Contestant on Fox’s ‘Masked Singer,’ Triggers Liberal Judges to Walk Off

https://www.louderwithcrowder.com/media-library/image.jpg?id=29228886&width=980

If you watch FOX’s "The Masked Singer" and are worried about spoilers… Whoops, too late! Rudy Guliani was revealed as one of the masked singers and two of the liberal judges were pissed. First, if you are unfamiliar with the show–I’ve never watched and am going off of this Deadline article–this is the masked singer.


Preview: The Good, The Bad, And The Cuddly | Season 7 | THE MASKED SINGER

youtu.be

Celebrities dress up as furries and sing songs. Other celebrity judges have to guess who the celebrity is. On a taping for the debut episode, one of those celebrities is Rudy Guiliani. If you want to know what furry he was or what song he sang, you’ll have to tune in to the show. OR, you can not care. What’s making the story trend is that two leftist judges, Robin Thicke and Ken Jeong, walked off in protest.

Robin Thicke is best known as being Alan Thicke’s less talented son, and for that one song where he stole the melody from Marvin Gaye. That one song people say is kinda rapey. Except, now, the people who call it rapey won’t care as much after Thicke stuck it to a Trump associate by walking off a stage. Ken Jeong is best known from this gif:

Rudy Guliani is, as you all know, the former Mayor of New York City and a frequent guest on the Louder with Crowder program. He’s also friends with Donald Trump and was in the news for some legal challenge that if mentioned will cause Facebook to immediately slap this post with a "fact" check. I’ll just say those legal challenges are most likely what triggered Thicke and Jeong. That, and how dare Fox normalize someone who has a different opinion than them. Leftists hate it when that happens.

If you were wondering why Rudy is trending today, I hope this clears things up.

The Louder with Crowder Dot Com Website is on Instagram now! Follow us at @lwcnewswire and tell a friend!


Steak-FIGHT at the Golden Corral! Crowder & Dave Rip on it for 10 minutes! | Louder With Crowder

youtu.be

Louder With Crowder

PHP Monitor 5.0 for macOS is Here

https://laravelnews.imgix.net/images/phpmon-5-0-featured.png?ixlib=php-3.3.1

PHP Monitor, the lightweight native Mac app to manage PHP and Laravel Valet, has released v5.0!

The author Nico Verbruggen announced the release yesterday:

Here are some of the highlight features summarized from the release notes:

  • Link a folder in Valet
  • Site list performance improvements
  • Faster and improved site search
  • Site list displays project type (i.e., Laravel, WordPress, etc.) from composer.json
  • Brew services status in the dropdown menu (PHP, Nginx, Dnsmasq, etc.)
  • See project’s PHP version requirement at a glance in the site list
  • Compatibility status per site
  • Change PHP versions from the compatibility status on the sites list
  • Automatic update of PHP INI changes
  • Alfred integration
  • Sponsor awareness – a one-time message to sponsor the author

One of my favorite features added is linking a folder and securing it (adding HTTPS) during creation:

PHP Monitor folder linking example

Linking a folder makes it convenient to manage projects via the UI and visualize the requirements for all your sites in one place. The site list updates in v5.0 are insane!

On his blog, the author has written about the 5.0 release with insider details. I recommend giving it a read and following the author for future updates.

To get started, check out the GitHub project for documentation and installation instructions. Since this project is free and open-source, you can support the creator by sponsoring his work.

Laravel News

Optimus Prime Wants You to Go the Hell to Sleep

https://i.kinja-img.com/gawker-media/image/upload/c_fill,f_auto,fl_progressive,g_center,h_675,pg_1,q_80,w_1200/ba009492ecde73f47b299db909a23498.jpg

You can now have Optimus Prime read you a bedtime story. This is not a sentence I expected to write today, and yet, it is now an inescapable fact that you can go to bed listening to the dulcet tones of the leader of the Autobots… as he describes the horrible wars that enveloped his home planet Cybertron before coming to Earth. Sweet dreams!

To clarify, you’ll need to have access to the immensely popular meditation/relaxation/sleep assistance app Calm—specifically, the Calm Kids iteration—to hear Optimus narrate a “Sleep Story,” which the company describes as being “soothing tales that mix music, sound fx, and incredible voice talent to help you drift into dreamland.” The story is titled “History of the Transformers,” which doesn’t seem like a tale that would be easy to drift off to given that the vast majority of it has to do with the endless wars between the Autobots and the Decepticons.

That said, Optimus, as per the classic cartoons and modern live-action movies, is played by Peter Cullen, whose deep, low, soothing voice seems absolutely tailor-made to lull just about anyone to sleep, no matter what he was reading. You can get a too-brief 30-second preview of the Sleep Story over at Calm, and hear for yourself.

The press release adds, “This never-before-heard Transformers story tells the history of the Autobots and Decepticons, taking listeners deeper into the More-Than-Meets-the-Eye themes of the iconic franchise, exploring bravery, leadership, friendship, and STEM.” I’m very curious about how much importance will be placed on science, technology, engineering, and mathematics in the recording, given that 1) virtually all of the STEM in Transformers is made up, and 2) I don’t know much you’re going to learn about these sciences while you are literally falling asleep. There’s not a chance in hell that any fact I heard would remain in my mind come daybreak, no matter what robot told it to me

“History of the Transformers” is available now in the Calm Kids app. If we’re lucky, the next release will be terrorist leader Cobra Commander reading a bedtime story about the time he created an entire game show just to make G.I. Joe feel dumb.


Wondering where our RSS feed went? You can pick the new up one here.

Gizmodo

Comic for February 01, 2022

https://assets.amuniversal.com/45d192405d30013a93c2005056a9545d

Thank you for voting.

Hmm. Something went wrong. We will take a look as soon as we can.

Dilbert Daily Strip

Database transaction middleware in Laravel

https://nico.orfanos.dev/card.png

Why transactions are a good thing.

Let’s say that in your application all users have to belong to a team. And in your createUser action, you create a user and then you assign this user a team.

$user = User::create(['email'=> '[email protected]'); $user->teams()->attach($team->id); //Throws an exception

If you get an Exception while attaching the Team to the User, your application ends with a wrong state where you have a User which hasn’t a Team assigned.

This is simple to fix in this case, but it can be more complex in other cases and by using database transactions will yourself these state fixes. Because, when using database transactions, if the team assignment throws an exception, your application will also prevent the user creation.

How to implement write transactions in Laravel

Database transactions are good practice for all write actions. Therefore we create a global middleware for this, using the following command.

$ php artisan make:middleware DatabaseTransaction

and we change the handle method like below:

//app/Http/Middleware/DatabaseTransaction.php public function handle($request, \Closure $next) { if (!in_array($request->method(),['POST','PUT','PATCH','DELETE'])) { return $next($request); } DB::beginTransaction(); try { $response = $next($request); } catch (\Exception $e) { DB::rollBack(); throw $e; } if ($response->getStatusCode() > 399) { DB::rollBack(); } else { DB::commit(); } return $response; }

This code will check if we make a write operation by checking if the request method of the request is a write one, and start a transaction. If within the write request something goes wrong it will roll back the transaction.

The only thing left to do is to register the middleware to our web middleware group in the app/Http/Kernel.php.

//app/Http/Kernel.php protected $middlewareGroups = [ 'web' => [ // ... \App\Http\Middleware\DatabaseTransaction::class ], ];

Now your application will use this DatabaseTransaction middleware on every request.

What to keep in mind

Once you have fully integrated database transactions in your applications, there is this one thing that you need to watch out for when dispatching jobs. If you dispatch a job and later your application rolls back, your job will still be processed by your queue.

For that reason, Laravel has the afterCommit method which you can chain after the dispatch. This way you are safe that the dispatch will only run if the response was successful.

So if you also are sending an email after the user creation, your code should look like this:

$user = User::create(['email'=> '[email protected]'); $user->teams()->attach($team->id); dispatch(new SendWelcomeEmail($user))->afterCommit();

Final words

The accuracy, completeness, and reliability of your database data are viable things for your application. Using database transactions in Laravel is easy for us to take advantage of them.

Laravel News Links