Laravel + AWS S3で画像アップロードを行う

# はじめに
現在作成中のアプリケーションにて、画像をアップロードできるようにしようと思います。
そこで今回、Laravel + AWS S3で画像アップロードの処理を実装したので簡単にご紹介します。

# 流れ
やることは大きく分けると２つ（AWS側の設定とLaravel側での設定+実装）

***1.AWS側の設定***

- S3でバケットを作成
- S3の権限を持ったIAMユーザーの作成

***2.Laravel側の設定+実装***

- AWSの認証情報を.envに記載
- S3のパッケージをインストール
- 処理の実装（すでに画像URL保存用のカラム追加済み）

# S3とは？
初めてS3を触る人からしたら、S3ってなんぞやと思いますので軽くまとめます。

> Amazon Simple Storage Service はインターネット用のストレージサービスです。また、ウェブスケールのコンピューティングを開発者が簡単に利用できるよう設計されています。
Amazon S3 のウェブサービスインターフェイスはシンプルで、いつでも、ウェブのどこからでも容量に関係なくデータを格納および取得できます。これにより、すべての開発者が、スケーラブルで信頼性が高く、かつ高速で安価なデータストレージインフラストラクチャを利用できるようになります。
参考：[Amazon S3 とは（公式ドキュメントより）](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/Welcome.html)


安価で高い耐久性の高いAWSクラウドストレージサービス。
値段は、0.023USD/GB 月1GB使用した場合約3円
そして、高い耐久性、容量無制限、バケットやオブジェクトに対してアクセス制限を設定できる。

### S3を使うに当たって理解しておくべき重要概念
***バケット***
オブジェクトの保存場所。名前はグローバルでユニークである必要がある。

***オブジェクト***
データ本体。S3に格納されるデータで、URLが付与される。

***キー***
オブジェクトの格納URLパス


参考：[AWS：ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得](https://www.udemy.com/course/aws-and-infra/)

# AWS側の設定
こちらの手順通りにやりました。とても参考になりました。
参考：[Rails, Laravel(画像アップロード)向けAWS(IAM:ユーザ, S3:バケット)の設定](https://qiita.com/nobu0717/items/4425c02157bc5e88d7b6)

# Laravel側の設定と実装
まずは、AWSの認証情報を.envに記載する

```.env
AWS_ACCESS_KEY_ID= AWS設定で保存したcsvの認証情報に記載されているAccess key ID
AWS_SECRET_ACCESS_KEY= csvの認証情報に記載されているSecret access key
AWS_DEFAULT_REGION=ap-northeast-1 （アジアパシフィック東京で作成したため）
AWS_BUCKET= 作成したバケット名
```

次に、S3のパッケージである`league/flysystem-aws-s3-v3`をインストールする。

```
composer require league/flysystem-aws-s3-v3
```

パッケージインストール時に、このようなエラーがでました。

```
Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes) in phar://C:/ProgramData/ComposerSetup/bin/composer.phar/src/Compose
r/DependencyResolver/RuleSetGenerator.php on line 129
```

こちらの記事にて解決方法をご紹介しているのでよろしければご確認ください。
[composer require時に起きたメモリー制限エラーとその解決策](https://qiita.com/sasao3/items/739c2826e72701190dbe)

あとは処理を実装するのみ！今回は必要最低限の処理だけ記載します。
## 実装

```php
$avatar = $request->file('avatar');

//imagesというファイルに、第二引数に指定した画像を保存する
$path = Storage::disk('s3')->putFile('images', $avatar, 'public');

//アップロードした画像のフルパスを取得
$avatarPath = Storage::disk('s3')->url($path);
```
`putFile(アップロード先のディレクトリ, 保存したい画像, オプション）`
第一引数にはアップロード先のディレクトリ　ここではimages配下に保存される
第二引数にはアップロードしたい画像を指定　ここではフォームから受け取った画像
第三引数にはオプションを指定。publicと指定することで外部からアクセスできるようになる。

指定したファイルのURLを取得するには、urlメソッドを使用する。
あとはこのURLをデータベースに保存すればいつでも使用できる。

参考
・[LaravelでAWS S3へ画像をアップロードする](https://qiita.com/nobu0717/items/51dfcecda90d3c5958b8)
・[Laravel 7.x ファイルストレージ（公式ドキュメント）](https://readouble.com/laravel/7.x/ja/filesystem.html)

View側ではファイルを送信できるようフォームを用意してあげればよい。

```
<form action="#" method="post" enctype="multipart/form-data">
    <input type="file" name="avatar">
</form>
```

このとき注意点（自分が知らなかった点）としては、ファイルを送信する際は
`enctype="multipart/form-data"`を忘れないこと！
※これがないと、受け取る値がnullになる

multipart/form-dataとは、複数の種類のデータを一度に扱える形式で、ファイルアップロードでよく使われる。
というのも、フロントエンドとバックエンドでのデータやりとりでは様々な種類のデータを扱う。その際、***どんな種類のデータを扱っているのかを指定する必要がある***。

参考：[[フロントエンド] multipart/form-dataを理解してみよう](https://www.yoheim.net/blog.php?q=20171201)

# まとめ
今回は、画像アップロード機能の実装に当たりAWS S3を使用しました。
アカウント作成したりと前準備は多少手間がかかりますが、実装自体は非常に簡単でした。

S3は非常に安価なため、値段も気にせず使用できる点もありがたい。

以上！