How to use Laravel Storage with AWS S3

This is a guide on setting up and testing the Storage object in Laravel to use Amazon AWS S3. As this is a local project I will be using MinIO as it’s S3 compatible, so when I move code to production I will switch from MinIO to S3.

Setup Laravel project for S3

Open up the terminal, change the current directory to the Laravel project you are using, and run the following command. This will install the library required to make S3 work with the Storage object.

composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies

In your code editor open the .env file and you will notice environment variables for S3.

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

Fill these details in as they are required to connect to it.

MinIO

As I was working on a local project there is no need to use AWS S3 as it’s an online cloud service, you can use MinIO which can be installed locally and is S3 compatible.

To use MinIO fill in the access, secret, and bucket values. You can set a region value as well for the bucket in MinIO which will require you to restart the MinIO server,

Add the following environment variable API URL, the value is the IP address that’s output when starting the MinIO service.

AWS_ENDPOINT=http://192.168.0.199:9000

To use the full path the URL needs to be set in the .env file. Below is an example of my local IP address with “test” being the name of the bucket I created in the MinIO WebUI.

AWS_URL=http://192.168.0.199:9000/test

Create a command to upload files

As these steps will involve uploading files you will need some examples, if you need some example images you can get some from the Lorem Pisum website.

Open up the code editor and create a folder named files to the storage/app directory of the project. Copy some example images inside of this new folder.

Create a command which can be done using the PHP artisan command.

php artisan make:command UploadS3Files

Now open up the UploadS3Files.php file in the app/console/Commands directory.

Copy and paste in the following code and save the file.

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;

class UploadS3Files extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'app:upload-s3-files';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Uploads files to S3';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $files = Storage::files('files');

        foreach ($files as $localFile) {
            $filename = basename($localFile);

            if (!Storage::disk('s3')->exists($filename)) {
                Storage::disk('s3')->putFileAs(
                    '',
                    new File(storage_path('app/files') . '/' . $filename),
                    $filename,
                    'public'
                );
            }
        }
    }
}

Open up the terminal, change to the current directory of the Laravel project, and then copy and paste the command below.

php artisan app:upload-s3-files

Create a controller and blade template to show images

Open up the terminal to create a few PHP files.

Run the following to create a Controller class.

php artisan make:controller ImagesController

Run the following to create a blade view template.

 php artisan make:view view-images

Open up the routes/web.php and add the following line so the route is linked to the controller.

Route::get('/images', [App\Http\Controllers\ImagesController::class, 'show']);

Open up the Controller file, and copy and paste the following code, the controller is found in the app/Http/Controllers directory.

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Storage;

class ImagesController extends Controller
{
    public function show()
    {
        $images = Storage::disk('s3')->files();
        $images = array_map(fn($image) => Storage::disk('s3')->url($image), $images);

        return view('view-images', ['images' => $images]);
    }
}

Open up the view-images.blade.php file found in the laravel/resources/views directory, copy and paste the following code into the file, and then save.

<div>
    @foreach ($images as $image)
        <div style="margin-bottom: 20px">
            <img src="{{ $image }}" style="width: 400px" />
        </div>
    @endforeach
</div>

Go back to the terminal and run the application.

php artisan serve

Go to the URL http://127.0.0.1:8000/images to see the images uploaded.

uploaded-images.png