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`にアクセスすると、下記のようにフォームが表示されます。
ファイルを適当に選択してアップロードします。今回は画像ファイルを選択しました。
アップロードが完了して、下記のように表示されました。
ファイルがアップロードされたか確認します。
指定した通りstorage/app/upfiles
配下にアップロードされています。ファイル名がランダムな文字列になっていますね。
ファイルの名前を付けてアップロード
ファイルに名前をつけてアップロードする場合は、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_size
はupload_max_filesize
より大きな値を設定する必要があります。
post_max_size = 20M
upload_max_filesize = 20M
今回は上記のように設定してみました。
コメント