【Laravel】画像保存処理実行時のエラー対処

###Laravelで画像保存処理を実行中、遭遇したエラーと対処法をまとめました。

##開発環境
* PHP7.4
* Laravel6
* Bootstrap4.4
* Docker20.10.8

##前提
* 画像保存処理は実装済み
* テーブル作成・マイグレーション実行済み
* バリデーション実装済み
* フォーム作成済み
* プレビュー表示処理実装済み(JavaScript)
* `Intervention Image` インストール済み
* `public artisan storage:link` 実行済み

##❗注意
:::note warn
コマンドをコピペして実行する際、コマンドの最後に余分なスペースが入らないよう注意しましょう。
コマンドが強制実行される場合があります。実行の際は慎重に。
:::

##目次
>1. 画像が正常に保存されない。
2. GD Library extension not available with this PHP installation.解決

##1. 画像が正常に保存されない。
* フォームをクリックして拡張子`.JPEG`の画像ファイルを選択。
* プレビューも正常に表示
![スクリーンショット 2021-11-26 1.07.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/3b0064f3-50de-9d0f-2f7c-a8d5cdd1b193.png)

* 更新ボタンクリック後、プロフィール画面に遷移するはずが、バリデーションに引っかかり保存できない。

![スクリーンショット 2021-11-26 17.08.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/4ec5c355-6c12-72df-e647-94996450c48d.png)



バリデーションは以下の通りです。(画像アップロード処理の部分のみ抜粋)

```PHP:src/app/Request/UserRequest.php
    public function rules()
    {
        return [
            'avatar' => ['file', 'image'],
        ];
    }

    public function attributes()
    {
        return [
            'avatar' => 'プロフィール画像',
        ];
    }

```

Viewは以下のとおりです。(画像フォームのみ抜粋)

```PHP:src/resources/view/users/edit.blade.php
<form method="POST" class="p-3 mb-1" action="{{ route('users.update', ["name" => Auth::user()->name] )}}" >
    @method('PUT')
    @csrf

     -----省略-----

       <div class="avatar-form image-picker text-center">
          <input type="file" name="avatar" id="avatar" class="d-none @error('avatar') is-invalid @enderror" accept="images/png,image/jpeg" />
          <label for="avatar" class="d-inline-block">
               @if (!empty($user->avatar))
               <img src="/storage/avatars/{{$user->avatar}}" class="rounded-circle" style="object-fit: cover; width: 125px; height: 125px;">
               @else
              　　<img src="/images/default.svg" class="rounded-circle" style="object-fit: cover; width: 125px; height: 125px;">
               @endif
          　</label>
          　<div class="small">プロフィール画像をアップロードできます。</div>

          　@error('avatar')
          　<span class="invalid-feedback" role="alert">
              　<strong>{{ $message }}</strong>
          　</span>
          　@enderror

        </div>

```


色々調べてみた結果、formタグに以下一文が抜けていたせいで保存出来なかった事が判明

```PHP:
enctype="multipart/form-data"
```

`enctype="multipart/form-data"`については以下の方の記事をご参考いただくと、理解が深まります。

https://www.yoheim.net/blog.php?q=20171201


以下のように修正します。

```PHP:src/resources/view/users/edit.blade.php
<!-- enctype="multipart/form-data"追加 -->
<form method="POST" class="p-3 mb-1" action="{{ route('users.update', ["name" => Auth::user()->name] )}}" enctype="multipart/form-data">
```

* 再度フォームをクリックして拡張子`.JPEG`の画像ファイルを選択。
* プレビューも正常に表示
* 更新ボタンクリック後、プロフィール画面に遷移するはずが、今度は以下のエラーに遭遇。

:::note alert
GD Library extension not available with this PHP installation.
:::

##2. GD Library extension not available with this PHP installation.解決

調べてみたところ、インストール済みの`Intervention Image`を使用するためには、`GD Library`がインストールされていなければならないことが判明

`GD Library`のインストール手順は、`Dockerfile`にコードを追加して行う方法と、
ターミナルコマンドで実行する方法があるが、私はターミナルコマンドでインストールしたので、その方法を解説します。

:::note warn
appコンテナに入って実行してください
:::
　以下コマンドでappコンテナに入る。(環境によってはコマンドが異なります)

```:ターミナル
$ docker compose exec app bash
```
以下のコマンドを上から順に実行(PHP7.4の場合)

```:ターミナル
# apt-get update
# apt-get install -y zlib1g-dev libpng-dev libjpeg62-turbo-dev
# docker-php-ext-configure gd --with-jpeg
# docker-php-ext-install -j$(nproc) gd
```
インストールできたらコンテナの再起動をしてください。
以下のコマンドで実行

```:ターミナル
　$　docker restart コンテナ名
```

コンテナ再起動後、再び画像を保存してみる。
* 再度フォームをクリックして拡張子`.JPEG`の画像ファイルを選択。
* プレビューも正常に表示
* 更新ボタンクリック後、プロフィール画面に遷移し画像も正常に表示されました。

![スクリーンショット 2021-11-26 1.00.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/891391/e1fd5185-8bad-e22a-9eaf-f2c45e052205.png)

##参考

https://qiita.com/njn0te/items/1807c0ef2c0cbc94a305

https://qiita.com/Soh1121/items/17dcdc815a1d22f31788

https://tt-computing.com/docker-php-gd

https://qiita.com/___yusuke49/items/9f6f64c7f800b8e77e7d

https://www.memotansu.jp/docker/620/