- カテゴリ: validation
- 掲載バージョン: Laravel 12・PHP 8.4
- 名前空間 / FQCN / コマンド: ルール文字列(
extensions:jpg,pngのように指定) - 関連:
file/image/mimes/mimetypes - 変更履歴: Laravel 9.x 系で追加(9.0 ドキュメントには未掲載。9.32 以降を推奨)(Qiita)
要点(TL;DR)
- 何に使うか: 「ファイル名の拡張子」が指定したものかどうかをチェックする。
- 最低限の使い方:
'file' => ['required', 'file', 'mimes:png', 'extensions:png']; - よくある罠
- 中身(MIMEタイプ)はチェックしない →
mimes/mimetypesと必ず併用する必要あり(laravel.com) extensionsだけだと、偽装されたファイル名でも通ってしまう- 拡張子は基本 小文字・ピリオド無し で書く(
jpg、pngなど)
- 中身(MIMEタイプ)はチェックしない →
概要
extensions ルールは、アップロードされたファイルの「ユーザーが付けた拡張子」(ファイル名の .xxx 部分)をチェックするためのバリデーションルールです。(laravel.com)mimes / mimetypes がファイルの中身から MIME タイプを推測して検証するのに対し、extensions はあくまでファイル名ベースで検証します。
そのため、実務では MIME と拡張子が一致していることを保証するために、mimes / mimetypes とセットで使うのが前提です。(laravel.com)
構文 / シグネチャ
// 文字列ルール
'field' => 'extensions:ext1,ext2,...';
// 配列ルール
'field' => ['extensions:ext1,ext2,...'];
引数
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| extensions | string | array | ✅ | なし | 許可する拡張子のリスト。ピリオド不要。jpg,png,pdf など |
※ 実際の実装ではカンマ区切り文字列として指定します。
戻り値
- bool
- 指定された拡張子リストのいずれかに一致すれば
true(バリデーション通過) - それ以外は
false(バリデーション失敗)
- 指定された拡張子リストのいずれかに一致すれば
例外 / 副作用
- 直接的な例外は投げません(通常のバリデーションエラーとして扱われる)。
- ファイルの内容は読み取りません(ユーザー指定の拡張子のみ参照)。(laravel.com)
使用例
最小例
アップロードされたテキストファイルが .txt 拡張子かをチェックしつつ、MIME もテキストであることを保証する例。
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('/upload', function (Request $request) {
$validated = $request->validate([
'file' => [
'required',
'file',
'mimes:txt', // 中身(MIME)がテキストか
'extensions:txt', // ファイル名が .txt か
],
]);
// 実際の保存処理
$path = $request->file('file')->store('uploads');
return response()->json(['path' => $path]);
});
実務例
画像アップロード API で、「PNG または JPEG 以外のアップロードを防ぐ」かつ
「拡張子偽装(例: photo.png だが中身が PDF)」も避けたいケース。
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('/profile/photo', function (Request $request) {
$validated = $request->validate([
'photo' => [
'required',
'file',
'mimes:jpeg,jpg,png', // 中身が画像かどうか
'extensions:jpeg,jpg,png', // 拡張子も画像か
'max:2048', // 2MB まで
],
]);
$path = $request->file('photo')->store('profile-photos');
// ユーザー情報にパスを保存するイメージ
$request->user()->forceFill([
'photo_path' => $path,
])->save();
return response()->json(['path' => $path]);
});
通過 / 失敗ケース
'file' => ['mimes:txt', 'extensions:txt'] の場合:
| ファイル名 | 中身の MIME | 結果 | 理由 |
|---|---|---|---|
memo.txt | text/plain | 通過 | MIME=txt かつ 拡張子=txt |
memo.sql | text/plain | 失敗 | 拡張子が txt ではない |
memo.txt | application/pdf | 失敗 | MIME が text/plain ではない |
memo.TXT | text/plain | 実装依存 | 大文字小文字の扱いは環境依存になる場合があるので小文字推奨 |
memo | text/plain | 失敗 | 拡張子が存在しない |
よくある落とし穴・注意
extensions単体で使わない- 中身を一切見ずに、ファイル名だけで判定するため、偽装ファイルを防げません。
- 公式も
mimes/mimetypesと組み合わせて使うよう明記しています。(laravel.com)
- 拡張子の書き方
- ピリオドは不要(
'.jpg'ではなく'jpg')。 - 小文字で統一するのが無難。
- ピリオドは不要(
- 古い Laravel では使えない可能性
- Laravel 9 以前のドキュメントには
extensionsの記載がなく、9.32 以降の利用が推奨されます。(Qiita)
- Laravel 9 以前のドキュメントには
代替・関連APIとの比較
mimes:jpg,png- ファイルの中身を読んで MIME タイプを判定し、「PNG 画像として正しいか」を検証。(laravel.com)
- ファイル名が
photo.txtでも、中身が PNG なら通ってしまう。
extensions:jpg,png- ファイル名の拡張子だけを見る。
- 中身は PNG ではないが、ファイル名が
photo.pngなら通ってしまう。
- 実務での選定基準
- 安全に行くなら両方
- 例:
['file', 'mimes:png', 'extensions:png']
- 例:
- 単純な UI チェックだけなら
extensionsだけでも良いが、セキュリティ的には非推奨。
- 安全に行くなら両方
テスト例(Pest)
<?php
use Illuminate\Support\Facades\Validator;
it('validates file extension and mime type', function () {
// テスト用の UploadedFile を作成
$file = new \Illuminate\Http\UploadedFile(
__DIR__.'/fixtures/sample.txt', // 実ファイル
'sample.txt', // クライアント側のファイル名
'text/plain', // MIME
null,
true
);
$validator = Validator::make([
'file' => $file,
], [
'file' => [
'required',
'file',
'mimes:txt',
'extensions:txt',
],
]);
expect($validator->passes())->toBeTrue();
});
トラブルシュート(エラー別)
| 症状 / エラー例 | 原因 | 対処 |
|---|---|---|
The file must have a file extension of: txt. 等のエラー | アップロードしたファイルの拡張子が許可リスト外 | extensions: のリストを見直す/ユーザーに再アップロードを促す |
The file must be a file of type: txt. 等のエラー | mimes ルールに合致していない(MIME が異なる) | ファイルの中身が正しいか、mimes の指定拡張子を見直す |
| 期待したファイルなのにバリデーション失敗 | 拡張子の大文字・小文字やピリオド付きでの指定ミス | extensions:TXT ではなく extensions:txt など、小文字・ピリオド無しで指定 |
| 開発環境では通るが本番で失敗する | 本番と開発で Laravel バージョンや PHP の差異 | Laravel のバージョンを確認し、extensions がサポートされているか確認 |
カスタムメッセージ
resources/lang/ja/validation.php などでメッセージを上書きできます。
'extensions' => ':attribute は次のいずれかの拡張子である必要があります: :values。',
バリデーション定義側では通常どおり attribute 名を設定します。
$request->validate([
'file' => ['required', 'file', 'mimes:txt', 'extensions:txt'],
], [
'file.extensions' => 'アップロードできるのは .txt ファイルのみです。',
]);
参考リンク
- Laravel 12.x Validation — File Validation (
extensionsの公式説明)(laravel.com) - Laravel 10.x バリデーション(日本語ドキュメント、
mimes/mimetypesの説明)(Readouble) - Qiita: Laravelでファイル拡張子のバリデーションを実装する際の注意点(
extensionsとmimesの組み合わせ解説)(Qiita) - Laravel 8.x バリデーション(古いバージョンとの差分確認用)(Readouble)

