Laravel 之 -- 验证 (下)

February . 05 . 2019

可用的验证规则

以下是所有可用验证规则及其功能的介绍。

accepted

验证字段值必须是 yes、on、1 或者 true。这在判断是否接收了「服务条款」非常有用。

active_url

验证字段值根据 dns_get_record PHP 函数判断,必须具有有效的 A 或者 AAAA 记录。

after:date

验证字段值必须是指定日期之后的。after: 后面的日期会传递给 PHP strtotime 函数处理:

'start_date' => 'required|date|after:tomorrow'

你还可以传递另一个日期字段作比较。

'finish_date' => 'required|date|after:start_date'

after_or_equal:date

验证字段值必须是指定日期或指定日期之后的。

alpha

验证字段值必须都是字母字符(指万国码字符,是支持中文的)。

alpha_dash

验证字段值可以是字母、数字、中划线(-)和下划线(_)。

alpha_num

验证字段值可以是字母和数字。

array

验证字段值必须是 PHP array

before:date

验证字段值必须是指定日期之前的。before: 后面的日期会传递给 PHP strtotime 函数处理:

before_or_equal:date

验证字段值必须是指定日期或指定日期之前的。日期会传递给 PHP strtotime 函数处理:

between:min,max

验证字段的大小必须在给定的最小值和最大值之间。 支持字符串、数字、数组和文件的大小比较,比较规则参考 size 规则。

boolean

验证字段值必须是可以转换为布尔值的,接收的输入数据可以是 truefalse10"1" 或是 "0"

confirmed

该验证字段必须有一个对应的 foo_confirmation 字段。例如,如果验证字段是 password,就要有一个与之比较 password_confirmation 字段。

date

验证字段值必须是 PHP strtotime 函数可以处理的有效日期格式。

date_equal:date

验证字段必须与给定的日期相同。日期会传递给 PHP strtotime 函数处理。

date_format:format

验证字段必须匹配给定的日期格式。验证日期字段时,不能同时使用 datedate_format 规则

different:field

验证字段必须与 field 字段有不同的值。

digits:value

验证字段必须是数字,并且必须具有指定的位数。

digits_between:min,max

验证字段必须是数字的位数,要保证在 min 和 max 之间。

dimensions

验证文件必须是图片,还要满足指定的维度约束。

'avatar' => 'dimensions:min_width=100,min_height=200'

可以使用的约束条件包括:min_width、max_width、min_height、max_height、width、height 和 ratio。

ratio 约束表示宽高比,可以用 3/2 和 1.5 这样的浮点数指定宽高比:

'avatar' => 'dimensions:ratio=3/2'

由于这个规则需要接受几个参数,可以使用 Rule::dimensions 方法来构造这个规则:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'avatar' => [
        'required',
        Rule::dimensions()->maxWidth(1000)->maxHeight(500)->ratio(3 / 2),
    ],
]);

distinct

与数组一起使用,验证字段中不允许出现重复值。

'foo.*.id' => 'distinct'

email

验证字段必须是正确的邮件地址格式。

exists:table,column

验证字段必须存在于给定的数据库表中。

exists 规则的基本使用

'state' => 'exists:states'

指定自定义列名

'state' => 'exists:states,abbreviation'

有时,在 exists 语句里还需要指定数据库连接。这时,使用 连接.表名 的形式来实现此目的:

'email' => 'exists:connection.staff,email'

如果要自定义规则,使用 Rule 类。在这个例子中,我们将验证规则指定为数组,就不用使用 | 分隔符了。

use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::exists('staff')->where(function ($query) {
            $query->where('account_id', 1);
        }),
    ],
]);

file

验证字段必须必须是一个有效的上传文件。

filled

当验证字段存在的时候,不能为空。

image

验证字段必须是图片(jpeg、png、bmp、gif 或者 svg)。

in:foo,bar,...

验证字段值必须包含在给定的值列表中。由于此规则需要 implode数组,所以这时可以用 Rule::in 方法来构造这个规则:

use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::in(['first-zone', 'second-zone']),
    ],
]);

in_array:anotherfield

验证字段值必须存在于另一个字段的值列表中。

integer

验证字段值必须是个整数。

ip

验证字段值必须是一个 IP 地址。

ipv4

验证字段值必须是一个 IPv4 地址。

ipv6

验证字段值必须是一个 IPv6 地址。

json

验证字段值必须是一个 JSON 字符串。

max:value

验证字段的大小必须在小于或者等于给定的值。 支持字符串、数字、数组和文件的大小比较,比较规则参考 size 规则。

mimetypes:text/plain,...

验证文件必须是符合给定 MIME 类型之一的:

'video' => 'mimetypes:video/avi,video/mpeg,video/quicktime'

为了确定上传文件的 MIME 类型,Laravel 将读取文件内容,尝试猜测 MIME 类型,这可能与客户端提供的 MIME 类型不同。

mimes:foo,bar,...

验证文件必须具有与列出的其中一个扩展名相对应的 MIME 类型。

mimes 规则的基本使用

'photo' => 'mimes:jpeg,bmp,png'

