※本記事は嘉数の個人ブログ(LaravelでS3へファイルをアップロード・参照する - けけずんセルフハッキング)からの転載になります
概要
LaravelでアップロードされたファイルをS3に保存・参照する。
ファイルアップロード時の処理は下図の通り、クライアントからLaravelを通ってS3に保存される。
ファイルを参照する際は下図の通り、Laravelが対象となるファイルのURLをS3から取得してページにリンクする。URLからS3上のファイルを参照するために、対象となるファイルはPublicに公開される必要がある。
環境
- Laravel 5.5.36
Laravelが動作するEC2、ファイル保存・参照先となるS3バケットは作成済みとする。
手順
AWS側の操作
AWSコンソールへログインし、以下の操作を行う。
IAMユーザーの作成
サービス「IAM」からサイドバーの「ユーザー」をクリックし、続いて以下の操作を行う。
- 「ユーザーを追加」をクリックする
- 「ユーザー名」を入力する
- 「プログラムによるアクセス」にチェックを入れる
- 「次のステップ:アクセス権限」をクリックする
- 「ユーザーをグループに追加」を選択する
- 「次のステップ:確認」をクリックする
- 「ユーザーの作成」をクリックする
ここでユーザの作成が完了する。このとき、作成したユーザーのセキュリティ認証情報が記述されたファイル(CSV)がダウンロード出来るので、ダウンロードしておく。
IAMユーザのアクセス権限を設定
サービス「IAM」からサイドバーの「ユーザー」をクリックし、続いて以下の操作を行う。
- 作成したユーザーをクリックする
- 「アクセス権限」タブを選択し、「インラインポリシー」をクリックする
- 「ビジュアルエディタ」タブにある項目を以下のように入力する
- 「Review policy」をクリックする
- 「名前」を入力する
- 「Create a policy」をクリックする
ちなみにJSONは以下のようになる。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:PutObjectAcl" ], "Resource": "arn:aws:s3:::mybucket/myprefix/*" } ] }
Resource
要素の末尾に*
がないと指定したプレフィックス(今回はmyprefix
)以下を操作する権限がないと言われるので注意!
Laravel側の操作
パッケージをインストール
Laravelプロジェクトフォルダ下で以下のコマンドを入力する。
$ composer require league/flysystem-aws-s3-v3
これによりLaravelのファイルシステムでファイルの保存・参照先をS3に向けるためのパッケージがインストールされる。
.envを編集
.env
ファイルに以下を追記する。
AWS_S3_KEY=[AWS S3接続用ユーザのAccess Key ID] AWS_S3_SECRET=[AWS S3接続用ユーザのSecret Key] AWS_S3_REGION=[AWS S3設置リージョン] AWS_S3_BUCKET=[AWS S3のバケット名]
config/filesystems.phpを編集
config/filesystems.php
を以下のように編集する。
<?php return [ 'default' => 'local', 'cloud' => 's3', 'disks' => [ 'local' => [ 'driver' => 'local', 'root' => storage_path('app'), ], 'public' => [ 'driver' => 'local', 'root' => storage_path('app/public'), 'url' => env('APP_URL').'/storage', 'visibility' => 'public', ], + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_S3_KEY'), + 'secret' => env('AWS_S3_SECRET'), + 'region' => env('AWS_S3_REGION'), + 'bucket' => env('AWS_S3_BUCKET'), + ], ], ];
Controllerの作成
以下のコマンドでControllerを作成する。
$ php artisan make:controller UploadContentController
app/Http/Controllers/UploadContentController.php
を以下のように編集する。
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class UploadContentController extends Controller { public function index() { return view('upload'); } public function store(Request $request) { $this->validate($request, ['myfile' => 'required|image']); $image = $request->file('myfile'); /** * 自動生成されたファイル名が付与されてS3に保存される。 * 第三引数に'public'を付与しないと外部からアクセスできないので注意。 */ $path = Storage::disk('s3')->putFile('myprefix', $image, 'public'); /* 上記と同じ */ // $path = $image->store('myprefix', 's3'); /* 名前を付与してS3に保存する */ // $filename = 'hoge.jpg'; // $path = Storage::disk('s3')->putFileAs('myprefix', $image, $filename, 'public'); /* ファイルパスから参照するURLを生成する */ $url = Storage::disk('s3')->url($path); return redirect()->back()->with('s3url', $url); } }
Viewの作成
resources/views/upload.blade.php
を作成し、以下のようにする。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Upload S3 Test</title> </head> <h1>S3アップロードテスト</h1> {!! Form::open(['url' => '/upload', 'method' => 'post', 'class' => 'form', 'files' => true]) !!} <div class="form-group"> {!! Form::label('myfile', 'Upload a file') !!} {!! Form::file('myfile', null) !!} </div> <div class="form-group"> {!! Form::submit('Upload') !!} </div> {!! Form::close() !!} @if (session('s3url')) <h1>いまアップロードしたファイル</h1> <img src="{{ session('s3url') }}"> @endif </html>
考察
LaravelからS3に対してファイルのアップロード及びファイルの参照を行うことができた。Controller内でファイルアップロード時のS3のプレフィックスを指定している箇所があるが、毎回同じプレフィックスを指定するの面倒くさいな。何かいい方法ないかな。