アップロードしたファイルの保存のメソッドがLaravelで5.3で少し変わりました。ここでそれらの情報更新とともに、AmazonのストレージサービスS3にファイルをアップロードする仕方を紹介します。
まず、準備から、
パッケージの追加と設定
コマンドラインで以下の実行が必要です。
composer require league/flysystem-aws-s3-v3 ~1.0
これにより、
config/filesystems.php
の設定ファイルが作成されます。
return [
'default' => 'local',
'cloud' => 's3',
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => 'AWSのキー',
'secret' => '秘密のキー',
'region' => '地域のコード', // 日本なら、ap-northeast-1
'bucket' => 'バケット名'
],
],
];
localは、使用しているサーバーのストレージのことです。
rootは、Laravelをインストールしたディレクトリのサブディレクトリ、storage/appの場所となります。
publicは、ウェブユーザーにアップロードしたファイルをパブリックに紹介する場所です。
以下の実行で、public/storageが、storage/app/publicにリンクされます
php artisan storage:link
例えば、アップロードされたファイルは、
storage/app/public/mario.jpg
に保存され、
http://localhost/public/storage/mario.jp
で閲覧できるということです。
s3のkey, secret, region, bucketの指定は必須です。これらは、Amazonのウェブサービスのコンソールで取得できます。
これで設定終わりです。
ファイルのアップロードのプログラム
簡単なファイルのアップロードのプログラムを書いてみます。
まず、routeの設定から、
Route::get('upload', 'UploadController@create');
Route::post('upload', 'UploadController@store');
これで、
http://localhost/upload
にアクセス可能です。
次にコントローラ、
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Storage;
class UploadController extends Controller
{
public function create()
{
return view('upload');
}
public function store(Request $request)
{
$filename = $request->file('image')->getClientOriginalName(); //アップロードしたファイル名を取得
$path = $request->file('image')->storeAs('public', $filename);
return back()->with('filename' => $filename);
}
}
storeAs('public', $filename);
この最初のパラメータは、ファイルを保存するディレクトリ名です。先のconfig/filesystems.phpの設定で、storage/appがルートのディレクトリゆえに、上のコードではstorage/app/publicにファイルが保存されることになります。
ファイル名がmario.jpgであれば、
storage/app/public/mario.jpg
と保存されます。
ファイルをアップロードするフォームのブレードは、
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Media Upload</div>
<div class="panel-body">
<form class="form-horizontal" role="form" method="POST" action="{{ url('upload') }}" enctype="multipart/form-data">
{{ csrf_field() }}
<div class="form-group">
<label for="image" class="col-md-4 control-label">File</label>
<div class="col-md-6">
<input id="image" type="file" name="image">
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Upload
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-body">
@if (session('filename'))
<h4>Local</h4>
<img src="{!! asset('storage/'.session('filename')) !!}">
@endif
</div>
</div>
</div>
</div>
</div>
@endsection
先の例で、ファイル名が、mario.jpgならば、
asset('storage/'.session('filename'))
は、
http://localhost/public/storage/mario.jpg
のようになるわけです。
ファイルをアップロードした後の画面はこんな感じです。

S3に画像をアップロード
さて、サーバーにアップした画像を、今度はS3にアップするのですが、これはconfig/filesystems.phpの設定が済んでいれば、本当に簡単です。
コントローラのstoreメソッドにたったの2行追加するだけです。
public function store(Request $request)
{
$filename = $request->file('image')->getClientOriginalName();
$path = $request->file('image')->storeAs('public', $filename);
$contents = Storage::get('public/'.$filename); //ファイルを読み取る
Storage::disk('s3')->put($filename, $contents, 'public'); // S3にアップ
return back()->with(['filename' => $filename]);
}
>put($filename, $contents, 'public')
ここのpublicに注意してください。これがないと一般には公開されません。
以下のAWSのコンソールの赤箱の部分がそれにより追加されます。

先の画面にS3から直接画像を表示したいなら、ブレードに以下の変更を。
<div class="panel-body">
@if (session('filename'))
<h4>Local</h4>
<img src="{!! asset('storage/'.session('filename')) !!}">
<h4>S3</h4>
<img src="{!! Storage::disk('s3')->url(session('filename')) !!}">
@endif
</div>
S3の以下のURLが生成されます。
https://s3-us-west-2.amazonaws.com/demo53/mario.jpg
us-west-2は、設定に使用した地域コードです。日本ならap-northeast-1となります。