虽然我们指定的是扩展名,但是规则实际验证的是文件的 MIME 类型,文件的 MIME 类型是通过读取文件内容,尝试猜测到的 MIME 类型。

完整的 MIME 类型和对应扩展名对照表参阅 这里 的地址。

min:value

验证字段的大小必须在大于或者等于给定的值。 支持字符串、数字、数组和文件的大小比较,比较规则参考 size 规则。

nullable

验证字段可取 null 值,这对于可取到 null 值的、像字符串和整数这样的基本类型的验证比较有用。

not_in:foo,bar,...

验证字段值必须不包含在给定的值列表中。可以用 Rule::notIn 方法来流畅地构造规则。

use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::notIn(['sprinkles', 'cherries']),
    ],
]);

numeric

验证字段值必须是数字。

present

验证字段必须出现在输入数据中,且值可以为空。

regex:pattern

验证字段必须匹配给定的正则表达式。

注意:最好将验证规则包含在一个数组里,而不是使用管道符号(|)连接,这在正则表达式本身包含 | 的情况特别有用。

required

验证字段必须出现在输入数据中,且值不可为空。在 Laravel 中,一个字段值满足下面任一条件都被视为空值。

  • null
  • 空字符串('')。
  • 空数组([])或者空 Countable 对象。
  • 无路径的上传文件。

required_if:anotherfield,value,...

验证字段必须出现在输入数据中,且值不可为空,这是有条件的:当另一个字段等于值列表里的任何一个值时。

required_unless:another,value,...

required_if相反,除了另一个字段等于值列表里的任何一个值时之外的情况时,当前验证字段才要求必须出现在输入数据中,且值不可为空。

required_with:foo,bar,...

只有当其他任何一个字段出现的时候,当前验证字段才要求必须出现在输入数据中,且值不可为空。

required_with_all:foo,bar,...

只有当其他所有字段出现的时候,当前验证字段才要求必须出现在输入数据中,且值不可为空。

required_without:foo,bar,...

只有当其他任何一个字段不出现的时候,当前验证字段才要求必须出现在输入数据中,且值不可为空。

required_without_all:foo,bar,...

只有当其他所有字段不出现的时候,当前验证字段才要求必须出现在输入数据中,且值不可为空。

same:field

当前验证字段值必须等于给定的这个字段值。

size:value

验证字段必须是与给定值一样的大小。对于字符串数据,value 是指字符数量;对于数字数据,value 是指数值;对于数组数据,value 是指数组的 count 值;对于文件,value 是指文件有多少 KB。

string

验证字段必须是一个字符串,如果可以取值 null,再加上 nullable 规则就 OK 了。

timezone

验证字段值是能被 PHP timezone_identifiers_list 函数识别的时区标识符。

unique:table,column,except,idColumn

验证字段值在数据库表里是唯一的。如果没指定 column,就使用验证字段名。

指定自定义列名

'email' => 'unique:users,email_address'

自定义数据库连接

有时需要为验证器的数据库查询指定自定义连接。unique:users 会使用默认的数据库连接查询数据库。需要使用 连接.数据库表 的形式覆盖使用得默认连接:

'email' => 'unique:connection.users,email_address'

强制 unique 规则忽略指定的 ID

有时,进行 unique 检查时,需要忽略一个 ID 值。例如,「更新用户资料」时,更新的字段包括用户名、邮箱地址和位置。你要验证邮箱地址是否是唯一的,但是如果用户只是更新了用户名,没有更新邮箱地址,那么提交后,就会验证错误的,因为用户已经是邮箱地址的所有者了。

为了忽略检查用户 ID 的对应的那个邮箱地址,这里要使用 Rule 去定义这个规则。

use Illuminate\Validation\Rule;

Validator::make($data, [
    'email' => [
        'required',
        Rule::unique('users')->ignore($user->id),
    ],
]);

// 等同于

Validator::make($data, [
    'email' => [
        'required',
        "unique:users,email,{ $user->id }"
    ],
]);

如果表格主键不是 id。可以为 ignore 方法指定要忽略的那个列名:

'email' => Rule::unique('users')->ignore($user->id, 'user_id');

// 等同于

'email' => "unique:users,email,{ $user->id },user_id";

添加额外的 Where 子句

可以通过自定义 where 子句添加额外的查询约束。例如,我们添加约束 account_id 值为 1。

'email' => Rule::unique('users')->where(function ($query) {
    $query->where('account_id', 1);
});

url

验证字段值必须是一个有效的 URL。

有条件的添加规则

当存在的时候验证

在一些场景中,只有 当字段存在于输入数组里才去验证它。为了实现这个功能,我们在规则里使用 sometimes

$v = Validator::make($data, [
    'email' => 'sometimes|required|email',
]);

在上面的例子,只有当字段存在于 $data 数组中时,才去验证它。

在我看来没必要,同样的功能需求用 filled 规则就能实现。

'email' => 'filled|email'

复杂条件验证

有时,需要基于更加复杂的条件逻辑添加验证规则。例如,当另一个字段的值大于 100 的时候,当前字段才是 required 的;或者有两个字段,只有在另一个字段存在的情况下,才能确定所取的数据类型。这些都不难。首先,创建一个 Validator 实例先设定那些验证规则不变的字段:

