制作環境
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
はじめに
この記事はプログラミングをはじめたばかりの素人が、できたことをメモするのに利用しています。
内容には誤りがあるかもしれません。
検証することにした経緯
とあるサイトで以下のような記述がありました(一部抜粋)。
public function upload(Request $request)
{
$this->validate($request, [
'file' => [
// 必須
'required',
// アップロードされたファイルであること
'file',
// 画像ファイルであること
'image',
// MIMEタイプを指定
'mimes:jpeg,png',
]
]);
if ($request->file('file')->isValid([])) {
$path = $request->file->store('public');
$file_name = basename($path);
$user_id = Auth::id();
$new_image_data = new Image();
$new_image_data->user_id = $user_id;
$new_image_data->file_name = $file_name;
$new_image_data->save();
return redirect('/output');
} else {
画像のアップロードについて検索している時に見つけたのですが、バリデーションルールのfileとisValidが同じ事をしているように思え、片方は記述が不要なのではないかと思い、検証してみることにしてみました。
リファレンスの説明
バリデーションルールのfileについて
isValidメソッドについて
検証前の自分の見解
バリデーションでフィールドがアップロードに成功したことの確認が取れたということは、(アップロードされているから)ファイルが存在している。
アップロードに成功しているので、問題なくアップロードができている。
故に、両方とも同じ内容で片方は不要なのではないか?
そもそもの誤解
検証中に気づいたのですが、リファレンスの内容の解釈に誤解がありました。
isValidについて、リファレンスでは「ファイルが存在しているかに付け加え、isValidメソッドで問題なくアップロードできたのかを確認できます。」と記載があった為、てっきり「ファイルの存在確認+問題なくアップロードできたか確認」の両方をやっていると思ったのですが、実際はファイルの存在確認の記述にプラス(付け加えて)でisValidを記述すれば、問題なくアップロードできたかの確認もできるという内容でした。
検証にあたり
ビューはアップロードのフォームとエラー・成功時のメッセージがでるだけの簡単なものを作成し、コントローラーの記述を変更することで検証していきました。
検証に直接関係ないのでビューは記載しません。
画像のアップロードを想定しています。
ビューのイメージ
検証
検証① バリデーションfileのみ記載 画像に対する処理なし
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\FileImage;
class FileUpController extends Controller
{
public function index()
{
$data = FileImage::all();
return view('file', compact('data'));
}
public function store(Request $request)
{
$this->validate($request, [
'img' => 'file',
]);
return redirect('/file')->with('success', '登録完了しました。');
}
}
結果:エラーなし。「登録完了しました。」が表示される。
★注意点★
fileのみの記載だと、バリデーションは全く機能しません。
ファイルを選択し、送信をクリックした場合も結果は同じでした。
fileはあくまでも、アップロードに成功したかどうかだけを検証しているようで、アップロードの操作が内部で行われていなけば、全く機能しません。
ファイル選択なし⇒ファイルがないので、アップロードの操作なし⇒file機能せず⇒バリデーション通過
ファイル選択あり⇒ファイルがあるので、アップロードの操作あり⇒fileバリデーション実行⇒バリデーション通過
つまり、必ずファイル自体の存在確認(require等)が必須です。
検証② バリデーションfileのみ記載 画像に対する処理あり
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
$this->validate($request, [
'img' => 'file',
]);
$path = $request->img->store('public/images');
$filename = basename($path);
$data = new FileImage;
$data->file_name = $filename;
$data->save();
return redirect('/file')->with('success', '登録完了しました。');
}
結果:エラー発生「Call to a member function store() on null」。
ファイルの存在確認をしていない為、ファイルが無い(空:null)時の処理でエラーが発生する。
※そもそもこういう処理の書き方はしないと思いますが、細かな動作を確認したい為、わざとやってます。
検証①の結果の通り、fileのみの記載はほぼザルなので、やはり必ずファイル自体の存在確認が必須です。
検証③ isValidメソッドのみ記載 画像に対する処理なし
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
if ($request->file('img')->isValid())
return redirect('/file')->with('success', '登録完了しました。');
}
return redirect('/file')->with('success', '失敗しました。');
}
結果:エラー発生「Call to a member function isValid() on null」。
メソッド自体が機能せずエラーが発生。
やはり、必ずファイル自体の存在確認が必須です。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
検証④ isValidメソッドのみ記載 画像に対する処理あり
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
結果:エラー発生「Call to a member function isValid() on null」。
そもそもファイルが無いと、検証③で試した通りisValidがエラーになるので、検証するまでもない。
なので、コントローラの記述は掲載しません。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
検証⑤ バリデーションfileとisValidメソッド両方記載 画像に対する処理なし
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
$this->validate($request, [
'img' => 'file',
]);
if ($request->file('img')->isValid()) {
return redirect('/file')->with('success', '登録完了しました。');
}
return redirect('/file')->with('success', '失敗しました。');
}
結果:エラー発生「Call to a member function isValid() on null」。
fileはザルの状態なので、検証③と同じ結果になります。
結果が検証③と同じなので、画像処理ありの検証は、検証④の理由から行いませんでした。
ここまでの結果だと、ファイルの存在確認をしていなければ、バリデーションのfileは無意味。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
ファイルの存在を確認しての追加検証
検証① バリデーションrequiredとfileのみ記載 画像に対する処理なし
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
$this->validate($request, [
'img' => 'required|file',
]);
return redirect('/file')->with('success', '登録完了しました。');
}
結果:問題なし。バリデーションのエラーがきちんと表示される。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
検証② バリデーションrequiredとfileのみ記載 画像に対する処理あり
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
$this->validate($request, [
'img' => 'required|file',
]);
$path = $request->img->store('public/images');
$filename = basename($path);
$data = new FileImage;
$data->file_name = $filename;
$data->save();
return redirect('/file')->with('success', '登録完了しました。');
}
結果:問題なし。バリデーションのエラーがきちんと表示される。
requiredがしっかり動作しているので、ファイルが無い場合も問題無し。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
検証③ hasFileとisValidメソッドのみ記載 画像に対する処理なし
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
if ($request->hasFile('img')) {
if ($request->file('img')->isValid()) {
return redirect('/file')->with('success', '登録完了しました。');
}
}
return redirect('/file')->with('success', '失敗しました。');
}
結果:問題なし。「失敗しました」が表示される。
ファイルの存在確認を行っているので、Call to a member function isValid() on nullのエラーは発生しませんでした。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
ちなみに、ネストさせず早期リターンさせるなら以下の記述でも同様の結果になります。
※「!」が入るとわかりづらい人もいるかと思うので、ネストさせる方で記載してます。
public function store(Request $request)
{
if (!$request->hasFile('img')) {
return redirect('/file')->with('success', '失敗しました。');
}
if ($request->file('img')->isValid())
return redirect('/file')->with('success', '登録完了しました。');
}
}
}
検証④ hasFileとisValidメソッドのみ記載 画像に対する処理あり
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
if ($request->hasFile('img')) {
if ($request->file('img')->isValid()) {
$path = $request->img->store('public/images');
$filename = basename($path);
$data = new FileImage;
$data->file_name = $filename;
$data->save();
return redirect('/file')->with('success', '登録完了しました。');
}
}
return redirect('/file')->with('success', '失敗しました。');
}
結果:問題なし。「失敗しました」が表示される。
ファイルの存在確認を行っているので、Call to a member function isValid() on nullのエラーは発生しませんでした。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
検証⑤ バリデーションrequiredとfileとisValidメソッドを記載 画像に対する処理なし
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
$this->validate($request, [
'img' => 'required|file',
]);
if ($request->file('img')->isValid()) {
return redirect('/file')->with('success', '登録完了しました。');
}
return redirect('/file')->with('success', '失敗しました。');
}
結果:問題なし。バリデーションのエラーがきちんと表示される。
requiredがしっかり動作しているので、ファイルが無い場合も問題無し。
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
検証⑥ バリデーションrequiredとfileとisValidメソッドを記載 画像に対する処理あり
検証④で問題がない為、検証の必要がないのでこの検証は行いませんでした。
結果は検証④と同じです。
検証⑦ バリデーションfileとhasFileとisValidメソッドを記載 画像に対する処理なし
上記の条件で、ファイルを選択しない(空:null)状態で送信ボタンをクリック。
public function store(Request $request)
{
$this->validate($request, [
'img' => 'file',
]);
if ($request->hasFile('img')) {
if ($request->file('img')->isValid()) {
return redirect('/file')->with('success', '登録完了しました。');
}
}
return redirect('/file')->with('success', '失敗しました。');
}
結果:問題なし。「失敗しました」が表示される。
ファイルの存在確認を行っているので、Call to a member function isValid() on nullのエラーは発生しませんでした。
バリデーションfileはここではザルの状態なので、この記述であれば検証③の結果も踏まえてfileは不要と言えます
★注意点★
同じ条件でファイルを選択した場合は、問題無く動作し、「登録完了しました。」が表示されます。
結果が見えているので、「画像に対する処理あり」は検証しません。
結果は同じになります。
検証結果まとめ
・fileもisValidも、単体の使用では意味がない。
・ファイルの存在確認が必須。
・存在確認をしない場合、isValidはエラーが出るが、fileはエラーもでずザルなので不要だと思う。※断定できない点があります。
・バリデーションでrequiredとfileを設定するなら、isValidは不要だと思う。※断定できない点があります。
・メソッドでhasFileとisValidを使うなら、fileは不要だと思う。※断定できない点があります。
断定できない点について
「不要。」と断定で記載したのですが、自分の現知識では検証できない内容がある為、断定ができません。
検証過程で、fileもisValidもファイルの存在確認ではなく、アップロードの処理がされたがどうかを確認していることがわかりました。
自分が検証できない内容ですが、ファイルをきちんと選択して送信をした場合で、アップロード時に何らかの障害がでた場合のそれぞれの検証です。
アップロード時に、わざと障害を起こさせることができませんでした。
仮に起こせたとして、fileもisValidも同じようにエラーを返すなら、片方だけでいいと思います。
もし、それぞれ違う結果がでるなら、両方の記載が必要。
※ただ、バリデーションでエラーを返すのと、メソッドでエラーを返すのどっちがいいか迷いますね。
結論
懸念材料がある為、両方記載するのが現状望ましい。
存在の確認についてはrequiredかhasFileのどちらかでいい。
ただし、hasFileを使用するのであれば、存在確認をしないfileはザルなので、fileは不要。
素人の個人的な見解なので、参考程度にしておいてください。