laravelで画像をs3アップロード


s3の設定
　ユーザー追加
　グループ追加
　バケットポリシー追加
　AWSのキー取得
laravelに処理追加
　AWSのキーをララベル.envに設定
　※ここのキーがあってること、通るキーであることを初めに検証すると早い。
　※他の細かい処理を書こうとも、そもそもキーとかでこけてると動かない。
　

# インストール

たまにメモリエラー的なの出るときあるので、その時はメモリ使用量を増やす設定入れればよし。
v2とv3のライブラリがある。
v3の時にphp7.2以上使ってねってエラー出るかもしれないので、
その時はphpのバージョンあげる。

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

# 何が一番デバッグ早いの？

tinkerでやるか、あるいは毎度laravelでserveする。
ユーザー認証のかかってない部分にルーティング1個追加して動かしたりする。
デバッガーとか使うのがより良いんだろうけど、時間ねぇので一旦これで行く。

# S3のバケット作って初期設定する


バケットポリシーは真似しながら書く
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies.html
https://qiita.com/k-staging/items/f9d00fa0bca25db31888
https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-access-denied-listobjects-sync/

アクセスポイントにも注意
https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html#s3_region

# ルーティング


こんな感じの追加する。


```php:routes/api.php
...
Route::post('/photo', 'HogeController@uploadImage');
...
```


# コントローラに直書き

サービス分けたりとかやりたい人は後からしてください。

```php:HogeController.php

    // ----------------------------------------
    // S3 アップロード
    // ----------------------------------------

    /**
     * @param Request $request
     * @return JsonResponse
     */
    public function uploadImage(
        Request $request
    ): JsonResponse {

        $this->validate($request, ['upload_image' => 'required|image']);
        $image = $request->file('upload_image');
        $filename = ((string)(uniqid("img_"))) .".". $image->getClientOriginalExtension();

        $filePath = Storage::disk('s3')
                        ->putFileAs(
                            'uploads'
                            , $image
                            , $filename
                            , [
                                'visibility' => 'public',
                                'ContentType' => 'image/jpeg'
                            ]
                        );
        return response()->json($filePath);
    }
```


# 実行

関係ありそうな場所のキャッシュをクリアすること


```
ルータ周り
php artisan route:clear
設定周り
php artisan config:cache
```


```
php artisan serve
```

postmanとかでpostする。


bodyでform-dataを選んで
keyをupload_imageにしてfileで画像を選択。



```
http://localhost:8000/api/photo
```

でpostmanを実行。


<img width="886" alt="スクリーンショット 2019-08-27 10.39.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64334/22cdc1b8-760d-c7f2-a336-5619ac926b82.png">


# vue側も


panelIndexはここに書いてないけど、一応この部分は配列でクルクル回るようなコンポーネント。
1個のコンポーネントの時は削って問題なし。


```html:
<div class="large-12 medium-12 small-12 cell">
  <label>
    <input type="file" @change="onFileChange(panelIndex, $event)" />
  </label>
</div>
```

vueのdataにimgFileを定義。
ファイルアップロードされるとonFileChangeが走ってapiを叩きに行く。
laravelからurlが返却される。


```js:
...
     data() {
         return {
             imgFile: '',
         }
     },
...
 onFileChange(panelIndex, e){
   this.imgFile = e.target.files[0];
   
   this.submitFile(panelIndex);
 },
 submitFile(panelIndex) {
    let formData = new FormData();
    formData.append('upload_image', this.imgFile);

    axios.post( '/api/photo',
      formData,
      {
        headers: {
            'Content-Type': 'multipart/form-data'
        }
      })
      .then(response => response.data)
      .then(data => {
        this.$set(this.group.reply.panels[panelIndex], 'image_url', data.url)
      })
      .catch(function(){
        console.log('FAILURE!!');
      });
 },
```


# その他参考

tinkerまとめ
http://kz-engineer-scrap.hatenablog.com/entry/2017/03/04/162158


https://qiita.com/D3vel0pper/items/45b2ddbfc68ee9cd7a3c
https://www.ritolab.com/entry/8
https://qiita.com/Ping/items/10ada8d069e13d729701

vueからaxiosで呼ぶ処理も書く時はここが良い。

https://serversideup.net/uploading-files-vuejs-axios/