Laravel 6.x 【画像アップロード】 ディレクトリの作成、ファイルの保存、データベースへの登録、表示


制作環境

Windows 10
Laravel : 6.18.35
Laravel/ui : 1.0
Laravel-mix : 5.0.1
Bootstrap : 4.0.0
MDBootstrap : 4.19.1
chart.js : 2.9.3
XAMPP
PHP : 7.4.3
Visual Studio Code

はじめに

この記事はプログラミングをはじめたばかりの素人が、できたことをメモするのに利用しています。
内容には誤りがあるかもしれません。

参考にしたサイト

https://qiita.com/10mi8o/items/ce9c875e736c7b1d2498
https://qiita.com/koru1893/items/1d2f522e20744b03e3ad
https://laraweb.net/tutorial/2707/
https://php-junkie.net/framework/laravel/upload_image/

リファレンス
https://readouble.com/laravel/6.x/ja/helpers.html?header=redirect()

関連記事

続編です。
Laravel 6.x 【画像アップロード】 ファイルの削除、データベースへのレコード削除
Laravel 6.x 【画像アップロード】 トランザクションを使用する

この記事の目的

Laravelでの画像アップロードを、シンプルに理解できるよう画像アップロードに特化して掲載するのが目的です。
その為、バリデーション等は(素人の自分的に)わかりづらくなるのであえて割愛してます。
またデザインなども一切気にしてません。
あくまで、画像アップロードのやり方だけを見るのに特化させてます。

事前にLaravelをインストールしてからはじめてください。

完成イメージ

アップロードフォーム

シンプルにファイル選択画面のみ。

登録完了後

完了メッセージと、登録した画像を表示。

要件

・画像を選択し、アップロードできる。
・プロジェクトのstorage>app>public>imagesにファイルを保存する。
・保存する際に、ファイル名は元のファイル名と別の名称にする。
・データベースにファイルの名前を登録する。

それでは、はじめていきます。

モデルとマイグレーションファイルの作成

プロジェクトのディレクトリでターミナルを起動し、以下を実行してください。

php artisan make:model Models/FileImage -m

これで、モデルとマイグレーションファイルが作成されます。
※モデルはModelsの中に作成するようにしています。

マイグレーションファイルの編集

database>migrations 内のxxxx_xx_xx_xxxxx_create_file_images_table.phpを開き、以下のように編集します。

create_file_images_table.php
    public function up()
    {
        // テーブルがなければ新規作成する
        if (!Schema::hasTable('file_images')) {
            Schema::create('file_images', function (Blueprint $table) {
                $table->bigIncrements('id');
                $table->string('file_name')->comment('ファイル名');
                $table->timestamps();
            });
        }
    }

->comment('ファイル名')は、なくてもかまいません。

モデルの編集

app>Models 内のFileImage.phpを開き、以下を記述します。

FileImage.php
class FileImage extends Model
{
    protected $fillable = ['file_name'];
}

コントローラの作成

ターミナルで以下を実行。

php artisan make:controller FileUpController

コントローラの編集

app>Http>Controllers 内のFileUpController.phpを開き、以下のように記述します。

FileUpController.php
<?php
// モデル使用の為に追記
use App\Models\FileImage;

class FileUpController extends Controller
{
    public function index()
    {
        // データベースからfile_imagesテーブルにある全データを抽出
        $data = FileImage::all();
        // ビューfile.blade.phpに$dataを渡して表示させる
        return view('file', compact('data'));
    }

    // 登録処理
    public function store(Request $request)
    {
        // $request->imgはformのinputのname='img'の値です
        // ->storeメソッドは別途説明記載します
        $path = $request->img->store('public/images');
        // パスから、最後の「ファイル名.拡張子」の部分だけ取得します 例)sample.jpg
        $filename = basename($path);
        // FileImageをインスタンス化(実体化)します
        $data = new FileImage;
        // 登録する項目に必要な値を代入します
        $data->file_name = $filename;
        // データベースに保存します
        $data->save();

        // 登録後/fileにリダイレクトします その際にフラッシュメッセージを渡します
        return redirect('/file')->with('success', '登録完了しました。');
    }
}

storeメソッドについて

下記storeメソッドだけで、

$path = $request->img->store('public/images');

以下の内容を実行してくれます。

・保存ディレクトリの作成 (今回はstorage>app>public 内にimagesディレクトリを作成してくれます)
・ファイルの保存
・保存の際に自動的に元のファイル名を変更します 例:mMwTQg1AGSNdhPaL5GofWxGF3DYkvgphEnzGEIxF.png
・ルートディレクトリからの相対位置を返します

リファレンス
https://readouble.com/laravel/6.x/ja/requests.html?header=%25E3%2582%25A2%25E3%2583%2583%25E3%2583%2597%25E3%2583%25AD%25E3%2583%25BC%25E3%2583%2589%25E3%2583%2595%25E3%2582%25A1%25E3%2582%25A4%25E3%2583%25AB%25E3%2581%25AE%25E4%25BF%259D%25E5%25AD%2598

ビューの作成

resources>views 内にfile.blade.phpを作成し、以下のように記述します。

file.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>ファイルアップロード</title>
</head>
<body>
  <h1>ファイルアップロード</h1>
  @if (session('success'))
      <p>{{ session('success') }}</p>
  @endif

  <form action="/file" method="post" enctype="multipart/form-data">
  @csrf
  <label>画像選択<input type="file" name="img" accept=".png,.jpg,.jpeg,image/png,image/jpg"></label>
  <br>
  <input type="submit" value="送信">
  </form>

@foreach ($data as $item)
  <img src="{{ asset('storage/images/' . $item->file_name) }}">
@endforeach

</body>
</html>

ルーティングの作成

routes 内のweb.phpを開き、以下のように記述します。

web.php
Route::get('/file', 'FileUpController@index');
Route::post('/file', 'FileUpController@store');

シンボリックリンクの作成

ターミナルで以下を実行。
これをやらないと画像を表示できません。

php artisan storage:link

Laravelの仕様で、ファイルはstrage>app>public>imagesに保存されますが、読み込み時はpublic>storage>imagesからファイルが読み込まれます。
その為、リンクを貼って保存先にアクセスできるようにしてます。

動作確認

/fileにアクセスして下さい。
以下が表示されればOKです。

次に適当な画像ファイルを選択し、送信をクリックしてください。
送信後、以下のように選択した画像が表示されればOKです。

※ちなみにバリデーションも何もやってないので、ファイルを選択しない状態で送信するとエラーが発生します。

ファイルの確認

以下の場所にimagesディレクトリと、画像ファイルが保存されていることを確認してください。
ファイル名は自動的に付くので、変な名前になってます。セキュリティー対策ですね。

同じく、以下の場所にimagesディレクトリと、画像ファイルがリンクされていることを確認してください。

確認ができればOKです。

データベースの確認

tinkerを使い、データベースにファイル名が保存されているか確認します。

ターミナルで以下を実行します。

php artisan tinker

次に以下を実行。

use App\Models\FileImage;

次に以下を実行。

FileImage::all();

以下のように表示され、storageに保存されているファイル名と、登録されたfile_nameが合っていたらOKです。

最後にexitかCtrl+cでtinkerを終了します。

exit or Ctrl+c

以上で終了です。