バリデーション(入力のチェック)
送られてきた入力が正しいかを調べるバリデーションの使い方を、書き方・エラーの表示・フォームリクエスト・自作のルールまで説明します。
バリデーションは、送られてきた入力が正しいかを調べることです。たとえば「題名は必ず入れる」「メールアドレスの形になっている」といった決まりを、保存の前に確かめます。学校の提出物の、受付での「名前は書いてありますか」の確認のようなものです。
いちばんよく使うのは、リクエスト(ブラウザから届くお願い)の validate メソッドです。このページでは、ほかのやり方も説明します。確かめるための決まり(ルール)は種類が多いので、一覧は バリデーションのルール一覧にまとめてあります。値がほかと重ならないか(ユニークか)を、データベースで確かめるルールもあります。
まず動かしてみる#
フォームの入力を確かめて、エラーを画面に返すまでの流れを、ひととおり見てみます。
ルートを決める#
まず、routes/web.php に、次のルート(URL と、それを受け持つ処理を結びつけること)があるとします。
use App\Http\Controllers\PostController;
Route::get('/post/create', [PostController::class, 'create']);
Route::post('/post', [PostController::class, 'store']);
GET のルートは、新しいブログ記事を作るフォームを表示します。POST のルートは、新しい記事をデータベースに保存します。
コントローラーを作る#
次に、この2つのルートを受け持つコントローラー(リクエストを受けて、何を返すかを決めるクラス)です。store メソッドは、まず空にしておきます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class PostController extends Controller
{
/**
* Show the form to create a new blog post.
*/
public function create(): View
{
return view('post.create');
}
/**
* Store a new blog post.
*/
public function store(Request $request): RedirectResponse
{
// Validate and store the blog post...
$post = /** ... */
return to_route('post.show', ['post' => $post->id]);
}
}
確かめる処理を書く#
store メソッドに、確かめる処理を書きます。Illuminate\Http\Request の validate メソッドを使います。決まりを守っていれば、そのまま次へ進みます。守っていなければ、Illuminate\Validation\ValidationException という例外(エラーの知らせ)が起き、エラーの答えが自動でユーザーに返されます。
ふつうの HTTP のリクエストで失敗したときは、前のページへ戻す答え(リダイレクト)が作られます。XHR リクエスト(JavaScript が、ページを切りかえずに送るリクエスト)のときは、エラーの文を入れた JSON の答えが返ります(後の「エラーの JSON」の節)。
/**
* Store a new blog post.
*/
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
// The blog post is valid...
return redirect('/posts');
}
validate には、ルールを配列で渡します。使えるルールはルール一覧にあります。失敗したときは、答えが自動で作られ、通ったときは、コントローラーの処理が続きます。
validateWithBag を使うと、エラーを、名前を付けたエラーのまとまり(エラーバッグ)に入れられます。
$validated = $request->validateWithBag('post', [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
最初の失敗で止める#
1つの項目で、最初に失敗したら、それ以降のルールを確かめたくないときは、bail というルールを付けます。
$request->validate([
'title' => ['bail', 'required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
この例では、title の unique が失敗したら、max は確かめません。ルールは、並べた順に確かめられます。
入れ子の項目#
HTTP のリクエストに「入れ子」のデータ(author の中に name がある、など)が含まれるときは、ルールのキーを、ドット . でつなげて書きます。
$request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'author.name' => ['required'],
'author.description' => ['required'],
]);
項目の名前に、本物のドットが含まれているときは、ドットの前にバックスラッシュを付けると、入れ子の意味にされません。
$request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'v1\.0' => ['required'],
]);
エラーを表示する#
入力がルールを守っていなかったら、どうなるでしょう。前に書いたとおり、Laravel は、ユーザーを前の場所へ戻します。同時に、すべてのエラーと入力した内容を、セッション(同じ人のアクセスをまたいで、少しの情報を覚えておくしくみ)に、1回だけ読める形で入れます。
$errors という変数が、すべてのビューで使えます。web ミドルウェアグループ(まとめてかかるミドルウェア)に入っている Illuminate\View\Middleware\ShareErrorsFromSession が、用意します。そのため、ビューで $errors は、いつもあるものとして使えます。$errors の中身は、Illuminate\Support\MessageBag というクラスのものです。使い方は、後の「エラーメッセージを扱う」の節です。
今の例では、失敗すると、ユーザーはコントローラーの create メソッドへ戻されます。ビューで、エラーを表示できます。
<!-- /resources/views/post/create.blade.php -->
<h1>Create Post</h1>
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<!-- Create Post Form -->
エラーの文を変える#
Laravel に入っているルールには、エラーの文が、lang/en/validation.php に書かれています。アプリに lang フォルダがなければ、lang:publish という Artisan コマンド(php artisan で動かすコマンド)で作れます。
lang/en/validation.php には、ルールごとの文があります。アプリに合わせて、自由に直せます。
このファイルを別の言語のフォルダにコピーすれば、エラーの文を、その言語に訳せます。多言語対応のくわしいことは、多言語対応のページにあります。
注意
新しい Laravel のアプリには、はじめは lang フォルダがありません。Laravel の言語ファイルを直したいときは、lang:publish コマンドで取り出します。
XHR リクエストの場合#
この例では、ふつうのフォームでデータを送りました。しかし、JavaScript で作った画面から、XHR リクエストで送るアプリも多くあります。XHR リクエストで validate を使ったときは、リダイレクトは作られません。代わりに、すべてのエラーを入れた JSON の答えが、HTTP のステータスコード 422 で返ります。
@error ディレクティブ#
Blade の @error ディレクティブ(@ で始まる命令)で、その項目にエラーがあるかを調べられます。中では $message で、エラーの文を表示できます。
<!-- /resources/views/post/create.blade.php -->
<label for="title">Post Title</label>
<input
id="title"
type="text"
name="title"
class="@error('title') is-invalid @enderror"
/>
@error('title')
<div class="alert alert-danger">{{ $message }}</div>
@enderror
名前を付けたエラーバッグ(後の節)を使うときは、@error の2つ目の引数に、その名前を渡せます。
<input ... class="@error('title', 'post') is-invalid @enderror">
フォームに入力を戻す#
バリデーションの失敗でリダイレクトするとき、Laravel は、リクエストの入力のすべてを、セッションに1回だけ読める形で入れます。次のリクエストで、その入力を取り出して、ユーザーが送ろうとしたフォームの中身を、元に戻せます。
前のリクエストの入力を取り出すには、Illuminate\Http\Request の old メソッドを呼びます。
$title = $request->old('title');
old という、どこからでも呼べる関数(ヘルパー関数)もあります。Blade のテンプレートで、元に戻すときは、これが便利です。その項目の古い入力が無いときは、null が返ります。
<input type="text" name="title" value="{{ old('title') }}">
入れなくてもよい項目#
Laravel のアプリには、はじめから、グローバルミドルウェア(全部のリクエストにかかるミドルウェア)として、TrimStrings(文字の前後の空白を取る)と ConvertEmptyStringsToNull(空の文字を null にする)が入っています。そのため、空のまま送られた項目は null になります。入れなくてもよい項目には、nullable を付けてください。付けないと、null が間違いとして扱われます。
$request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
'publish_at' => ['nullable', 'date'],
]);
この例では、publish_at は、null か、正しい日付のどちらでもよい、と決めています。nullable が無いと、null は、正しくない日付として扱われます。
エラーの JSON#
ValidationException が起きたとき、リクエストが JSON の答えを求めていると、Laravel は、エラーの文を整えて、422 Unprocessable Entity の答えを返します。
次が、エラーの JSON の例です。入れ子のキーは、ドットでつないだ1つの名前になります。
{
"message": "The team name field must be a string. (and 4 more errors)",
"errors": {
"team_name": [
"The team name field must be a string.",
"The team name field must be at least 1 characters."
],
"authorization.role": [
"The selected authorization.role is invalid."
],
"users.0.email": [
"The users.0.email field is required."
],
"users.2.email": [
"The users.2.email field must be a valid email address."
]
}
}
フォームリクエストで確かめる#
込み入った確かめには、「フォームリクエスト」を作ります。フォームリクエストは、確かめる処理と、してよいかの確認(認可)を、中に持つリクエストのクラスです。make:request という Artisan コマンドで作ります。
php artisan make:request StorePostRequest
作られたクラスは、app/Http/Requests に置かれます。そのフォルダがなければ、コマンドが作ります。できたクラスには、authorize と rules の2つのメソッドがあります。
authorize は、ログインしている人が、その操作をしてよいかを決めます。rules は、リクエストのデータに使うルールを返します。
/**
* Get the validation rules that apply to the request.
*
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
];
}
補足
rules メソッドの引数に、必要な道具の型を書くと、サービスコンテナ(クラスを作って渡してくれる、道具箱のようなしくみ)が、自動で渡してくれます。
では、このルールはどうやって使われるのでしょう。コントローラーのメソッドの引数に、フォームリクエストの型を書くだけです。コントローラーのメソッドが動く前に、リクエストが確かめられます。そのため、コントローラーに確かめる処理を書かなくて済みます。
/**
* Store a new blog post.
*/
public function store(StorePostRequest $request): RedirectResponse
{
// The incoming request is valid...
// Retrieve the validated input data...
$validated = $request->validated();
// Retrieve a portion of the validated input data...
$validated = $request->safe()->only(['name', 'email']);
$validated = $request->safe()->except(['name', 'email']);
// Store the blog post...
return redirect('/posts');
}
失敗したときは、ユーザーを前の場所へ戻す答えが作られます。エラーは、セッションに入れられ、表示できます。XHR リクエストのときは、ステータスコード 422 で、エラーの JSON が返ります。
補足
Inertia で作った Laravel の画面で、フォームリクエストのバリデーションを、入力しながらその場で確かめたいときは、Laravel Precognition という機能があります。
確かめたあとの追加の確認#
最初の確かめのあとに、さらに確かめたいことがあります。そのときは、フォームリクエストの after メソッドを使います。
after は、確かめが終わったあとに呼ばれる関数の配列を返します。関数は Illuminate\Validation\Validator を受け取り、必要ならエラーを足せます。
use Illuminate\Validation\Validator;
/**
* Get the "after" validation callables for the request.
*/
public function after(): array
{
return [
function (Validator $validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add(
'field',
'Something is wrong with this field!'
);
}
}
];
}
after が返す配列には、__invoke メソッドを持つクラスも入れられます。__invoke は Validator を受け取ります。
use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;
use Illuminate\Validation\Validator;
/**
* Get the "after" validation callables for the request.
*/
public function after(): array
{
return [
new ValidateUserStatus,
new ValidateShippingTime,
function (Validator $validator) {
//
}
];
}
最初の失敗で、全体を止める#
リクエストのクラスに StopOnFirstFailure という PHP の属性(クラスの前に書く印)を付けると、1つでも失敗した時点で、ほかの項目の確かめも、すべて止まります。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\Attributes\StopOnFirstFailure;
use Illuminate\Foundation\Http\FormRequest;
#[StopOnFirstFailure]
class StorePostRequest extends FormRequest
{
// ...
}
知らない項目を断る#
リクエストのクラスに FailOnUnknownFields を付けると、ルールに書いていない項目が送られてきたとき、はねつけます。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\Attributes\FailOnUnknownFields;
use Illuminate\Foundation\Http\FormRequest;
#[FailOnUnknownFields]
class StorePostRequest extends FormRequest
{
public function rules(): array
{
return [
'title' => ['required', 'string'],
'body' => ['required', 'string'],
];
}
}
すべてのフォームリクエストに、まとめて効かせるには、AppServiceProvider で、次のように呼びます。
use Illuminate\Foundation\Http\FormRequest;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
FormRequest::failOnUnknownFields();
}
あるリクエストだけ、止めたいときは、属性に false を渡します。
#[FailOnUnknownFields(false)]
class PublicWebhookRequest extends FormRequest
{
// ...
}
知らない項目をはねつけると、予想外の入力が、アプリの奥まで入りこむのを防げます。マスアサインメント(一括代入。配列でまとめて値を入れること)のような問題に対する、追加の守りになります。それでも、モデルの $fillable や $guarded を設定し、信頼できる、確かめずみの入力だけを保存してください。
戻す先を変える#
フォームリクエストの確かめに失敗すると、ふつうは、前の場所へ戻されます。この動きは変えられます。RedirectTo という属性で、戻す URL を決められます。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\Attributes\RedirectTo;
use Illuminate\Foundation\Http\FormRequest;
#[RedirectTo('/dashboard')]
class StorePostRequest extends FormRequest
{
// ...
}
名前を付けたルートへ戻したいときは、RedirectToRoute を使います。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\Attributes\RedirectToRoute;
use Illuminate\Foundation\Http\FormRequest;
#[RedirectToRoute('dashboard')]
class StorePostRequest extends FormRequest
{
// ...
}
エラーバッグを変える#
フォームリクエストが失敗すると、エラーは default というエラーバッグに入ります。別の名前のエラーバッグ(後の節)に入れたいときは、ErrorBag という属性を使います。
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\Attributes\ErrorBag;
use Illuminate\Foundation\Http\FormRequest;
#[ErrorBag('login')]
class LoginRequest extends FormRequest
{
// ...
}
フォームリクエストのクラスの属性をまとめると、次のとおりです。
| 属性 | 説明 |
|---|---|
StopOnFirstFailure |
1つでも失敗したら、全体の確かめを止める |
FailOnUnknownFields |
ルールにない項目が送られたら、はねつける(false を渡すと止められる) |
RedirectTo |
失敗したときに戻す URL を決める |
RedirectToRoute |
失敗したときに戻す、名前付きルートを決める |
ErrorBag |
エラーを入れるエラーバッグの名前を決める |
フォームリクエストの認可#
フォームリクエストには、authorize メソッドもあります。ここで、ログインしている人が、そのデータを直してよいかを決めます。たとえば、直そうとしているブログのコメントが、その人のものかを確かめられます。たいていは、ゲートとポリシー(「この人はこれをしてよいか」を決める関数とクラス)を使います。
use App\Models\Comment;
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
$comment = Comment::find($this->route('comment'));
return $comment && $this->user()->can('update', $comment);
}
フォームリクエストは、Laravel の基本のリクエストクラスを引きつぐので、user メソッドで、ログインしている人を取り出せます。route メソッドは、URL の中の {} で書いた部分(ルートのパラメータ)の値を取り出します。次の例の {comment} がそれです。
Route::post('/comment/{comment}');
ルートモデルバインディング(URL の値から、モデルを自動で探してくれる機能。ルーティングのページ)を使っていれば、探されたモデルを、リクエストのプロパティとして使えて、もっと短く書けます。
return $this->user()->can('update', $this->comment);
authorize が false を返すと、ステータスコード 403 の答えが自動で返り、コントローラーのメソッドは動きません。
認可を、アプリの別の場所で決めるなら、authorize を消すか、true を返すだけにできます。
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
補足
authorize の引数にも、必要な道具の型を書けます。サービスコンテナが自動で渡します。
フォームリクエストのエラーの文#
messages メソッドを書きかえると、フォームリクエストが使うエラーの文を変えられます。「項目名.ルール名」と、その文の組を、配列で返します。
/**
* Get the error messages for the defined validation rules.
*
* @return array<string, string>
*/
public function messages(): array
{
return [
'title.required' => 'A title is required',
'body.required' => 'A message is required',
];
}
項目の名前を変える#
Laravel に入っているルールのエラーの文には、:attribute という置き場所(プレースホルダー)があります。そこへ入る項目の名前を変えたいときは、attributes メソッドを書きかえます。「項目 => 名前」の配列を返します。
/**
* Get custom attributes for validator errors.
*
* @return array<string, string>
*/
public function attributes(): array
{
return [
'email' => 'email address',
];
}
確かめる前に入力を整える#
ルールを使う前に、リクエストのデータを整えたいときは、prepareForValidation メソッドを使います。
use Illuminate\Support\Str;
/**
* Prepare the data for validation.
*/
protected function prepareForValidation(): void
{
$this->merge([
'slug' => Str::slug($this->slug),
]);
}
確かめたあとに、データを整えたいときは、passedValidation メソッドです。
/**
* Handle a passed validation attempt.
*/
protected function passedValidation(): void
{
$this->replace(['name' => 'Taylor']);
}
フォームリクエストのメソッドをまとめると、次のとおりです。
| メソッド | 説明 |
|---|---|
authorize |
その操作をしてよいかを決める |
rules |
使うルールを返す |
after |
確かめたあとの追加の確認を返す |
messages |
エラーの文を変える |
attributes |
:attribute に入る名前を変える |
prepareForValidation |
確かめる前に、データを整える |
passedValidation |
確かめたあとに、データを整える |
自分で Validator を作る#
リクエストの validate を使いたくないときは、Validator ファサード(Route::get() のように、クラス名と :: で機能を呼べる窓口)の make メソッドで、確かめる係(バリデーター)を、自分で作れます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class PostController extends Controller
{
/**
* Store a new blog post.
*/
public function store(Request $request): RedirectResponse
{
$validator = Validator::make($request->all(), [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
]);
if ($validator->fails()) {
return redirect('/post/create')
->withErrors($validator)
->withInput();
}
// Retrieve the validated input...
$validated = $validator->validated();
// Retrieve a portion of the validated input...
$validated = $validator->safe()->only(['name', 'email']);
$validated = $validator->safe()->except(['name', 'email']);
// Store the blog post...
return redirect('/posts');
}
}
make の1つ目の引数は、確かめるデータ、2つ目は、使うルールの配列です。
失敗したかを調べたら、withErrors メソッドで、エラーをセッションに入れられます。そうすると、リダイレクトのあと、$errors が自動でビューに渡され、ユーザーに表示しやすくなります。withErrors には、バリデーター・MessageBag・PHP の配列のどれかを渡せます。
最初の失敗で止める#
stopOnFirstFailure メソッドを使うと、1つでも失敗した時点で、すべての項目の確かめを止めます。
if ($validator->stopOnFirstFailure()->fails()) {
// ...
}
自動でリダイレクトする#
自分で作ったバリデーターでも、リクエストの validate のような自動のリダイレクトを使いたいときは、作ったバリデーターの validate メソッドを呼びます。失敗すると、自動でリダイレクトされ、XHR リクエストのときは、JSON の答えが返ります。
Validator::make($request->all(), [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
])->validate();
失敗したとき、エラーを名前付きのエラーバッグに入れたいなら、validateWithBag を使います。
Validator::make($request->all(), [
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required'],
])->validateWithBag('post');
名前付きのエラーバッグ#
1つのページに、フォームがいくつもあるときは、エラーをまとめた MessageBag に名前を付けると、フォームごとのエラーを取り出せます。withErrors の2つ目の引数に、名前を渡します。
return redirect('/register')->withErrors($validator, 'login');
名前を付けた MessageBag は、$errors の中から取り出せます。
{{ $errors->login->first('email') }}
自分で作ったバリデーターのエラーの文#
Laravel が用意している文の代わりに、自分の文を使わせられます。いくつか方法があります。1つ目は、Validator::make の3つ目の引数に、文を渡す方法です。
$validator = Validator::make($input, $rules, $messages = [
'required' => 'The :attribute field is required.',
]);
この例の :attribute は、確かめている項目の名前に置きかわります。ほかの置き場所も使えます。
$messages = [
'same' => 'The :attribute and :other must match.',
'size' => 'The :attribute must be exactly :size.',
'between' => 'The :attribute value :input is not between :min - :max.',
'in' => 'The :attribute must be one of the following types: :values',
];
項目ごとの文#
ある項目だけに、別の文を使いたいときは、ドットでつなぎます。項目の名前を先に書き、ルールの名前を続けます。
$messages = [
'email.required' => 'We need to know your email address!',
];
項目の名前を変える#
エラーの文の :attribute を、別の名前にしたいときは、Validator::make の4つ目の引数に、名前の配列を渡します。
$validator = Validator::make($input, $rules, $messages, [
'email' => 'email address',
]);
バリデーターで、あとから確かめる#
バリデーターにも after メソッドがあります。最初の確かめのあとに、追加で確かめられます。after は、関数か、関数の配列を受け取ります。関数は Illuminate\Validation\Validator を受け取り、エラーを足せます。
use Illuminate\Support\Facades\Validator;
$validator = Validator::make(/* ... */);
$validator->after(function ($validator) {
if ($this->somethingElseIsInvalid()) {
$validator->errors()->add(
'field', 'Something is wrong with this field!'
);
}
});
if ($validator->fails()) {
// ...
}
配列には、__invoke メソッドを持つクラスも入れられます。
use App\Validation\ValidateShippingTime;
use App\Validation\ValidateUserStatus;
$validator->after([
new ValidateUserStatus,
new ValidateShippingTime,
function ($validator) {
// ...
},
]);
確かめた入力を取り出す#
フォームリクエストや、自分で作ったバリデーターで確かめたあと、実際に確かめられたデータだけを取り出したいことがあります。方法はいくつかあります。まず、validated メソッドです。確かめられたデータの配列が返ります。
$validated = $request->validated();
$validated = $validator->validated();
safe メソッドもあります。Illuminate\Support\ValidatedInput が返ります。only・except・all で、一部か全部を取り出せます。
$validated = $request->safe()->only(['name', 'email']);
$validated = $request->safe()->except(['name', 'email']);
$validated = $request->safe()->all();
ValidatedInput は、foreach でくり返したり、['email'] のように配列と同じ書き方で取り出したりもできます。
// Validated data may be iterated...
foreach ($request->safe() as $key => $value) {
// ...
}
// Validated data may be accessed as an array...
$validated = $request->safe();
$email = $validated['email'];
確かめたデータへ、項目を足したいときは、merge です。
$validated = $request->safe()->merge(['name' => 'Taylor Otwell']);
確かめたデータをコレクション(配列を便利に扱うための入れ物)で取り出したいときは、collect です。
$collection = $request->safe()->collect();
| メソッド | 説明 |
|---|---|
validated |
確かめられたデータの配列を返す |
safe()->only |
確かめられたデータから、指定した項目だけ取り出す |
safe()->except |
確かめられたデータから、指定した項目以外を取り出す |
safe()->all |
確かめられたデータを全部取り出す |
safe()->merge |
確かめられたデータへ、項目を足す |
safe()->collect |
確かめられたデータを、コレクションで取り出す |
エラーメッセージを扱う#
バリデーターの errors メソッドを呼ぶと、Illuminate\Support\MessageBag が返ります。エラーの文を扱う、便利なメソッドがたくさんあります。すべてのビューで自動で使える $errors も、MessageBag です。
| メソッド | 説明 |
|---|---|
first |
項目の最初のエラーの文を取り出す |
get |
項目のすべてのエラーの文を、配列で取り出す |
all |
すべての項目のすべてのエラーの文を、配列で取り出す |
has |
項目にエラーの文があるかを調べる |
項目の最初のエラーの文#
項目の最初のエラーの文は、first です。
$errors = $validator->errors();
echo $errors->first('email');
項目のすべてのエラーの文#
項目のすべてのエラーの文を配列で取り出すには、get です。
foreach ($errors->get('email') as $message) {
// ...
}
配列の項目を確かめているときは、* を使って、配列の要素ごとのエラーの文をまとめて取り出せます。
foreach ($errors->get('attachments.*') as $message) {
// ...
}
すべての項目のすべてのエラーの文#
すべての項目の、すべてのエラーの文を配列で取り出すには、all です。
foreach ($errors->all() as $message) {
// ...
}
項目にエラーの文があるか#
has で、項目にエラーの文があるかを調べられます。
if ($errors->has('email')) {
// ...
}
言語ファイルでエラーの文を決める#
Laravel に入っているルールには、エラーの文が、lang/en/validation.php に書かれています。アプリに lang フォルダがなければ、lang:publish コマンドで作れます。
ファイルには、ルールごとの文があります。アプリに合わせて、自由に直せます。別の言語のフォルダにコピーすれば、その言語に訳せます。くわしくは多言語対応のページです。
注意
新しい Laravel のアプリには、はじめは lang フォルダがありません。Laravel の言語ファイルを直したいときは、lang:publish コマンドで取り出します。
項目ごとの文#
項目とルールの組み合わせごとに、文を変えたいときは、lang/xx/validation.php の custom 配列に書きます。
'custom' => [
'email' => [
'required' => 'We need to know your email address!',
'max' => 'Your email address is too long!'
],
],
言語ファイルで項目の名前を決める#
エラーの文の :attribute を、別の名前にしたいときは、lang/xx/validation.php の attributes 配列に書きます。
'attributes' => [
'email' => 'email address',
],
注意
新しい Laravel のアプリには、はじめは lang フォルダがありません。Laravel の言語ファイルを直したいときは、lang:publish コマンドで取り出します。
言語ファイルで値の表し方を決める#
エラーの文には、:value という置き場所があり、その項目の今の値に置きかわります。この値を、別の分かりやすい表し方にしたいことがあります。たとえば、payment_type が cc のとき、クレジットカードの番号を必須にするルールです。
Validator::make($request->all(), [
'credit_card_number' => ['required_if:payment_type,cc']
]);
このルールが失敗すると、次のエラーの文が出ます。
The credit card number field is required when payment type is cc.
cc ではなく、分かりやすい表し方にしたいときは、lang/xx/validation.php に values 配列を書きます。
'values' => [
'payment_type' => [
'cc' => 'credit card'
],
],
注意
新しい Laravel のアプリには、はじめは lang フォルダがありません。Laravel の言語ファイルを直したいときは、lang:publish コマンドで取り出します。
こう決めると、エラーの文は次のようになります。
The credit card number field is required when payment type is credit card.
言語ファイルの設定をまとめると、次のとおりです。
| 配列 | 説明 |
|---|---|
custom |
項目とルールの組み合わせごとに、エラーの文を変える |
attributes |
:attribute に入る名前を変える |
values |
:value に入る値の表し方を変える |
使えるルール#
ルールの一覧は、バリデーションのルール一覧のページにあります。
条件で、ルールを足す#
決まった値のときは確かめない#
ほかの項目が、ある値のときは、その項目を確かめたくないことがあります。exclude_if ルールを使います。次の例では、has_appointment が false のとき、appointment_date と doctor_name は確かめられません。
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($data, [
'has_appointment' => ['required', 'boolean'],
'appointment_date' => ['exclude_if:has_appointment,false', 'required', 'date'],
'doctor_name' => ['exclude_if:has_appointment,false', 'required', 'string'],
]);
反対に、ほかの項目が、ある値でないときは確かめない exclude_unless ルールもあります。
$validator = Validator::make($data, [
'has_appointment' => ['required', 'boolean'],
'appointment_date' => ['exclude_unless:has_appointment,true', 'required', 'date'],
'doctor_name' => ['exclude_unless:has_appointment,true', 'required', 'string'],
]);
あるときだけ確かめる#
項目が、確かめるデータの中にあるときだけ、確かめたいことがあります。そのときは、sometimes ルールをルールの一覧に足します。
$validator = Validator::make($data, [
'email' => ['sometimes', 'required', 'email'],
]);
この例では、email は、$data の配列にあるときだけ確かめられます。
補足
いつもあるはずで、空でもよい項目を確かめたいときは、前の「入れなくてもよい項目」の注意を見てください。
込み入った条件#
もっと込み入った条件で、ルールを足したいことがあります。たとえば、ほかの項目が 100 より大きいときだけ、ある項目を必須にしたい、といった場合です。まず、いつも変わらないルール(静的なルール)で、Validator を作ります。
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'email' => ['required', 'email'],
'games' => ['required', 'integer', 'min:0'],
]);
ゲームを集める人向けのアプリだとします。登録した人が 100 本以上のゲームを持っているなら、その理由を書いてもらいたい、と考えます。条件つきでこの決まりを足すには、Validator の sometimes メソッドを使います。
use Illuminate\Support\Fluent;
$validator->sometimes('reason', ['required', 'max:500'], function (Fluent $input) {
return $input->games >= 100;
});
1つ目の引数は、条件つきで確かめる項目の名前、2つ目は、足したいルールの一覧です。3つ目の引数の関数が true を返すと、ルールが足されます。複数の項目を、まとめて決めることもできます。
$validator->sometimes(['reason', 'cost'], 'required', function (Fluent $input) {
return $input->games >= 100;
});
補足
関数に渡される $input は、Illuminate\Support\Fluent です。確かめている入力やファイルを取り出せます。
込み入った、配列の条件#
同じ入れ子の配列の中の、ほかの項目の値で、確かめるかどうかを決めたいことがあります。でも、その配列が何番目かは分かりません。そういうときは、関数の2つ目の引数で、確かめている配列の1つ分を受け取れます。
$input = [
'channels' => [
[
'type' => 'email',
'address' => 'abigail@example.com',
],
[
'type' => 'url',
'address' => 'https://example.com',
],
],
];
$validator->sometimes('channels.*.address', 'email', function (Fluent $input, Fluent $item) {
return $item->type === 'email';
});
$validator->sometimes('channels.*.address', 'url', function (Fluent $input, Fluent $item) {
return $item->type !== 'email';
});
$input と同じで、$item は、その項目のデータが配列のときは Illuminate\Support\Fluent です。そうでないときは、文字列です。
配列を確かめる#
ルール一覧の array ルールにあるとおり、array ルールには、使ってよいキーの一覧を渡せます。それ以外のキーが配列の中にあると、失敗します。
use Illuminate\Support\Facades\Validator;
$input = [
'user' => [
'name' => 'Taylor Otwell',
'username' => 'taylorotwell',
'admin' => true,
],
];
Validator::make($input, [
'user' => ['array:name,username'],
]);
ふつうは、配列に入ってよいキーを、いつも書いておくべきです。書かないと、バリデーターの validate と validated が、ほかの入れ子のルールで確かめていないキーも含めて、配列全体を返してしまいます。
入れ子の配列の入力を確かめる#
入れ子になった配列の入力も、ドットでつなげて確かめられます。たとえば、HTTP のリクエストに photos[profile] という項目があるなら、次のように確かめます。
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'photos.profile' => ['required', 'image'],
]);
配列の1つ1つを確かめることもできます。たとえば、配列で送られてきたメールアドレスが、どれもほかと重ならないことを確かめるには、次のように書きます。
$validator = Validator::make($request->all(), [
'users.*.email' => ['email', 'unique:users'],
'users.*.first_name' => ['required_with:users.*.last_name'],
]);
言語ファイルの項目ごとの文(前の「言語ファイルでエラーの文を決める」の節)にも * を使えます。配列の項目に、1つの文を使えます。
'custom' => [
'users.*.email' => [
'unique' => 'Each user must have a unique email address',
]
],
入れ子の配列のデータを使う#
ルールを決めるときに、入れ子の配列の、その要素の値を使いたいことがあります。そのときは Rule::forEach メソッドを使います。forEach には関数を渡します。この関数は、配列の要素ごとに呼ばれます。受け取るのは、その項目の値と、* を実際の番号に置きかえた項目の名前(companies.0.id など)です。そして、その要素に付けるルールの配列を返します。
use App\Rules\HasPermission;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
$validator = Validator::make($request->all(), [
'companies.*.id' => Rule::forEach(function (string|null $value, string $attribute) {
return [
Rule::exists(Company::class, 'id'),
new HasPermission('manage-company', $value),
];
}),
]);
エラーの文の番号と位置#
配列を確かめるとき、失敗した要素の番号や位置を、エラーの文に入れたいことがあります。自分で決めるエラーの文に、:index(0 から数える)・:position(1 から数える)・:ordinal-position(1st のように数える)を入れられます。
use Illuminate\Support\Facades\Validator;
$input = [
'photos' => [
[
'name' => 'BeachVacation.jpg',
'description' => 'A photo of my beach vacation!',
],
[
'name' => 'GrandCanyon.jpg',
'description' => '',
],
],
];
Validator::validate($input, [
'photos.*.description' => ['required'],
], [
'photos.*.description.required' => 'Please describe photo #:position.',
]);
この例は、確かめに失敗し、ユーザーには「Please describe photo #2.」というエラーの文が出ます。
さらに深い入れ子の番号や位置は、second-index・second-position・third-index・third-position のように使えます。
'photos.*.attributes.*.string' => 'Invalid attribute for photo #:second-position.',
| 置き場所 | 説明 |
|---|---|
:index |
要素の番号(0 から数える) |
:position |
要素の位置(1 から数える) |
:ordinal-position |
要素の位置(1st のように数える) |
second-index / second-position |
2つ目の入れ子の番号/位置 |
third-index / third-position |
3つ目の入れ子の番号/位置 |
ファイルを確かめる#
アップロードされたファイルを確かめるルールは、mimes・image・min・max など、たくさんあります。1つずつ書いてもよいのですが、Laravel には、メソッドをつなげて書ける、ファイル用のルールを作る道具(File)もあります。
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\File;
Validator::validate($input, [
'attachment' => [
'required',
File::types(['mp3', 'wav'])
->min(1024)
->max(12 * 1024),
],
]);
ファイルの種類を確かめる#
types メソッドには、拡張子(ファイル名の最後の .mp3 のような部分)だけを書きます。しかし、実際には、ファイルの中身を読んで MIME タイプ(ファイルの種類を表す名前)を推しはかり、それを確かめます。MIME タイプと拡張子の一覧は、次の場所にあります。
https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
ファイルの大きさを確かめる#
最小と最大の大きさは、単位を付けた文字列でも書けます。kb・mb・gb・tb が使えます。
File::types(['mp3', 'wav'])
->min('1kb')
->max('10mb');
画像ファイルを確かめる#
ユーザーが画像をアップロードするアプリでは、File の image メソッドで、画像かどうかを確かめられます(jpg・jpeg・png・bmp・gif・webp・avif・heic・heif)。
さらに、dimensions ルールで、画像の大きさを制限できます。
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File;
Validator::validate($input, [
'photo' => [
'required',
File::image()
->min(1024)
->max(12 * 1024)
->dimensions(Rule::dimensions()->maxWidth(1000)->maxHeight(500)),
],
]);
補足
画像の大きさの確かめ方は、ルール一覧の dimensions に、くわしくあります。
注意
image ルールは、はじめは SVG ファイルを認めません。XSS(ほかの人が悪意のあるスクリプトを、ページに混ぜこむ攻撃)の危険があるからです。SVG を認めたいときは、allowSvg: true を渡します。File::image(allowSvg: true) のように書きます。
画像の大きさを確かめる#
画像の大きさ(幅と高さ)も確かめられます。たとえば、dimensions ルールで、幅が 1000 ピクセル以下、高さが 500 ピクセル以下かを確かめられます。
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\File;
File::image()->dimensions(
Rule::dimensions()
->maxWidth(1000)
->maxHeight(500)
);
補足
画像の大きさの確かめ方は、ルール一覧の dimensions に、くわしくあります。
パスワードを確かめる#
パスワードが、十分に複雑かを確かめるには、Laravel の Password ルールのオブジェクトを使います。
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rules\Password;
$validator = Validator::make($request->all(), [
'password' => ['required', 'confirmed', Password::min(8)],
]);
Password ルールでは、アプリに合わせて、パスワードの複雑さの条件を決められます。たとえば、文字・数字・記号を必ず含める、大文字と小文字を混ぜる、などです。
// Require at least 8 characters...
Password::min(8);
// Require at most 256 characters...
Password::min(16)->max(256);
// Require at least one letter...
Password::min(8)->letters();
// Require at least one uppercase and one lowercase letter...
Password::min(8)->mixedCase();
// Require at least one number...
Password::min(8)->numbers();
// Require at least one symbol...
Password::min(8)->symbols();
uncompromised メソッドを使うと、そのパスワードが、これまでの流出事件で外に漏れていないかも確かめられます。
Password::min(8)->uncompromised();
中では、k-匿名性(k-Anonymity。元のパスワードを知られないようにするしくみ)という方法で、haveibeenpwned.com のサービスに、漏れたことがあるかを問い合わせます。この方法なので、ユーザーのプライバシーや安全は守られます。
はじめは、流出したデータに、1回でも入っていれば、危ないパスワードとして扱われます。uncompromised の1つ目の引数で、その回数の目安を変えられます。
// Ensure the password appears no more than 3 times in the same data leak...
Password::min(8)->uncompromised(3);
もちろん、ここまでのメソッドは、全部つなげられます。
Password::min(8)
->max(256)
->letters()
->mixedCase()
->numbers()
->symbols()
->uncompromised();
| メソッド | 説明 |
|---|---|
min |
最低の長さを決める |
max |
最大の長さを決める |
letters |
文字を、1つ以上含める |
mixedCase |
大文字と小文字を、それぞれ1つ以上含める |
numbers |
数字を、1つ以上含める |
symbols |
記号を、1つ以上含める |
uncompromised |
流出事件で漏れたことがないかを確かめる(引数で、入っていてよい回数を決められる) |
rules |
初期のパスワードのルールに、別のルールを足す |
toPasswordRulesString |
HTML の passwordrules 属性に使える文字列にする |
toPasswordRulesString メソッドで、Password ルールを、HTML の passwordrules 属性に使える文字列にできます。
<input
type="password"
name="password"
autocomplete="new-password"
passwordrules="{{ Password::defaults()->toPasswordRulesString() }}"
/>
パスワードの初期のルールを決める#
アプリの1か所に、パスワードの初期のルールを決めておくと便利です。Password::defaults メソッドを使います。関数を受け取り、その関数が、初期の Password ルールを返します。ふつう、サービスプロバイダ(アプリの起動のときに、道具箱へ道具を登録する場所)の boot メソッドで呼びます。
use Illuminate\Validation\Rules\Password;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Password::defaults(function () {
$rule = Password::min(8);
return $this->app->isProduction()
? $rule->mixedCase()->uncompromised()
: $rule;
});
}
決めたあとは、パスワードにその初期のルールを使いたいとき、引数なしで defaults を呼びます。
'password' => ['required', Password::defaults()],
初期のルールに、別のルールを足したいときは、rules メソッドを使います。
use App\Rules\ZxcvbnRule;
Password::defaults(function () {
$rule = Password::min(8)->rules([new ZxcvbnRule]);
// ...
});
自分でルールを作る#
ルールのオブジェクトを使う#
Laravel には便利なルールがたくさんありますが、自分のルールを作りたいこともあります。方法の1つが、ルールのオブジェクトです。make:rule という Artisan コマンドで作れます。ここでは、文字が大文字かを確かめるルールを作ります。新しいルールは app/Rules に置かれます。そのフォルダがなければ、コマンドが作ります。
php artisan make:rule Uppercase
作ったら、動きを書きます。ルールのオブジェクトには、validate というメソッドが1つあります。項目の名前・値・失敗したときに呼ぶ関数(エラーの文を渡す)を受け取ります。
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class Uppercase implements ValidationRule
{
/**
* Run the validation rule.
*/
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (strtoupper($value) !== $value) {
$fail('The :attribute must be uppercase.');
}
}
}
ルールを作ったら、ほかのルールといっしょに、ルールのオブジェクトを渡します。
use App\Rules\Uppercase;
$request->validate([
'name' => ['required', 'string', new Uppercase],
]);
エラーの文を訳す#
$fail に、決まった文を渡す代わりに、翻訳のキー(多言語対応)を渡して、Laravel に訳させることもできます。
if (strtoupper($value) !== $value) {
$fail('validation.uppercase')->translate();
}
必要なら、translate の1つ目の引数に置きかえる値、2つ目の引数に言語を渡せます。
$fail('validation.location')->translate([
'value' => $this->value,
], 'fr');
確かめているほかのデータを使う#
自分で作ったルールで、確かめているほかのデータもすべて使いたいときは、Illuminate\Contracts\Validation\DataAwareRule というインターフェース(守るべき決まりを書いたもの)を使います。クラスに setData メソッドが要ります。Laravel が、確かめを始める前に、確かめているデータ全部を渡して、自動で呼びます。
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\DataAwareRule;
use Illuminate\Contracts\Validation\ValidationRule;
class Uppercase implements DataAwareRule, ValidationRule
{
/**
* All of the data under validation.
*
* @var array<string, mixed>
*/
protected $data = [];
// ...
/**
* Set the data under validation.
*
* @param array<string, mixed> $data
*/
public function setData(array $data): static
{
$this->data = $data;
return $this;
}
}
確かめているバリデーターそのものが要るときは、ValidatorAwareRule を使います。
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Contracts\Validation\ValidatorAwareRule;
use Illuminate\Validation\Validator;
class Uppercase implements ValidationRule, ValidatorAwareRule
{
/**
* The validator instance.
*
* @var \Illuminate\Validation\Validator
*/
protected $validator;
// ...
/**
* Set the current validator.
*/
public function setValidator(Validator $validator): static
{
$this->validator = $validator;
return $this;
}
}
| インターフェース | 説明 |
|---|---|
ValidationRule |
ルールのオブジェクトの基本。validate メソッドを持つ |
DataAwareRule |
確かめているデータ全部を受け取る(setData メソッド) |
ValidatorAwareRule |
確かめているバリデーターを受け取る(setValidator メソッド) |
関数でルールを作る#
自分のルールを、アプリの中で1か所でしか使わないなら、ルールのオブジェクトの代わりに、関数が使えます。関数は、項目の名前・値・失敗したときに呼ぶ $fail を受け取ります。
use Illuminate\Support\Facades\Validator;
use Closure;
$validator = Validator::make($request->all(), [
'title' => [
'required',
'max:255',
function (string $attribute, mixed $value, Closure $fail) {
if ($value === 'foo') {
$fail("The {$attribute} is invalid.");
}
},
],
]);
空でも動くルール(暗黙のルール)#
はじめは、確かめる項目がない、または空の文字のときは、自分で作ったルールも含めて、ふつうのルールは動きません。たとえば、unique ルールは、空の文字には使われません。
use Illuminate\Support\Facades\Validator;
$rules = ['name' => ['unique:users,name']];
$input = ['name' => ''];
Validator::make($input, $rules)->passes(); // true
項目が空でも自分のルールを動かしたいときは、そのルールを「暗黙のルール」にします。暗黙のルールは、「この項目は必須だ」という意味を、口に出さずにふくんでいるルールです。作るには、make:rule に --implicit オプションを付けます。
php artisan make:rule Uppercase --implicit
注意
暗黙のルールにしても、空の項目が自動で失敗になるわけではありません。項目が無いときや空のときに、本当に失敗にするかどうかは、ルールの中で自分で決めます。
関連するページ#
公式ドキュメント(英語)
2026年10月5日時点の内容をもとに、日本語でまとめています。