$v = Validator::make([
    'email' => 'required|email',
    'games' => 'required|numeric',
]);

设想一下我们有一个为游戏收藏者提供服务的网站。在我们的用户注册的时候,我们想让游戏收藏超过 100 个的用户解释为什么会拥有这么多的游戏。例如,也许他们在运营一家游戏专售店,或者只是因为单纯的喜欢。为了有条件地添加此要求,我们可以在 Validator 实例上使用 sometimes 方法。

$v->sometimes('reason', 'required|max:500', function ($input) {
    return $input->games >= 100;
});

sometimes 方法的一地个参数是验证字段;第二个参数是要添加的验证规则;第三个参数是一个闭包,当闭包返回 true 时,就会使用验证规则。这种方法使得构建复杂的条件验证变得轻而易举。 你甚至可以同时为几个字段添加条件验证:

$v->sometimes(['reason', 'cost'], 'required', function ($input) {
    return $input->games >= 100;
});

提示! 传递给闭包的参数 $inputIlluminate\Support\Fluent 实例,用来获得输入和文件。

验证数组字段

我们使用点(.)符号来验证数组类型字段。例如,如果传入的 HTTP 请求中包含 photos[profile] 字段,则可以如下验证:

$validator = Validator::make($request->all(), [
    'photos.profile' => 'required|image',
]);

你也可以验证数组里的每个元素。例如,验证每个元素的邮箱地址都是唯一的:

$validator = Validator::make($request->all(), [
    'person.*.email' => 'email|unique:users',
    'person.*.first_name' => 'required_with:person.*.last_name',
]);

同样,在语言文件 resources/lang/xx/validation.php 中的 custom 数组里也可以使用 * 来添加自定义消息,这样就可以基于数组字段进行验证了。

'custom' => [
    'person.*.email' => [
        'unique' => 'Each person must have a unique e-mail address',
    ]
],

自定义验证规则

使用 Rule 对象

Laravel 已然提供了大量丰富有用的验证规则。但有时还是要定义自己的验证规则,这时要使用 Rule 对象,使用 Artisan 命令 make:rule 生产它。我们以检查字符串是否全部大写为例,自定义规则对象被放在 app/Rules 目录下:

php artisan make:rule Uppercase

规则类创建好后,接下来定义它的行为。一个规则类中包含两个方法:passesmessagepasses 方法接收属性名和属性值,根据最终属性值的验证结果,返回 truefalsemessage 方法返回验证失败时的错误消息。

<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Uppercase implements Rule
{
    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        return strtoupper($value) === $value;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The :attribute must be uppercase.';
    }
}

当然,错误消息也可以从语言文件里返回,使用 trans 辅助函数:

/**
 * Get the validation error message.
 *
 * @return string
 */
public function message()
{
    return trans('validation.uppercase');
}

规则类定义好后,你就可以像使用其它规则一样,在验证器里使用这个规则了。

use App\Rules\Uppercase;

$request->validate([
    'name' => ['required', new Uppercase],
]);

使用扩展

另一种自定义验证规则的方法是使用 Validator 门面上的 extend 方法。我们需要在服务提供者里注册这个自定义规则:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Validator::extend('foo', function ($attribute, $value, $parameters, $validator) {
            return $value == 'foo';
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

自定义验证器的闭包里接收 4 个参数:验证的属性名、验证的属性值、传递给规则的 $parameters 数组和 Validator 实例对象。

当然,也可以选择给 extend 方法传递一个类和方法的形式代替闭包:

Validator::extend('foo', 'FooValidator@validate');

定义错误消息

你需要为自定义规则定义错误消息,你可以使用内联自定义消息数组或者在语言文件里定义。这个消息应该放在顶层的那个数组里,而不是在 custom 数组里(这里是为规则属性指定错误消息的)。

"foo" => "Your input was invalid!",

"accepted" => "The :attribute must be accepted.",

// The rest of the validation error messages...

在创建一个自定义的验证规则时,你有时可能需要为错误消息自定义占位符。这要使用 Validator 门面的 replacer 方法。你可以在服务提供者的 boot 里写这个。

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Validator::extend(...);

    Validator::replacer('foo', function ($message, $attribute, $rule, $parameters) {
        return str_replace(...);
    });
}

隐式扩展

默认情况下,被验证字段是个空值,使用的 required 规则、 、正常的验证规则,包括自定义扩展,就不再执行了。例如,对于 null 值,unique 规则不会执行。

$rules = ['name' => 'unique'];

$input = ['name' => null];

Validator::make($input, $rules)->passes(); // true

当被验证字段是个空值时,还希望继续执行规则,那就要写明这个规则属性是必需的。创建这「隐式」扩展,需使用 Validator::extendImplicit() 方法:

Validator::extendImplicit('foo', function ($attribute, $value, $parameters, $validator) {
    return $value == 'foo';
});

警告! 一个「隐式」扩展只意味着属性是必需的,实际上是采用无效缺失还是空属性,由你决定。


本文为转载文章: 原文链接