九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
Laravelにはいつも開発の作業効率をあげてもらって、とても感謝しているんですけど、その中でもトップクラスでありがたいと感じるもの、それがバリデーション機能です。
バリデーションとは、入力データが正しいかどうかをチェックする機能のことです。一昔前までは、ひとつずつメールの妥当性をチェックするなど、とても億劫な作業でした。
でも、Laravelには強力なバリデーション機能が備わっているんで、サクサクと開発を進めることができます。
そこで!今回は、そんなバリデーション全54種類をLaravel 5.7
でテスト実行してみることにしました。ぜひ参考になれば幸いです。
目次
- 1 基本コード
- 2 accepted
- 3 after/before/after_or_equal/before_or_equal
- 4 alpha/alpha_dash/alpha_num
- 5 numeric/integer
- 6 between/size/max/min
- 7 digits/digits_between
- 8 distinct
- 9 email
- 10 exists
- 11 file/image
- 12 in/not_in
- 13 ip/ipv4/ipv6
- 14 json
- 15 mimetypes/mimes
- 16 nullable
- 17 present/filled
- 18 regex
- 19 required(と、その他関連バリデーション)
- 20 same/different
- 21 starts_with
- 22 timezone
- 23 unique
- 24 url
- 25 active_url
- 26 boolean
- 27 string
- 28 array
- 29 Confirmed
- 30 date
- 31 date_equals
- 32 date_format
- 33 dimensions
- 34 in_array
- 35 おわりに
基本コード
本来、バリデーションは「php artisan make:request *****」で独自のRequestを作成する方法がおすすめです(完全な手順!LaravelでAjaxコンテンツをつくる方法を参照してください)。
ただ、今回はテストなので、以下のコードを使います。
$input = ['name' => 'value']; $rules = ['name' => '*****']; $validator = Validator::make($input, $rules); if($validator->fails()) { echo '失敗!'; }
中身としては、
- $input ・・・ 入力データ(ここのデータが正しいかどうかチェックします)
- $rules ・・・ バリデーション・ルール
そして、もし入力データが正しくない場合は「失敗!」と表示されます。
では、さっそくひとつひとつみていきましょう!
accepted
これは、よくユーザー登録のとき、「利用規約に同意する」にチェックが入ってるかどうかを確認するバリデーションです。
<input name="kiyaku" type="checkbox" value="1" />利用規約に同意する
ここで注意が必要なのは、valueの中身です。
チェックを通過するためには、以下4つのうちのどれかでないといけません。
- yes
- on
- true
- 1
私の場合は、見た目がシンプルなので「1」を採用しています。
そして、実際のコードです。
$input = ['kiyaku' => 1]; // 成功します $rules = ['kiyaku' => 'accepted'];
after/before/after_or_equal/before_or_equal
日付が正しいかをチェックするルール。
例えば、予約を受けるとき、「30日後以内ならOK」としたいなら、以下のようになります。
$input = ['yoyaku_date' => '2018-04-15']; // 失敗(実行時が2018/3/1とする) $rules = ['yoyaku_date' => 'before:30 days']; // 30日以内
ちなみに、「30 days」の書き方は、
- now
- next Sunday
- 1 week
のような使い方もできます。
より詳しくはstrtotimeで確認してください。
なお、以下のように入力された日付データで比較もできます。
$input = [ 'yoyaku_date_1' => '2017-12-31', 'yoyaku_date_2' => '2018-01-01' ]; $rules = ['yoyaku_date_1' => 'before:yoyaku_date_2'];
2017年12月31日
は、2018年1月1日
よりも前の日付なのでバリデーションは通過します。
alpha/alpha_dash/alpha_num
文字列に関するバリデーション・ルールです。
中身としては、
- alpha ・・・ アルファベットだけOK
- alpha_dash ・・・ アルファベットとダッシュ(横棒ですね)、アンダースコアだけOK
- alpha_num ・・・ アルファベットと数字ならOK
ちなみに、ダッシュがどんなものがうまくいくのかテストしてみました。
$input = ['text' => 'ABC-']; // 成功 $rules = ['text' => 'alpha_dash'];
驚くことに、日本語の「ー」もOKでした。(逆にそうじゃないほうがいいような気はしますけどね・・・)
$input = ['text' => 'あいうー']; // 成功
次にアンダースコアです。
$input = ['text' => 'ABC_']; // 成功
もちろん成功。
では日本語は・・・?
$input = ['text' => 'あいう_']; // 失敗
え!失敗・・・・・・。。
じゃあ、チルダは?
$input = ['text' => 'ABC~']; // 失敗
うーん、、、なぜか全角のダッシュだけがOKという結果に。(全角の「〜」でも失敗します)
これは、mb_convert_kana()
なんかで半角に統一してからバリデーションしたほうが良さそうですね。
numeric/integer
入力値が数値かどうかをチェックするバリデーションですが、違いは(おおまかに言うと)小数点があるかないか。
例えば、numericの場合以下の2つともチェックには成功します。
$input = ['days' => 3]; // 成功
$input = ['days' => 3.5]; // 成功
でも、integerの場合は
$input = ['days' => 3]; // 成功
$input = ['days' => 3.5]; // 失敗
3.5だと失敗してしまいます。
ただし、もし小数点がついていてもゼロなら問題なくチェック通過します。
$input = ['days' => 3.000]; // 成功 $rules = ['days' => 'integer'];
ちなみに日本語だと・・・?
$input = ['days' => '3']; // 失敗
numeric/integerの両方とも失敗します。
between/size/max/min
量や大きさをチェックするバリデーションです。
sizeの場合は数値が1つで、betweenは数値が2つ必要です。(カンマで区切ってあげましょう)
では、betweenで数値の例を見てみましょう。
$input = ['days' => '3']; // 成功 $rules = ['days' => 'numeric|between:2,3'];
ここで注意しないといけいないのが、numericです。この場合、numericを省略してしまうと、バリデーションに失敗してしまいます。
また、between/size/max/minは配列や文字列、ファイルにも利用が可能で、配列の場合は、
$input = ['text' => [1, 2, 3]]; // 成功 $rules = ['text' => 'array|size:3'];
というように要素の数をチェックし、文字列の場合は、
$input = ['text' => 'xxxx']; // 失敗 $rules = ['text' => 'string|max:3'];
桁数をチェックします。
digits/digits_between
数字の桁数をチェックするバリデーションです。
たとえば、以下は3桁の数字なのでOKです。
$input = ['days' => 123]; // 成功 $rules = ['days' => 'digits:3'];
範囲指定したい場合は、
$input = ['days' => 123456]; // 失敗 $rules = ['days' => 'digits_between:3,5'];
というように、digits_betweenを使ってあげてください。
ちなみに、文字列だとダメかというとそうでもなく、以下のような場合は問題なくパスできます。
$input = ['days' => '01234']; // 成功 $rules = ['days' => 'digits:5'];
ただし、クォートがない場合は、失敗します。
$input = ['days' => 01234]; // 失敗 $rules = ['days' => 'digits:5'];
distinct
配列内の重複をチェックするバリデーションです。
例えば、ユーザーIDが重複しないようにしたい場合は以下のようにします。
$input = ['users' => [ [ 'id' => 1, 'name' => '太郎' ], [ 'id' => 1, 'name' => '花子' ], ] ]; // 失敗 $rules = ['users.*.id' => 'distinct'];
この場合ID「1」が重複しているので、失敗します。
ちなみに、users.*.id は配列の中身を便利に取得する方法です。もし名前の重複をチェックしたいなら「users.*.name」としましょう。
これはemailが正しいかどうかをチェックするバリデーションです。
きっと、よく使っているんじゃないでしょうか。
$input = ['days' => 'test@example.com']; // 成功 $rules = ['days' => 'email'];
exists
データベースにある特定のデータが存在するかどうかをチェックするバリデーションです。
例えば、itemsというテーブルにID「1」のデータが存在していたら、以下のバリデーションはパスできます。
$input = ['id' => '1']; // 成功 $rules = ['id' => 'exists:items'];
カラムはキー名(ここではid)をチェックしますが、
$input = ['shipped_date' => '2018-01-01']; // 成功 $rules = ['shipped_date' => 'exists:items'];
とすると、shipped_dateがチェックされます。
もしくは、以下のようにカンマで区切って指定すると、特定のカラム名でチェックすることができます。
(shipped_dateに、2018-01-01のみ存在している場合)
$input = ['id' => '2018-01-02']; // 失敗 $rules = ['id' => 'exists:items,shipped_date'];
そして、where句を使ってデータを制限することもできます。
以下のように配列内に指定しましょう。
use Illuminate\Validation\Rule; // 忘れずに!
$input = ['id' => '1']; // 成功 $rules = ['id' => [ Rule::exists('items')->where(function ($query) { $query->where('shipped_date', '2018-01-01'); }), ]];
file/image
fileは、ファイルがアップロードされているかどうかをチェックするバリデーションで、imageは以下5つの形式の画像かどうかをチェックするバリデーションです。
- jpeg
- png
- bmp
- gif
- svg
in/not_in
チェックしたいデータが、指定したものの中に存在する/存在しない?をチェックするバリデーションです。
$input = ['id' => '2']; // 成功 $rules = ['id' => 'in:1,2,3'];
毎回 implode() を使っての結合が嫌な場合は、
use Illuminate\Validation\Rule;
$input = ['id' => 2]; // 成功 $rules = ['id' => [ Rule::in([1, 2, 3]) ]];
という風にすれば、直接配列を指定することができます。
ip/ipv4/ipv6
データが、ip、もしくは、ipv4、ipv6として正しいかどうかチェックするバリデーションです。
$input = ['text' => '192.168.0.1']; $rules = ['text' => 'ip:']; // 成功
json
jsonが正しいをチェックするバリデーションです。
$input = ['id' => '[{"id":"1"}]']; // 成功 $rules = ['id' => 'json'];
mimetypes/mimes
アップロードされたファイルのmimeタイプをチェックするバリデーションで、違いは直接mimeタイプを指定するか、拡張子を指定するかです。
'video' => 'mimetypes:video/avi,video/mpeg'
'photo' => 'mimes:jpeg,png,gif'
ちなみにmimesの拡張子一覧はこちらです。
nullable
nullを許可するバリデーション・ルールです。例えば、以下のように中身がnullであっても、
$input = ['text' => null]; // 成功 $rules = ['text' => 'nullable'];
中身が入っていてもOKになります。
$input = ['text' => 'test']; // 成功 $rules = ['text' => 'nullable'];
つまり、「入力したければしてもいいよ」という入力ボックスなどに利用されるわけですね。
present/filled
どちらもデータが存在しているかどうかをチェックするバリデーション・ルールですが、違いは送信データ内にキーがあるかどうかです。
たとえば、presentの場合中身がnullでも成功しますが、
$input = ['text' => null]; // 成功 $rules = ['text' => 'present'];
filledの場合は失敗します。
$input = ['text' => null]; // 失敗 $rules = ['text' => 'filled'];
では、presentがどのような場合に失敗するのかというと、このようにキーが送信データ内に存在していない時です。
$input = ['text_2' => 'xxxx']; // 失敗 $rules = ['text_1' => 'present'];
※つまり、「text_1をチェックしたいのに、キーそのものが存在してないじゃないか!」と怒ってるんですね。
regex
正規表現を使って、文字列がマッチしているかどうかをチェックするバリデーション・ルールです。
このルールは、配列を使って利用します。(なぜならバリデーション・ルールの区切りに「|」が使われるからですね)
$input = ['text' => '5']; // 失敗 $rules = ['text' => [ 'Regex:/[a-z]/' ]];
required(と、その他関連バリデーション)
requiredは「必ずデータがないとダメ!」というバリデーション・ルールですが、これにはいろいろ関連するものがあって、現在のところ以下の7つがあります。
- required
- required_if
- required_unless
- required_with
- required_with_all
- required_without
- required_without_all
中には複雑なものもありますので、ひとつひとつ例で見ていきましょう。
(1) required
これは基本中の基本ですね。
きっと一番よく使ってるんじゃないでしょうか。
$input = ['text' => '']; // 失敗 $rules = ['text' => 'required'];
(2) required_if
「もし、他の入力データが「***」なら、ここは必須ですよ!」というバリデーション。
以下の例でいうと、「もし、text_1がxxxなら、text_2は入力必須」となります。
$input = [ 'text_1' => 'xxx', 'text_2' => '' ]; // 失敗 $rules = ['text_2' => 'required_if:text_1,xxx'];
(3) required_unless
これはrequired_ifの逆バージョンで、「もし、他の入力データが「***」以外なら、ここは必須ですよ!」というバリデーション。
例は、「もし、text_1がyyy以外なら、text_2は入力必須」となります。
$input = [ 'text_1' => 'xxx', 'text_2' => '' ]; // 失敗 $rules = ['text_2' => 'required_unless:text_1,yyy'];
(4) required_with
「他のデータが存在してるなら、ここは必須です」というバリデーション・ルールです。
以下の例では、「もしtext_1が存在してるなら、text_2は必須入力」となります。
$input = [ 'text_1' => 'xxx', 'text_2' => '' ]; // 失敗 $rules = ['text_2' => 'required_with:text_1'];
ちなみに、
$input = [ 'text_1' => '', 'text_2' => '' ]; // 成功 $rules = ['text_2' => 'required_with:text_1'];
$input = [ 'text_2' => '' ]; // 成功 $rules = ['text_2' => 'required_with:text_1'];
中身が空白でも、キー自体が存在しない場合も「存在しない」ということになります。
(5) required_without
required_withの逆バージョンです。
以下は、「もし、text_1が空白(存在しない)なら、text_2は必須入力」となります。
つまり、text_1かtext_2どっちかにデータが入っていればバリデーションは通過できます。
$input = [ 'text_1' => '', 'text_2' => '' // 必須 ]; // 失敗 $rules = ['text_2' => 'required_without:text_1'];
(6) required_with_all
required_withの複数形バージョンです。
下の例だと、「text_1とtext_2のデータがあるなら、text_3も必須入力」となります。
$input = [ 'text_1' => 'x', 'text_2' => 'y', 'text_3' => '' // 必須 ]; // 失敗 $rules = ['text_3' => 'required_with_all:text_1,text_2'];
(7) required_without_all
required_withoutの複数バージョンです。
下の例は、「text_1とtext_2が空白(存在しない)なら、text_3は必須入力」となります。
$input = [ 'text_1' => '', 'text_2' => '', 'text_3' => '' // 必須 ]; // 失敗 $rules = ['text_3' => 'required_without_all:text_1,text_2'];
same/different
他のデータと同じ値かどうか、もしくは違うかをチェックするバリデーションです。
sameの場合、次の例は「text_2の値は、text_1と一緒?」となります。
$input = [ 'text_1' => 'xxx', 'text_2' => 'xxx' ]; // 成功 $rules = ['text_2' => 'same:text_1'];
そして、differentの場合は、「同じだとダメ」という意味なので、次の例だとバリデーションに失敗します。
$input = [ 'text_1' => 'xxx', 'text_2' => 'xxx' ]; $rules = ['text_1' => 'different:text_2']; // 失敗
starts_with
テキストが指定した文字列ではじまるかどうかをチェックするバリデーション・ルールです。
※ Laravel 5.7.15
で追加されました。
$input = ['name' => 'value']; // 失敗 $rules = ['name' => 'starts_with:valx'];
なお、チェックする文字列はカンマ区切りで複数指定できます。
$input = ['name' => 'value']; // 失敗 $rules = ['name' => 'starts_with:vae,valx,vale'];
また、日本語テキストでも機能します。
$input = ['name' => '東京都世田谷区']; // 成功 $rules = ['name' => 'starts_with:東京'];
timezone
タイムゾーンをチェックするバリデーション・ルールです。
例えば、以下のようにチェックします。
$input = ['text' => 'Asia/Tokyo']; // 成功 $rules = ['text' => 'timezone'];
unique
データベース内に同じ値がないか(あってはいけない)をチェックするバリデーション・ルールです。
例えば、メールアドレスやIDなど重複してはいけないものなどに使われます。
// すでにidに「1」のデータがある場合 $input = ['id' => '1']; $rules = ['id' => 'unique:users']; // 失敗
existsバリデーションと同じく、チェックされるカラム名はキー名です。
そのため、以下はemailカラムがチェックされます。
// すでにemailに「admin@example.com」のデータがある場合 $input = ['email' => 'admin@example.com']; $rules = ['email' => 'unique:users']; // 失敗
ただ、もしキー名ではなくて特定のカラム名を指定したい場合は、
$input = ['email' => 'admin@example.com']; $rules = ['email' => 'unique:users,email_address'];
とすればOKです。
また、ユーザー情報を変更する場合など、「自分以外のメールアドレスで重複禁止」といった場合には、以下のように例外をつけてあげます。
use Illuminate\Validation\Rule;
$user_id = 1; $input = ['email' => 'admin@example.com']; $rules = ['email' => Rule::unique('users')->ignore($user_id) ];
この例は、「usersテーブルのidが1のもの以外で重複禁止」となります。もしid以外でデータの除外をしたい場合は、
Rule::unique('users')->ignore($user_id, 'user_id')
という風に第二引数にカラム名を記述してあげましょう。
そして、where句を使うこともできて、以下のように都道府県が「東京都」となってる人の中から重複チェックをすることもできます。
use Illuminate\Validation\Rule;
$input = ['email' => 'admin@example.com']; $rules = ['email' => Rule::unique('users')->where(function ($query) { return $query->where('todofuken', '東京都'); }) ];
注意すべき点は、「where句で取得したデータの中に、同じものがあってはいけない」という点です。
つまり、上の例でいうと「東京都に住んでいる人で、メールアドレスがadmin@example.comの人はいないよね?(いちゃダメ)」ということになります。
url
URLが正しいかどうかをチェックするバリデーション・ルールです。
$input = ['text' => 'http://google.com']; $rules = ['text' => 'url']; // 成功
ちなみに以下のようにhttpsもOKですし、ポート番号やパラメータが入っていても問題ありません。
$input = ['text' => 'https://google.com:8000/xxx/yyy/zzz?key=value']; $rules = ['text' => 'url']; // 成功
active_url
DNSリソースレコードを取得し、「A」もしくは「AAAA」かをチェックするバリデーション・ルール。
boolean
booleanかどうかをチェックするバリデーション・ルールです。
$input = ['text' => true]; $rules = ['text' => 'boolean']; // 成功
真偽値以外は失敗します。
$input = ['text' => 3]; $rules = ['text' => 'boolean']; // 失敗
string
文字列かどうかをチェックするバリデーション・ルールです。
$input = ['text' => 'xxx']; $rules = ['text' => 'string']; // 成功
ちなみに、
$input = ['text' => '3']; $rules = ['text' => 'string']; // 成功
はパスしますけど、以下は失敗します。
$input = ['text' => 3]; $rules = ['text' => 'string']; // 失敗
array
配列かどうかをチェックするバリデーション・ルールです。
$input = ['text' => [1, 2, 3]]; $rules = ['text' => 'array']; // 成功
Confirmed
パスワードを入力してもらうとき、入力ボックスが●●●●●で隠されてしまうため、ミスタイプがあるかどうか、目で見て判断できません。
そのために、「パスワード(確認)」などとして、もう一度同じパスワードを入力してもらう場面があると思います。
そんな場合に、1つめのパスワードと2つ目のパスワードが一致しているかどうかをチェックすることができるバリデーション・ルールで、使い方は以下のようになります。
$input = [ 'password' => 'xxx', 'password_confirmation' => 'xxxw' ]; $rules = ['password' => 'confirmed']; // 成功
ここで重要なのは、キー名です。
というのも、confirmed はキー名が、「そのキー名 + _confirmation」を自動で探して文字列の比較を行ってくれるからです。
つまり、HTMLでいうと、
パスワード: <br> <input name="password" type="password"> パスワード(確認):<br> <input name="password_confirmation" type="password">
というように、nameが
- password
- password_confirmation
という2つの入力ボックスを用意する必要があります。
date
dateは、日付をチェックするバリデーション・ルールです。
使い方は、次のようになります。
$input = ['text' => '2018-01-01']; $rules = ['text' => 'date']; // 成功
ちなみに、日付にスラッシュを使ってもバリデーションはパスします。
$input = ['text' => '2018/01/01']; $rules = ['text' => 'date']; // 成功
月日のゼロを省略してもOK。
$input = ['text' => '2018/1/1']; $rules = ['text' => 'date']; // 成功
でも、年を省略すると失敗します。
$input = ['text' => '18/1/1']; $rules = ['text' => 'date']; // 失敗
もちろん、ありえない日付もアウトです。
$input = ['text' => '2018/2/29']; $rules = ['text' => 'date']; // 失敗
そして、全角文字もダメです。
$input = ['text' => '2018年1月1日']; $rules = ['text' => 'date']; // 失敗
date_equals
入力された日付が同じかどうかをチェックするバリデーション・ルールです。
$input = ['text' => '2018-01-01']; $rules = ['text' => 'date_equals:2018-01-01']; // 成功
このバリデーションは、strtotime関数を使ってくれるので、ハイフンとスラッシュなど表記が違っていても実際の日付が同じならきちんと通過します。
$input = ['text' => '2018-01-01']; $rules = ['text' => 'date_equals:2018/1/1']; // 成功
なお、Laravel 5.7.15
からは以下のようにエラーメッセージを翻訳させることができるようになりました。
// resources/lang/en/validation.php 'date_equals' => 'The :attribute must be a date equal to :date.',
日本語の場合はこんなカンジです。
// resources/lang/ja/validation.php 'date_equals' => ':attributeは、:dateと同じ日付を指定してください。',
実際のエラーメッセージは次のようになります。
textは、2018-01-01と同じ日付を指定してください。
date_format
日付の表記があっているかをチェックするバリデーション・ルールです。
つまり、次の形なら成功しますが、
$input = ['text' => '2018-01-01']; $rules = ['text' => 'date_format:Y-m-d']; // 成功
こちらの場合だと失敗します。
$input = ['text' => '2018-1-1']; $rules = ['text' => 'date_format:Y-m-d']; // 失敗
dimensions
画像のサイズをチェックするバリデーションです。
使えるパターンは、以下の7パターン。
- min_width
- max_width
- min_height
- max_height
- width
- height
- ratio
以下のように、イコール「=」でつなげて、カンマで区切ります。
$rules = ['image' => 'dimensions:min_width=100,min_height=200'];
ちなみにratioの場合は、こうなります。
$rules = ['image' => 'dimensions:ratio=3/2'];
in_array
他の配列データの中に、同じものがあるかどうかをチェックするバリデーション・ルールです。
使い方は、こうなります。
$input = [ 'text_1' => ['x', 'y', 'z'], 'text_2' => 'x' ]; $rules = ['text_2' => 'in_array:text_1.*']; // 成功
気をつけないといけないのが、in_arrayはドットつなぎで渡さないといけないと言う点です。以下のようにキー名だけで実行してもうまくいきません。
$input = [ 'text_1' => ['x', 'y', 'z'], 'text_2' => 'x' ]; $rules = ['text_2' => 'in_array:text_1']; // 失敗
おわりに
特にconfirmedのように、「やる必要のないことは、極力やらないでOKにする」という点がLaravelがこれだけ愛される理由なのだろうな、とつくづく思いました。
日本の働き方改革もこうあってほしいものです(笑)