Laravel 11でAmazon S3に画像を保存し、表示する手順

コード

1. パッケージのインストール

まず、S3を使用するために必要な aws/aws-sdk-php パッケージがインストールされているか確認します。インストールされていない場合は以下のコマンドで追加します。

composer require league/flysystem-aws-s3-v

2. AWS設定の追加

config/filesystems.php にS3設定を追加します。env関数で環境変数から情報を読み込むよう設定すると、管理がしやすくなります。

config/filesystems.php

// おそらく大体の場合はすでに書いてあるので、変更不要。
// 以下、envから読み込むので、自分の環境に合わせて書き換えなくて大丈夫です。
's3' => [
    'driver' => 's3',
    'key' => env('AWS_ACCESS_KEY_ID'),
    'secret' => env('AWS_SECRET_ACCESS_KEY'),
    'region' => env('AWS_DEFAULT_REGION'),
    'bucket' => env('AWS_BUCKET'),
    'url' => env('AWS_URL'),
    'endpoint' => env('AWS_ENDPOINT'),
    'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
    'throw' => false,
],

.env

// ここは自分の環境に合わせて書き換え

AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_DEFAULT_REGION=your_region
AWS_BUCKET=your_bucket_name
AWS_URL=https://your_bucket_name.s3.amazonaws.com

3. 画像のアップロード処理

ファイルのアップロードをコントローラで実行する方法を示します。

ここではユーザー情報にプロフィール画像をアップロードするという設定で実装方法を記述しています。

UserController.php

// UserController

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class UserController extends Controller
{

    // 新規追加の保存
    public function store(Request $request)
    {
        $request->validate([
            'name' => ['required', 'string', 'max:100'],
            'profile_image' => ['nullable', 'image', 'mimes:jpeg,png,jpg,gif', 'max:2048'],
        ]);

        // 画像のアップロード
        $profileImagePath = null;
        if ($request->hasFile('profile_image')) {
            // ファイルをS3にアップロード
            $profileImagePath = $request->file('profile_image')->store('profile_images', 's3');
            // アップロードしたファイルのアクセスを制限する(デフォルトでprivate)
            Storage::disk('s3')->setVisibility($profileImagePath, 'private');
        }
        
        $user = User::create([
            'name' => $request->first_name." ".$request->last_name,
            'profile_image' => $profileImagePath,
        ]);

        return redirect()->route('admin.users.index')->with('success', '作成されました。');
    }
}

create.blade.php

<form action="{{ route('admin.users.store') }}" method="POST"  enctype="multipart/form-data">
    <div class="mb-3">
        <label for="last_name" class="form-label">last_name</label>
        <input type="text" class="form-control" id="last_name" name="last_name" value="{{ old('last_name') }}" required>
    </div>
    <div class="mb-3">
        <label for="profile_image" class="form-label">プロフィール画像</label>
        <input type="file" class="form-control" id="profile_image" name="profile_image">
    </div>

    <div class="pt-3">
        <button type="submit" class="btn btn-primary">新規作成</button>
    </div>
</form>

4. 画像の表示

S3に保存した画像を表示するには、S3のURLをそのままHTMLの画像タグなどに埋め込むことができます。

大体の場合は、セキュリティの観点からアクセス可能な時間を設定すると思います。その場合は、以下のようにModels内に書いておくと楽です。

Models/User.php

use Illuminate\Support\Facades\Storage;

class User extends Authenticatable
{
    // s3 署名付きURLを取得するメソッド
    public function getFileUrl($filePath)
    {
        if ($filePath) {
            return Storage::disk('s3')->temporaryUrl(
                $filePath, now()->addMinutes(15)
            );
        }
        return null;
    }
}

Bladeテンプレートでの表示例

// s3 署名付きURLを取得するメソッドを使う
@if ($user->profile_image )
    <img src="{{ $user->getFileUrl($user->profile_image) }}" alt="Profile Image" class="">
@else
    <span>画像なし</span>
@endif

前提として、AWSのS3にアクセス可能なIAMユーザーのアクセスキーとシークレットキーが設定されていることを想定しています。