こんにちは!
突然ですが、皆さんは画像保存する場合にどのように保存していますか?
Webサーバーに保存するというのは一般的かもしれません。
ただ、Amazon S3に画像を保存すると、Webサーバーに画像保存する必要がなくなり、容量を圧迫せずに済んだりと何かとメリットが大きいです。
Amazon S3を活用するメリットは、一般的には以下のようなものがあるとされています。
- スケーラビリティ・・・大規模なトラフィックやデータ増加に耐えられる
- 低コスト・・・使用した分だけ課金される従量課金制。コストを最小限に抑えられる
- 高速なデータ転送・・・高速かつ安定したデータ転送ができる
- セキュリティとアクセス制御・・・バケットポリシーやIAMロールを使用して、データへのアクセスを制御できる
などなど。
そこで、今回はLaravelを使ったS3への画像アップロード方法をご紹介していきます。

「LaravelでS3に画像保存する手順を知りたい」
このようにお考えの方には参考になるかと思います。
それでは、早速見ていきましょう!
前提
- AWSアカウントをすでに持っていること
LaravelからS3へ画像アップロードする方法
バケットを作成する
まずは、S3にバケットを作成していきます。
AWSの「Amazon S3」に入り、以下の「バケットを作成」をクリック。

バケットの設定を行う
- バケットタイプ・・・汎用
- バケット名・・・任意の名前
- オブジェクト所有者・・・ACL 無効
- ブロックパブリックアクセス・・・「パブリックアクセスをすべてブロック」を解除
- バケットのバージョニング・・・無効にする
- タグ・・・なし
- デフォルトの暗号化・・・Amazon S3 マネージドキーを使用したサーバー側の暗号化 (SSE-S3)。バケットキーは有効にする
これらを設定し、「バケットを作成」をクリック。
バケットポリシーの編集
- 対象のバケットを選択
- 「プロパティ」タブを開く
- ARNをコピーしメモしておく
- 「アクセス許可」タブを開く
- バケットポリシーの編集ボタンをクリック
- ポリシージェネレータを開く
ポリシージェネレータでは、以下のように入力します。
- Select Type of Policy・・・S3 Bucket Policy
- Effect・・・Allow
- Principal・・・「*」を入力
- AWS Service・・・Amazon S3
- Actions・・・All Actionsにチェック
入力したら、「Add Statement」をクリックします。
続いて「Generate Policy」をクリックします。
Policy JSON Documentが出てくるのでコピーして閉じる。
バケットポリシー編集画面に戻ってコピーしたPolicyをペーストし、変更を保存する。

IAMユーザーを作成
次に、IAM > ユーザーに入って、「ユーザーの作成」をクリックします。
ユーザー名には適当なユーザー名を入力します。

次に、以下のように設定します。
- 許可のオプション・・・「ポリシーを直接アタッチする」を選択
- 許可ポリシー・・・「AmazonS3FullAccess」を選択

最後に確認画面が出てくるので、問題なければ「ユーザーの作成」をクリック。
ユーザーが作成されるので、詳細画面に入って、「アクセスキーを作成」をクリック。

ユースケースに「コマンドラインインターフェース(CLI)」を選択します。

設定タグ値には任意の説明を入れて、「アクセスキーを作成」をクリック。

アクセスキーとシークレットキーが作成されるので、CSVダウンロードして漏れないように大切に保管してください。
このアクセスキーとシークレットキーは後ほど使っていきます。
LaravelプロジェクトにS3用パッケージをインストールする
以下のコマンドからFlysystem S3パッケージをインストールします
composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies
S3用の設定を追加
「config/filesystems.php」に以下を追記します。
'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,
],
環境変数の設定
AWS用の環境変数を設定します。
AWS_ACCESS_KEY_ID=アクセスキー
AWS_SECRET_ACCESS_KEY=シークレットキー
AWS_DEFAULT_REGION=ap-northeast-1(東京リージョンの場合)
AWS_BUCKET=バケット名
AWS_USE_PATH_STYLE_ENDPOINT=false
アクセスキーには作成しておいたIAMユーザーのアクセスキーとシークレットキーを記述します。
S3へのアップロード処理
以下、S3へのアップロード処理の一例です。
public function store(Request $request)
{
...
// s3に保存
$path = Storage::disk('s3')->put('images', $request->file('image'));
$post->image_path = Storage::disk('s3')->url($path);
$post->save();
return redirect()->route('post.index');
}
Storageファサードのメソッドはput
を使っていますが、そのほかにもputFile
やputFileAs
メソッドなどがあります。
put
はメモリ消費が一番大きいのでここは適時検討してください。
フォーム
<form action="{{ route('post.store') }}" method="post" enctype="multipart/form-data">
@csrf
<div class="form-group">
<label for="post-image">投稿画像</label>
<input type="file" name="image" id="post-image">
</div>
...
<button type="submit">投稿</button>
</form>
formタグに「enctype=”multipart/form-data”」の記述を忘れないよう注意です。
これを忘れると動きません。
画像表示
@foreach ($posts as $post)
<div class="card">
<div class="card-img">
<img src="{{ $post->image_path ? $post->image_path : 'img/sample-img.jpeg' }}" alt="サンプル画像">
</div>
...
</div>
@endforeach
DBに保存しておいた画像パスを取得してsrc属性に入れています。取得できなかった場合は、事前に用意しておいたサンプル画像を差し込んでいます。
テストコード
use Illuminate\\Support\\Facades\\Storage; // 追加
use Illuminate\\Http\\UploadedFile; // 追加
public function test_store(): void
{
Storage::fake('s3');
$file = UploadedFile::fake()->image('test.jpg');
// login_userが認証を通過しているとする
$this->assertAuthenticatedAs($this->login_user);
$response = $this->actingAs($this->login_user)->post(route('post.store'), [
'title' => 'Test Title',
'body' => 'Test Body',
'image' => $file,
]);
$response->assertStatus(302);
Storage::disk('s3')->assertExists('images/' . $file->hashName());
$response->assertRedirect(route('post.index'));
}
Storage::fake()
メソッドとUploadedFile::fake()
メソッドを使えば、簡単にテストすることができます。
動作確認
最後に、動作確認。

画像表示ができました!素晴らしい!👏
コメント