Laravelで画像をアップロードする方法

## Laravelで画像をアップロードするフォームを作成する

## 著者の環境
著者は事前にCRUD用のコントローラを作成しており、ルーティングが次の状態にしてます
ルーティングの内容が異なる場合は`ご自身の環境に合うようURIを変える必要があります`
[CRUD用コントローラの役割](https://qiita.com/Laravel-student/items/242ea2d8b35f44b52d49)

```php
Route::resource('/', '******Controller');
```
`php artisan route:list`

```
+--------+-----------+----------+---------+--------------------------------------------------+--------------+
| Domain | Method    | URI      | Name    | Action                                           | Middleware   |
+--------+-----------+----------+---------+--------------------------------------------------+--------------+
|        | GET|HEAD  | /        | index   | App\Http\Controllers\******Controller@index   | web          |
|        | POST      | /        | store   | App\Http\Controllers\******Controller@store   | web          |
|        | GET|HEAD  | api/user |         | Closure                                          | api,auth:api |
|        | GET|HEAD  | create   | create  | App\Http\Controllers\******Controller@create  | web          |
|        | GET|HEAD  | {}       | show    | App\Http\Controllers\******Controller@show    | web          |
|        | PUT|PATCH | {}       | update  | App\Http\Controllers\******Controller@update  | web          |
|        | DELETE    | {}       | destroy | App\Http\Controllers\******Controller@destroy | web          |
|        | GET|HEAD  | {}/edit  | edit    | App\Http\Controllers\******Controller@edit    | web          |
+--------+-----------+----------+---------+--------------------------------------------------+--------------+
```






## ビューにファイルをアップロードするフォームを作成する

- ビューにフォームを用意しコントローラーへ画像を送ります


```php
<form method="POST" action="/" enctype="multipart/form-data">
  @csrf
  <input type="file" name="image">
  <button>アップロード</button>
</form>
```
---
### 用語説明

**method="POST"**
- ブラウザの&lt;form>に入力された情報を特定のURI(コントローラーのアクション）へ送ります

**action="/"**
- &lt;form>を送信する先を`"/"`へ指定しています。
- `methodをPOST`にすることで移動先はindexアクションではなく`storeアクション`になります

**enctype="multipart/form-data"**
- フォームで画像をアップロードする際に必須レベルで記述しなければならない項目
- HTMLフォームのHTTP通信で複数の種類のデータを一度に扱える形式
- 記述がない場合サーバーサイド側が適切にデータを受け取れない可能性がある

**@csrf**
- [CSRF(クロスサイトリクエストフォージェリ)]((https://qiita.com/Laravel-student/items/e6ca6658ffcf08e6d912)) による脆弱性を防止するための記述です
- Laravelでフォームを利用する際には必ず記述しなければならないコードになります
- Laravelでは&lt;form>の内部に`@csrf`を記述しなければ`脆弱性対策`でエラーを起こします
- `@csrf`とは同じ意味の`{{csrf_field()}}`を記述しても&lt;form>は動きます

**type="file"**
- ブラウザに表示されるボタンを押すことで`ファイルを選択`することができるようになります

**name="任意の名前"**
- フォームで送るデータに名前を付けます
- コントローラーに渡されたデータは`任意の名前を引数`にすることで参照することができます
- 渡されるデータはファイル名,画像データ,作成日時など様々な項目がセットになっています
- コントローラーで利用する際にはfile関数やstoreAsメソッドの引数に使います

**&lt;button>**
- ボタンを押すことでフォームのデータを送信することができます



## コントローラーで画像を保存する（ファイル名ランダム）

- `画像データはLaravelのプロジェクトフォルダへ保存`されます
- `データベースへファイル名や保存先のパスなどを保存`すればビューへ画像を呼び出すことができます
- CRUD用のコントローラーを用いているため`storeアクション`にコードを記述しています

```php
public function store(Request $request)
    {
        // ディレクトリ名を任意の名前で設定します
        $dir = 'img';

        // imgディレクトリを作成し画像を保存
        // storage/app/public/任意のディレクトリ名/
        $request->file('inputタグに付けられたname属性の値')->store('public/' . $dir);
        
        // ページを更新します
        return redirect('/');
    }
```

- storeメソッドの引数には保存先のディレクトリ名を指定することができます。
- ファイルはランダムな一意の値（アルファベット＋数字）にリネームされて保存されます

## 画像を保存する（ファイル名を変更せずに保存する）

- storeAsメソッドを使用することでファイル名を指定して保存することができます

```php
 public function upload(Request $request)
    {
        // ディレクトリ名
        $dir = 'img';

        // アップロードされたファイル名を取得
        $file_name = $request->file('inputタグに付けられたname属性の値')->getClientOriginalName();

        // 取得したファイル名で保存
        // storage/app/public/任意のディレクトリ名/
        $request->file('inputタグに付けられたname属性の値')->storeAs('public/' . $dir, $file_name);

        return redirect('/');
    }
```

- phpの変数はドット`.`で連続した表示をすることができます
- `$maxUserId = Products::max('id')+1;`では次のレコードのIDを変数に代入することができます

## 画像の保存先パスをデータベースに保存する

- 事前にデータベースのテーブルを操作するためのモデルを作成する必要があります
- 作成したモデルを任意の変数に入れることでデータベースを操作する`インスタンス`を作成します
- 作成された変数（インスタンス）に挿入先の列を指定することで`値を代入`することができます

```php
$image = new　User();
// $任意の変数名　=　テーブルを操作するモデル名();
// storage/app/public/任意のディレクトリ名/
        $image->file_name = $file_name;
        $image->file_path = 'storage/app/public/' . $dir . '/' . $file_name;
        $image->save();
   
   //ページを更新する 
   return redirect('/');
 
```

```php
$image->実際に存在するテーブルの列名 = $file_name;
$image->実際に存在するテーブルの列名 = 'storage/app/public/' . $dir . '/' . $file_name;
```

- `$変数名->save`でデータベースに1レコードが登録されます
- saveを動かす場合、1レコードに存在する列（カラム）は一度に全て値を埋める必要があります
- saveを動かす場合、レコードの値に1つでも空欄がある場合、エラーになります
- file_nameやfile_pathの列以外にも列が存在する場合は、それら全て値で埋める必要があります
- 自動で入力されるIDや更新日時（created_at）などは埋める必要はありません

## ビュー表示への下準備（シンボリックリンク設定）

- Laravelでは画像の参照先は`storage/app/public/`です
- ただし、そのままではビューで参照することができません
- `storageディレクトリ`を参照するためにはシンボリックリンクが必要です

## Laravelではシンボリックリンクが必須

- windowsで言うところ`ショートカット`の意味
- Laravelはデフォルトでstrageはweb側から参照できない仕様です
- Laravelでstrageを参照する場合はシンボリックリンクを貼りましょう


## シンボリックリンクを作成するコマンド
- storageへのシンボリックリンクが作成されます
- ブラウザから参照可能になります

```
php artisan storage:link
```

## ビューに画像を表示させるコード

- braidファイルへ次のコードを記述することで画像を参照できます
- コントローラーからモデルが代入された変数を渡しておく必要があります


```php3

@foreach($users as $user)

<img src="{{ asset($user->img_path) }}" >

@endforeach

```
```php3

@foreach($コントローラから渡した変数名 as $任意の変数名)

<img src="{{ asset($任意の変数名->パスが格納された列名) }}" >

@endforeach

```
### asset関数とは？

- publicディレクトリのパスを返す関数です
- 使用することでpublicまでのパスを省略することができます

#### 実際のテーブルに入力をしておくべきパス
- `storage/ファイル名.jpg`
- `storage/任意のフォルダ名/ファイル名.jpg`
- asset関数の引数に入力することで画像ファイルを参照します