この記事では、LaravelでファイルをS3上へアップロードする手順について解説します。

Amazon S3を準備する

まず、初めにS3バケットを作成してファイルの保存先を作ります。
AWSのコンソールページからバケットを作成します。

バケットを作成する

ファイルを保存する先となるバケットをAWSのコンソールページから作成します。

バケット名を指定して後はそのままの設定値でバケットを作成します。

ユーザーを作成してキーを取得する

バケットにアクセスするためのユーザーを作成しアクセスキーを生成します。
右のプルダウンメニューから「セキュリティ認証情報」をクリックしアクセス管理のユーザーをクリックします。

右上の「ユーザーを追加」ボタンをクリックしユーザーを作成します。

ユーザー名を指定して認証情報タイプを「アクセスキー・プログラムによるアクセス」にチェックを入れます。これにチェックを入れないとLaravelからのアクセスができません。

次のステップへ進むとアクセス許可の設定画面になります。
今回作成するユーザーはS3を使用できるようにするため、「AmazonS3FullAccess」の権限を設定します。
規程のポリシーを選択する形で設定します。

次の画面ではタグの設定画面が表示されますが、特に設定しないのでスキップして次へのボタンをクリックします。
最後の画面は確認画面になります。特に問題なければユーザーを作成します。

ユーザーの作成が完了するとアクセスキーとシークレットキーが表示されます。
このキーは後ほどLaravelでS3へアクセスする際に使用するので忘れないようにメモしておきましょう。
.csv形式でダウンロードして保存しておくのが良いと思います。

AWS側の設定はこれで完了です。

Laravel側での操作

AWS側の設定が完了したら、LaravelでS3へアクセスするための環境を整えます。

S3を操作するパッケージをインストールする

Laravelをインストールすると、configのfilesytem.phpにS3の情報が記述されていてenvファイルにアクセスキーを書き込めば使えそうですが、別途S3へ接続するためのパッケージをインストールする必要があります。
さっそく以下のComposerコマンドを実行してパッケージをインストールします。

composer require league/flysystem-aws-s3-v3

インストール後はプロバイダーの追加など不要です。

envファイルにAWSのキーを書き込む

S3へアクセスするための、アクセスキーとシークレットキーをenvファイルへ書き込みます。
以下のように記述します。

AWS_ACCESS_KEY_ID=#ここにアクセスキーを入れます#
AWS_SECRET_ACCESS_KEY=#ここにシークレットキーを入れます#
AWS_DEFAULT_REGION=ap-northeast-1 #東京リージョンを指定します。
AWS_BUCKET=#バケット名を入れます#
AWS_USE_PATH_STYLE_ENDPOINT=false

これでS3への接続ができるようになりました。

S3へ接続するためのコードを書く

Laravelで適当にコントローラーを作成してS3にアクセスできるか確認します。

$ php artisan make:controller S3Controller

新しいコントローラーを作成したら以下のようにStorageでdiskをS3に指定してフォルダを作成してみます。

<?php

namespace App\Http\Controllers;

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

class S3Controller extends Controller
{
    
    // S3へのファイルアップロード
    public function uploadS3(Request $request)
    {
        // バリデーション
        $request->validate(
            [
                'file' => 'required|file',
            ]
        );

        // S3へファイルをアップロード
        $result = Storage::disk('s3')->put('/', $request->file('file'));

        // アップロードの成功判定
        if ($result) {
            return 'アップロード成功';
        }else {
            return 'アップロード失敗';
        }
    }
    
}

ファイルアップロードのビューを作成します。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>ファイルアップロード</title>
</head>
<body>
    <form action="{{ route('s3') }}" method="post" enctype="multipart/form-data">
        @csrf
        <input type="file" name="file" id="">
        <input type="submit" value="アップロード">
    </form>
</body>
</html>

あとは、ルートをします。

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::view('upload', 'upload');
Route::post('s3', [\App\Http\Controllers\S3Controller::class, 'uploadS3'])->name('s3');

コードは以上で完了です。

ファイルをアップロードしてみる

サーバーを立ち上げてファイルをアップロードしてみます。

$ php artisan serve

ルートで設定したURLへアクセスします。
http://localhost:8000/upload
※画像はローカルドメインになっています。

ファイルのアップロードが成功したら「アップロード成功」の表示がでます。

ファイルがアップロードされたか確認する

AWSのコンソールからS3へアクセスしてファイルが保存されているか確認します。

バケット内にファイルがあればアップロード成功です。

まとめ

Laravelを設置しているサーバーでstorageディレクトリにファイルを格納しすぎた結果、容量が枯渇してHTTP500エラーになることも大いに考えられます。そのため、ファイルを多く取り扱うサイトを構築する際はS3がほぼ必要になります。今回はS3へファイルアップロードを行うことができましたが、クライアント側でS3上のデータを閲覧することができないので別の記事でクライアントがS3へアクセスできるようにする設定やCloudfrontについてを紹介していきたいと思います。