Laravelで画像をアップロードし、パスをDBに保存する方法

#はじめに
Laravelで画像をアップロードし、DBに保存する方法について解説していきます。

まず、今回は画像はプロジェクト内のディレクトリに保存をし、画像のパスをデータベース（以下DB）に保存していきます。
データベースに画像を保存することもできますが、その場合はサイズが大きくなってしまい処理に時間がかかってしまいます。
そのため、画像のパスのみをDBに保存するのが主流のようです。

また、今回はLaravelのプロジェクトは作成し、DBへ接続済であることを前提に進めていくのでご了承ください。

-各バージョン
-laravel 6.x
-PHP 7.4.9
-mySQL 5.7.30

##モデルとテーブルを作成する
今回は読書の記録をするアプリを推定して作っていきます。データはシンプルに画像、本の題名、著者名にしたいと思います。

早速、モデルとテーブルをコマンドで作成します。

```
php artisan make:model Book -m
```

上記のコマンドを実行すると、Bookモデルとbooksテーブルが作成されます。

続いて、booksテーブルにDBに保存する項目を入力していきます。

```php:books_table_php
public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title', 100);
            $table->string('author', 100);
            $table->string('image');
            $table->timestamps();
        });
    }
```
そのままマイグレーションします。

```
php artisan migrate
```
問題なくマイグレーションできれば、DBにbooksというテーブルが作成されているはずです。

##ビューを作成する
続いて、入力フォームを作っていきます。

```php:upload.blade.php
<form method="post" action="{{ route('upload_image') }}" enctype="multipart/form-data">
   @csrf
   <input type="file" name="image">
   <label for="title">題名</label>     
   <input id="title" type="text" name="title">
   <label for="author">作者</label>     
   <input id="author" type="text" name="author">
   <input type="submit" value="登録">
</form>
```
まず、画像ファイルをアップデートするには必ず`form`に`enctype="multipart/form-data`が必要になります。
また、`@csrf`はCSRFトークンというもので、外部からの悪意のある攻撃から守るための記述であり、Laravelのフォームには記述が必須となっています。

`input`内を見ていきます。
画像をアップロードする場合はtype属性を`file`に指定します。そしてname属性には先ほどbooks_table_phpで指定したカラム名を指定します。
##コントローラーを作成する
まずはコマンドでコントローラーを作成します。

```
php artisan make:controller BookController
```
BookControllerが作成されたら、利用するモデル名と、使用するヘルパ関数名を冒頭に記述します。もちろん、あとからその都度記述することも可能です。

```php:BookController.php
use App\Book;
use Illuminate\Support\Str;
```
そして、画像を保存するための処理を書いていきます。

```php:php:BookController.php
public function store(Stock $request)
  {
      $book = new Book();

      $book->title = $request->input('title');
      $book->author = $request->input('author');

       // 保存されているデータを$formに格納する
       $form = $request->all();
       //　もし$formにimageデータがあったら
       if (isset($form['image'])) {
         // $fileにイメージデータを格納する
         $file = $request->file('image');
         // getClientOrientalExtension()でファイルの拡張子を取得する
         $extension = $file->getClientOriginalExtension();
         $file_token = Str::random(32);
         $filename = $file_token . '.' . $extension;
         // 表示を行うときに画像名が必要になるため、ファイル名を再設定
         $form['image'] = $filename;
         $file->move('uploads/books', $filename);
        }
        $book->save();

        return redirect('home');
  }
```
コードにコメントを書いていないところを解説していきます。

まず、`getClientOriginalExtension()`でファイルの拡張子を取得した後に、`Str::random()`でランダムな文字列を取得します。`Str::random()`は(　)内に指定された文字数分、ランダムな文字列を作成することができる関数です。今回は32文字を指定しました。
こうして`$filename`には画像のパスが「ランダムな32文字 . 拡張子」の状態で保存されていることになります。

続いてこちらを、`move()`で任意のファイルに保存するように設定します。`move('指定したファイル', 保存するファイル名)`の順番で記述をすると、Publicフォルダ内に指定したファイルが自動生成され、アップロードした画像が保存されるようになります。

最後に `save()`メソッドでデータを保存し、今回は`redirect()`でhomeに戻るように指定しています。

##ルーティングを設定する
upload.blade.php内で`form`の`action`を`route('upload_image')`と指定したので、今回は`upload_image`を`name()`で指定し、アクセスをしたら、BookControllerのStoreアクションにつながるように記述します。

```php:web.php
Route::post('/upload', 'BookController@store')->name('upload_image');
```

これで完成です！
#さいごに
今回はLaravelで画像をアップロードし、DBに保存する方法について解説しました。
次回以降、保存したデータを表示する方法や編集方法に関しても解説していけたらと思います！
##参考
https://youtu.be/il9gsKH9V-8