Laravel can't connect to AWS S3

7.6k Views Asked by At

I have set up an S3 bucket and created an IAM user with full S3 access permission, and ran composer require league/flysystem-aws-s3-v3.

I have also have configured the following in .env:

AWS_ACCESS_KEY_ID=XXXX
AWS_SECRET_ACCESS_KEY=YYYY
AWS_DEFAULT_REGION=us-west-3
AWS_BUCKET=my-bucket
AWS_USE_PATH_STYLE_ENDPOINT=false
FILESYSTEM_DRIVER=s3

The problem is that I can't interact with S3 at all from my controller. I've tried sending files to S3:

$path = $request->Image->store('images', 's3');

I have also manually uploaded an image to S3, then tried to check if it can find it:

if (Storage::disk('s3')->exists('photo.jpg')) {
dd("file found");
} else{
dd("file not found");
}

This results in this error: Unable to check existence for: photo.jpg

This makes me think that the issue is with flysystem-aws-s3-v3.

Is there a way to narrow down where the issue resides? by the way, I'm using Laravel 9 and flysystem-aws-s3-v3 3.0 if that helps.

2

There are 2 best solutions below

0
On BEST ANSWER

I finally found the reason why the connection didn't work. This is how the .env file looked like:

//some env vars here...

AWS_ACCESS_KEY_ID=XXXX
AWS_SECRET_ACCESS_KEY=YYYY
AWS_DEFAULT_REGION=us-west-3
AWS_BUCKET=my-bucket
AWS_USE_PATH_STYLE_ENDPOINT=false
FILESYSTEM_DRIVER=s3

//many other env vars here...

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=

It turns out that Laravel (or maybe it was Flysystem?) already configured the same S3 variables and left the values empty. So my environment variables were getting overridden by these empty ones, leaving the connection to fail. I guess the lesson to learn here is to always check your entire .env file if it contains multiple vars with the same key.

Bonus

After setting up S3 with Laravel, you could use these snippets to:

  • Generate a random string as new name for your image file:
$imageName = preg_replace('/[\W]/', '', base64_encode(random_bytes(18)));
  • Save an image to your S3 bucket:
Storage::disk('s3')->put($newImagePath, file_get_contents($imageName));
 //$imageName is just a string containing the name of the image file and it's extension, something like 'exampleImage.png'
 //make sure to include the extension of the image in the $imageName, to do that, concatenate your the name of your image with "." + $Image->extension()
  • Get an image from your S3 bucket:
$image =  Storage::disk('s3')->temporaryUrl($imagePath, Carbon::now()->addSeconds(40));   //tip: if you get a squiggly line on tempraryUrl(), it's just Intelephense shenanigans, you can just ignore it or remove it using https://github.com/barryvdh/laravel-ide-helper 
//This will generate a temporary link that your Blade file can use to access an image, this link will last for 40 seconds, this 40 seconds is the period when the image link will be accessible.
//Of course after your image loads onto the browser, even if the image link is gone, the image will remain on the page, reloading the page generates a new image link that works for another 40 seconds. 
//This will work even with S3 images stored with Private visibility.

//In your blade file:
<img src="{{$image}}">
  • Check if an image exists in your S3 bucket:
if (Storage::disk('s3')->exists($imagePath)) {  //make sure to include the full path to the image file in $imagePath
//do stuff
}
  • Delete an image from your S3 bucket:
Storage::disk('s3')->delete($imagePath);
3
On

It looks like you did everything right! .. is it working for the local drive?

also you might try to flush the cache:

php artisan cache:clear
php artisan config:clear