はじめに
Laravelでフォームバリデーションのimage
というルールを使っていて、今回少し分かりづらい点があったので、対処法を備忘録を残していきます。
今回のLaravelのバージョンは5.6
です。
※今回の件はバージョン8.0から改善されていそうで、7.0
までは該当するかと思います。
現状のコードはこんな感じ。
$rules['file'] = 'file|image';
エラー内容
- 本来jpgの画像はバリデーションが通らなければいけないが、jpgの画像をアップロードしようとすると
The upload file must be an image.
と表示されてしまっていて、pngでは問題なくバリデーション通っている。 - エラー内容概説
- アップロードファイルは画像である必要がある。
試したこと(現状)
-
Laravel公式ドキュメントを確認してみる
- フィールドで指定されたファイルが画像(
jpg
、png、bmp、gif、svg)であることをバリデートしますと書いている - バージョンアップしたばかりだったため、前のバージョンと見比べても挙動の違いはなさそう
- フィールドで指定されたファイルが画像(
ふむふむ、jpgが入っているではないか・・・
ただ、それ以上の情報が公式ドキュメントに書いていないため困りました。
先輩エンジニアにアドバイス頂き、こーゆうときはvendorの中身(ライブラリの実装コード)を見ていこうと言われ、image
ルールの実装がLaravel側でどう判定されているのか中身を見ていき原因を特定しました。
原因
結論、ルールimage
だとjpgの拡張子が許容されていなかったです。
細かく見ていくと、、、
- ルール一覧が実装されていた、下記のtraitファイルの中身を見ていくと
mimes(validateMimes())
のルールが内部で呼ばれていて、第三引数には、jpeg
は入っているが、jpg
が入っていない・・・
/**
* Validate the MIME type of a file is an image MIME type.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function validateImage($attribute, $value)
{
return $this->validateMimes($attribute, $value, ['jpeg', 'png', 'gif', 'bmp', 'svg']);
}
公式にはjpg
って書いてたのに、なぜjpeg
の方しかないんや。。。
- mimesのルールも確認してみると許容する拡張子を明示的に指定できるようです。
mimes
ルールで明示的jpeg
とjpg
をどちらも指定すれば解決しそうだが、確証を得るためにvendor内下記のvalidateMimes()
のバリデーション判定で、image
とmimes:jpg,jpeg
ルールをセットしてデバッグして比較してみる。
/**
* Validate the guessed extension of a file upload is in a set of file extensions.
*
* @param string $attribute
* @param mixed $value
* @param array $parameters
* @return bool
*/
public function validateMimes($attribute, $value, $parameters)
{
+ dd($value, $parameters);
if (! $this->isValidFileInstance($value)) {
return false;
}
if ($this->shouldBlockPhpUpload($value, $parameters)) {
return false;
}
return $value->getPath() !== '' && in_array($value->guessExtension(), $parameters);
}
デバッグ結果
- 変更前(image)
-
jpeg
が許容されていて、jpg
が何故かいない(公式の表記わかりづらい、、、)
-
^ array:5 [
0 => "jpeg"
1 => "png"
2 => "gif"
3 => "bmp"
4 => "svg"
]
- 変更後(mimes:jpg,jpeg,png)
-
jpg
とjpeg
を明示的に追加しているので、どちらも許容される
-
^ array:6 [
0 => "jpg"
1 => "jpeg"
2 => "png"
]
解決策
-
mimes
ルールで明示的に許容する
- $rules['file'] = 'file|image';
+ $rules['file'] = 'file|mimes:jpg,jpeg,png';
結果
- 無事jpgファイルをアップロードして、バリデーションが通りました!
終わりに
公式ドキュメントを見ても、解決しないときはライブラリの中身の実装を見るのはかなり成長するし、いい体験になるし、課題解決力も上がる気がするので、またこの体験は別途記事にしたいと思います。
なおLaravel8からは、image
ルールにjpeg
が追加されている模様なので、jpg
は元々ある点だけ気になりますが、問題なく動くかも?
もし問題あればまたライブラリ内の実装を確認するのがよいかもです。
参考