Laravelの入力検証 (Csv, Excelファイル)
概要
ファイルアップロードの際、CSVファイルやExcelファイルのチェックに、
下記ルールを使ったが、期待する動作を得られなかったので調べた結果をメモします。
※ 単純にファイル拡張子(ファイル名)をチェックしたかった...
・Rule mimes
https://readouble.com/laravel/6.x/ja/validation.html#rule-mimes
チェック処理 (mimes)
下記のコードが該当のルール処理のようです。
public function validateMimes($attribute, $value, $parameters)
{
...
return $value->getPath() !== '' && in_array($value->guessExtension(), $parameters);
}
この処理を見ると...
拡張子をチェックには「 $value->guessExtension()
」が使われている。
/**
* ...
*
* @see MimeTypes
* @see getMimeType()
*/
public function guessExtension()
{
return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null;
}
このメソッドは、「MimeTypes」クラスが使われている。
/**
* ...
*
* @see Resources/bin/update_mime_types.php
*/
private static $map = [
'text/plain' => ['txt', 'text', 'conf', ... ],
...,
'text/csv' => ['csv'],
...
];
そのため、実際は、ファイル名の拡張子ではく、mimeTypeで判定している。
mimeTypeが「text/plain
」のCSVファイルの場合は、「txt
」と判定される。
↓↓↓
純粋にファイル名の拡張子でチェックして欲しい要件の場合には、都合が良くない。
※ xlab
という拡張子も、xlsx
と判定されてしまった...
対応方法
期待する動作が得られないので、独自ルールを作るしかないかとやってみる...
独自ルール追加を追加する
下記コマンドで、独自ルールのクラスを追加する。
$ php artisan make:rule FileExtension
追加したクラスには、以下のように記述してみました。
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class FileExtension implements Rule
{
/**
* @var array
*/
private $extensions;
/**
* @param array $extensions
*/
public function __construct(array $extensions)
{
$this->extensions = $extensions;
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value): bool
{
return $value->getPath() !== '' && in_array($value->getClientOriginalExtension(), $this->extensions);
}
/**
* Get the validation error message.
*
* @return string
*/
public function message(): string
{
return sprintf('The file extension is invalid. (%s)', implode(',', $this->extensions));
}
}
独自ルールを登録する
独自ルールを、Validatorに登録しておいた方が使うのに楽そうです。
新規に作るValidatorServiceProviderをconfigに追加する。
'providers' => [
...,
App\Providers\ValidatorServiceProvider::class, // ← 追記する
],
ValidatorServiceProviderクラスを追加する。
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;
use App\Rules\FileExtension;
class ValidatorServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
Validator::extend('extensions', function ($attribute, $value, $parameters) {
$rule = app()->makeWith(FileExtension::class, [
'extensions' => $parameters
]);
return $rule->passes($attribute, $value);
});
}
}
独自ルールを使ってみる
formRequestクラスにextensions
というルールを定義してみる。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UploadRequest extends FormRequest
{
private $mimetypes = [
'text/csv', // csv
'text/plain', // csv
'application/vnd.ms-excel', // excel ( .xls OFFICE2007より過去 )
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // excel ( .xlsx OFFICE 2007以降 )
];
private $extensions = [
'csv',
'xls',
'xlsx',
];
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'file' => [
'required',
'file',
'mimetypes:' . implode(',', $this->mimetypes),
'extensions:' . implode(',', $this->extensions),
],
];
}
public function messages(): array
{
return [
'file.required' => 'ファイルを指定してください。',
'file.mimetypes' => '指定されたファイル形式はアップロードできません。',
'file.extensions' => sprintf('ファイルの拡張子が間違っています(%s)。', implode(',', $this->extensions)),
];
}
}
これで、問題ないようでした。
まとめ
とりあえず、独自実装で要件を満たす動作を構築できました。
ひとまず、学習のために作ってみましたが...
独自で作らなくても、簡単に実装できる方法(ライブラリなど)があれば、
そっちを使った方がいいかもですね(^^;)
参考資料
- Laravel 6.x バリデーション
- Laravel でファイルアップロードでcsv の拡張子が取得できない
- Laravelで200%お世話になるであろうUploadedFileクラスを見てみよう
- How to pass parameters in Laravel Rule?
以上
Author And Source
この問題について(Laravelの入力検証 (Csv, Excelファイル)), 我々は、より多くの情報をここで見つけました https://qiita.com/reflet/items/3a9275e8b3f87fca069a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .