Laravelでファイルアップロードする方法!

Laravel Laravel

Laravelでファイルをアップロードすることも増えてきました。
ファイルアップロードについてのサンプルコードや注意点などをまとめておきます。

サンプルの動作検証にはLaravelのバージョン8を使用しています。

Laravelでファイルをアップロードするには?

PHPでファイルアップロードするときのように、フォームを用意してからコントローラーにファイルを送信します。
コントローラー側では、フォームのinputタグにつけたname属性の値でファイルを取得することができます。

この内容が/vendor/laravel/framework/src/Illuminate/Http/UploadedFile.phpクラスのインスタンスになっています。
受け取ったインスタンスを使用して、storeメソッドやstoreAsメソッドを呼ぶとファイルがアップロードされます。

ファイルのアップロード場所について

アップロードしたファイルのデフォルトの配置位置は、storage/app配下になります。
コントローラーで指定されたディレクトリ名のディレクトリが作成され、アップロードされます。

Laravelでファイルアップロードをするサンプルコード

単純にファイルをアップロードするときのサンプルコードを載せています。
BladeファイルからフォームをPOST形式で送信して、コントローラーでファイルをアップロードする処理を行います。

ルーティングファイル(routes/web.php)

下記のルートを用意しました。

Route::get('/test/file_upload', [FileUploadController::class, "index"])->name('file_upload.index');
Route::post('/test/file_upload/action', [FileUploadController::class, "action"])->name('file_upload.action');

/test/file_uploadにアクセスすると、アップロードフォームのbladeが表示されます。
/test/file_upload/actionが実際にアップロード処理をするためのルートになります。

Bladeファイル

file_upload.blade.phpという名前で、下記のファイルを作成しました。

<!DOCTYPE html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
  </head>
  <body>
    @if ($errors->any())
    <div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative ml-5 mr-5 mt-3" role="alert">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
    @endif
    <form method="post" action="{{ route('file_upload.action') }}" enctype="multipart/form-data">
        @csrf
        <div class="m-5">
            <div>
                <input type="file" name="upload_file" class="mb-5" />
            </div>
            <button type="submit" class="bg-blue-500 hover:bg-blue-400 text-white font-bold py-2 px-4 border-b-4 border-blue-700 hover:border-blue-500 rounded">送信</button>
        </div>
    </form>
  </body>
</html>

単純にinputタグで、type="file"としてファイルを指定するためのタグを用意しています。
その下にファイルを送信するためのボタンを設置しました。

フォームのmethodにPOSTを指定して、actionにはroutes/web.phpで作成したファイルアップロードのルーティングを指定しています。
ファイルアップロードのときに気を付けておくべきなのが、enctype="multipart/form-data"をフォームタグに付ける必要があります。

このenctype属性が指定されていない場合は、コントローラーからupload_fileにアクセスすると、ファイル名のみしかない状態になります。

Controllerファイル

ファイルアップロードをテストするためのコントローラーを下記のように作成しました。

<?php

namespace App\Http\Controllers;

use Carbon\Carbon;
use Illuminate\Http\Request;

class FileUploadController extends Controller
{
    public function index() {
        return view('file_upload');
    }

    public function action(Request $request) {
        $request->validate([
            'upload_file' => 'required'
        ]);

                // storage/app/upfiles配下にアップロード
        $request->upload_file->store('upfiles');

        echo "upload success";
        exit;
    }
}

indexメソッドにアクセスされると、先ほど作成したフォームが表示されます。
フォームの送信ボタンを押すと、actionメソッドにフォームに設定したファイルが送信されます。

inputタグのname属性がupload_fileなので、下記のようにして送信ファイルにアクセスして、アップロードします。

$request->upload_file->store('upfiles');

storeメソッドの引数はディレクトリ名になります。
このようにアップロードすると、storage/app/upfilesにファイルがアップロードされます。
storeメソッドを使用した場合は、ファイル名はランダムで作成されます。

アップロードができたら”upload success”の文字列を画面に表示して、処理を終了しています。
実際に動作確認をしてみます。

動作確認する

`http://127.0.0.1:8000/test/file_upload`にアクセスすると、下記のようにフォームが表示されます。
Laravelでファイルアップロード

ファイルを適当に選択してアップロードします。今回は画像ファイルを選択しました。
Laravelでファイルアップロードのため画像選択

アップロードが完了して、下記のように表示されました。
Laravelでファイルアップロード完了

ファイルがアップロードされたか確認します。
指定した通りstorage/app/upfiles配下にアップロードされています。ファイル名がランダムな文字列になっていますね。
Laravelでアップロードされたファイル確認

ファイルの名前を付けてアップロード

ファイルに名前をつけてアップロードする場合は、storeAsメソッドを使用します。

$request->upload_file->storeAs('upfiles', 'myfileNewName.' . $request->upload_file->extension());

upload_fileの箇所はinputタグで指定されたname属性の値になります。
storeAsメソッドの第1引数にディレクトリ名、第2引数にファイル名を指定します。

上記の例では、ファイル名を”myfileNewName”という名前にしました。
さらにアップロードされたファイルの拡張子をそのままつけています。

ファイルの名前を付けずにアップロード

ファイルに名前をつけずにアップロードする場合は、サンプルと同じですが下記のようにします。

$request->upload_file->store('upfiles');

内部的には、storeAsメソッドが使われていて、名前の箇所はランダム文字列が指定されるようになっています。

public function store($path, $options = [])
{
    return $this->storeAs($path, $this->hashName(), $this->parseOptions($options));
}

ファイルの拡張子が知りたい

先ほど出てきましたが、ファイルの拡張子が知りたい場合は、extensionメソッドで取得できます。

$request->upload_file->extension();

「.」ドットを含まない形で、拡張子が取得できます。

アップロード時のファイル名が知りたい

アップロード時のファイル名をそのまま使ったり、取得したい場合はgetClientOriginalNameメソッドを使用します。

$request->upload_file->getClientOriginalName();

アップロードするファイルのバリデーション

アップロードするときにファイルにバリデーションをするかと思います。
実際に使いそうなバリデーションルールをまとめておきます。

必須のバリデーション

必須バリデーションは他の項目と同じようにrequiredでバリデーション可能です。

$request->validate([
    'upload_file' => 'required'
]);

ファイルサイズの上限のバリデーション

ファイルサイズの上限をバリデーションする場合は、maxを使用します。
maxはキロバイト指定になるので、max:1024と指定すると、1メガバイト以上だとエラーが出るようになります。

$request->validate([
    'upload_file' => 'required|max:1024'
]);

画像ファイルの場合だと大きいものは8Mとかになるので、10M(10240)とかを指定しておけば良さそうです。
アップロードするファイルの内容によって、指定しておきましょう。

拡張子のバリデーション

特定の拡張子以外をバリデーションで弾く時には、mimesを使用します。
アップロードできるファイルの拡張子を「,」で区切って記載します。

$request->validate([
    'upload_file' => 'required|max:1024|mimes:jpg,jpeg,png,gif'
]);

画像ファイルの場合は、上記のような感じになるかと思います。

ファイルが大きすぎてアップロードエラーになる

ファイルサイズが大きい場合は、下記のようなエラーが発生することがあります。
Illuminate\Http\Exceptions\PostTooLargeException

この例外は、php.iniのpost_max_sizeの設定値を見て、アップロードされたファイルより小さい場合は発生させるようになっています。
post_max_sizeはPOSTできる最大サイズとなっています。

そもそも、phpの設定でファイルサイズが制限されているので、設定を変える必要があります。

post_max_sizeはデフォルト値が”8M”になっているので、必要に応じた値に変えておきましょう。
同じように、upload_max_filesizeというアップロードされるファイルの最大サイズを定義している項目があるので、こちらも必要に応じた値に変えておきます。

post_max_sizeupload_max_filesizeより大きな値を設定する必要があります。

post_max_size = 20M
upload_max_filesize = 20M

今回は上記のように設定してみました。

php.iniのデフォルト設定値については、公式の下記に書いていました。
PHP: コア php.ini ディレクティブに関する説明 - Manual

コメント

タイトルとURLをコピーしました