【laravel7.x中文文档】表单验证


【laravel7.x中文文档】表单验证

表单验证

[TOC]

简介

Laravel 提供了几种不同的方法来验证传入应用程序的数据。默认情况下,Laravel 的控制器基类使用 ValidatesRequests trait,它提供了一种方便的方法去使用各种强大的验证规则来验证传入的 HTTP 请求。

快速验证

要了解 Laravel 强大的验证功能,让我们看一个验证表单并将错误消息显示回给用户的完整示例。

定义路由

首先,让我们假设在 routes/web.php 文件中定义了下面这些路由:

Route::get('post/create', 'PostController@create');

Route::post('post', 'PostController@store');

GET 路由会显示一个供用户创建一个新的博客帖子的表单,而 POST 路由会将新的博客文章存储在数据库中。

创建控制器

下面让我们一起来看看处理这些路由的控制器 store 方法暂时留空:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class PostController extends Controller
{
    /**
     * 显示创建博客文章的表单.
     *
     * @return Response
     */
    public function create()
    {
        return view('post.create');
    }

    /**
     * 保存一篇新的博客文章
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // 验证并存储博客文章...
    }
}

编写验证器逻辑

现在我们开始在 store 方法中编写逻辑来验证新的博客文章。为此,我们将使用 Illuminate\Http\Request 对象提供的 validate 方法 。如果验证通过,代码就可以正常的运行。如果验证失败,则会抛出异常,并自动将对应的错误响应返回给用户。在典型的 HTTP 请求的情况下,会生成一个重定向响应,而对于 AJAX 请求则会发送 JSON 响应。

让我们接着回到 store 方法来深入理解 validate 方法:

/**
 * 保存一篇新的博客文章
 *
 * @param  Request  $request
 * @return Response
 */
public function store(Request $request)
{
    $validatedData = $request->validate([
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ]);

    // 博客文章验证通过...
}

如你所见,我们将所需的验证规则传递至 validate 方法中。另外再提醒一次,如果验证失败,会自动生成一个对应的响应。如果验证通过,那我们的控制器将会继续正常运行。

或者,验证规则可以指定为一个数组而不是单个 | 分隔字符串:

$validatedData = $request->validate([
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

您可以使用 validateWithBag 方法来验证请求,并将任何错误消息存储在一个命名错误包中:

$validatedData = $request->validateWithBag('post', [
    'title' => ['required', 'unique:posts', 'max:255'],
    'body' => ['required'],
]);

首次验证失败后停止运行

如果你希望在某个属性第一次验证失败后停止运行验证规则,你需要附加 bail 规则到该属性:

$request->validate([
    'title' => 'bail|required|unique:posts|max:255',
    'body' => 'required',
]);

在这个例子中,如果 title 字段没有通过 unique 规则,那么程序就不会继续检查 max 规则。规则会按照分配的顺序来验证。

关于数组数据的注意实现

如果你的 HTTP 请求包含一个 「嵌套」 参数(即数组),那你可以在验证规则中通过 「点」 语法来指定这些参数:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'author.name' => 'required',
    'author.description' => 'required',
]);

显示验证错误信息

如果传入的请求参数未通过给定的验证规则呢?正如前面所提到的,Laravel 会自动把用户重定向到之前的位置。另外,所有的验证错误信息会被自动 存储到 session。

重申一次,我们不必在 GET 路由中将错误消息显式绑定到视图。因为 Lavarel 会检查在 Session 数据中的错误信息,并自动将其绑定到视图(如果这个视图文件存在)。而其中的变量 $errorsIlluminate\Support\MessageBag 的一个实例。要获取关于这个对象的更多信息,请查阅这个文档。

提示:$errors 变量被 web 中间件组提供的 Illuminate\View\Middleware\ShareErrorsFromSession 中间件绑定到视图中。 当这个中间件被应用后,在你的视图中就可以获取到 $errors 变量 , 可以使一直假定 $errors 变量存在并且可以安全地使用。

因此,在我们的例子中,当验证失败的时候,用户将会被重定向到控制器的 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 -->

@error 指令

你还可以使用 @error Blade 模板 指令快速检查给定属性是否存在验证错误消息。 在 @error 指令中,你可以输出 $message 变量以显示错误消息:

<!-- /resources/views/post/create.blade.php -->

<label for="title">Post Title</label>

<input id="title" type="text" class="@error('title') is-invalid @enderror">

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

关于可选字段的注意事项

默认情况下,在 Laravel 应用的全局中间件堆栈 App\Http\Kernel 类中包含了 TrimStringsConvertEmptyStringsToNull 中间件。因此,如果你不希望验证程序将 null 值视为无效的话,那就需要将「可选」的请求字段标记为 nullable,举个例子:

$request->validate([
    'title' => 'required|unique:posts|max:255',
    'body' => 'required',
    'publish_at' => 'nullable|date',
]);

在这个例子里,我们指定 publish_at 字段可以为 null 或者一个有效的日期格式。如果 nullable 的修饰词没有被添加到规则定义中,验证器会认为 null 是一个无效的日期格式。

AJAX 请求与验证

在这个例子中,我们使用传统的表单将数据发送到应用程序。但实际情况中,很多程序都会使用 AJAX 来发送请求。当我们对 AJAX 的请求中使用 validate 方法时,Laravel 并不会生成一个重定向响应,而是会生成一个包含所有验证错误信息的 JSON 响应。这个 JSON 响应会包含一个 HTTP 状态码 422 被发送出去。

验证表单请求

创建表单请求验证

面对更复杂的验证情境中,你可以创建一个「表单请求」来处理更为复杂的逻辑。表单请求是包含验证逻辑的自定义请求类。可使用 Artisan 命令 :request 来创建表单请求类:

php artisan make:request StoreBlogPost

新生成的类保存在 app/Http/Requests 目录下。如果这个目录不存在,运行 make:request 命令时它会被创建出来。让我们添加一些验证规则到 rules 方法中:

/**
 * 获取应用于请求的验证规则
 *
 * @return array
 */
public function rules()
{
    return [
        'title' => 'required|unique:posts|max:255',
        'body' => 'required',
    ];
}

Tip:你可以向 rules 方法传入所需的任何依赖项。他们会自动被 Laravel 提供的 服务容器 自动解析。

所以,验证规则是如何运行的呢?你所需要做的就是在控制器方法中类型提示传入的请求。在调用控制器方法之前验证传入的表单请求,这意味着你不需要在控制器中写任何验证逻辑:

/**
 * 存储传入的博客文章.
 *
 * @param  StoreBlogPost  $request
 * @return Response
 */
public function store(StoreBlogPost $request)
{
    // 传入的请求通过验证...

    // 获取通过验证的数据...
    $validated = $request->validated();
}

如果验证失败,就会生成一个让用户返回到先前的位置的重定向响应。这些错误也会被闪存到 session 中,以便这些错误都可以在页面中显示出来。如果传入的请求是 AJAX,会向用户返回具有 422 状态代码和验证错误信息的 JSON 数据的 HTTP 响应。

添加表单请求后钩子

如果你想在表单请求「之后」添加钩子,可以使用 withValidator 方法。这个方法接收一个完整的验证构造器,允许你在验证结果返回之前调用任何方法:

/**
 * 配置验证实例
 *
 * @param  \Illuminate\Validation\Validator  $validator
 * @return void
 */
public function withValidator($validator)
{
    $validator->after(function ($validator) {
        if ($this->somethingElseIsInvalid()) {
            $validator->errors()->add('field', 'Something is wrong with this field!');
        }
    });
}

表单请求授权验证

表单请求类内也包含了 authorize 方法。在这个方法中,你可以检查经过身份验证的用户确定其是否具有更新给定资源的权限。比方说,你可以判断用户是否拥有更新文章评论的权限:

/**
 * 判断用户是否有请求权限
 *
 * @return bool
 */
public function authorize()
{
    $comment = Comment::find($this->route('comment'));

    return $comment && $this->user()->can('update', $comment);
}

由于所有的表单请求都是继承了 Laravel 中的请求基类,所以我们可以使用 user 方法去获取当前认证登录的用户。同时请注意上述例子中对 route 方法的调用。这个方法允许你在被调用的路由上获取其定义的 URI 参数,譬如下面例子中的 {comment} 参数:

Route::post('comment/{comment}');

如果 authorize 方法返回 false,则会自动返回一个包含 403 状态码的 HTTP 响应,也不会运行控制器的方法。

如果你打算在应用程序的其它部分处理授权逻辑,只需从 authorize 方法返回 true

/**
 * 判断用户是否有请求权限
 *
 * @return bool
 */
public function authorize()
{
    return true;
}

Tip:你可以向 authorize 方法传入所需的任何依赖项。他们会自动被 Laravel 提供的 服务容器 自动解析。

自定义错误消息

你可以通过重写表单请求的 messages 方法来自定义错误消息。此方法应返回属性 / 规则对及其对应错误消息的数组:.

/**
 * 获取已定义验证规则的错误消息
 *
 * @return array
 */
public function messages()
{
    return [
        'title.required' => 'A title is required',
        'body.required'  => 'A message is required',
    ];
}

自定义验证属性

如果你希望将验证消息的 :attribute 部分替换为自定义属性名称,则可以重写 attributes 方法来指定自定义名称。此方法应返回属性 / 名称对的数组:

/**
 * 获取验证错误的自定义属性
 *
 * @return array
 */
public function attributes()
{
    return [
        'email' => 'email address',
    ];
}

准备验证输入

如果需要在应用验证规则之前清除请求中的任何数据,可以使用 prepareForValidation 方法:

use Illuminate\Support\Str;

/**
 * 准备验证数据
 *
 * @return void
 */
protected function prepareForValidation()
{
    $this->merge([
        'slug' => Str::slug($this->slug),
    ]);
}

手动创建验证器

如果你不想在请求上使用 validate 方法,你可以通过 Validator facade 手动创建一个验证器实例。用 Validator facade 上的 make 方法创建一个验证器实例:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class PostController extends Controller
{
    /**
     * 保存一篇新的博客文章
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);

        if ($validator->fails()) {
            return redirect('post/create')
                        ->withErrors($validator)
                        ->withInput();
        }

        // Store the blog post...
    }
}

传给 make 方法的第一个参数是需要验证的数据。第二个参数则是该数据的验证规则。

如果验证失败,则可以使用 withErrors 方法把错误消息闪存到 Session 。使用这个方法进行重定向后, $errors 变量会自动和视图共享,你可以把这些消息显示给用户。withErrors 方法接收验证器、MessageBag 或 PHP Array

自动重定向

如果你想手动创建验证器实例,又想使用 validates 方法提供的自动重定向,那么你可以在现有的验证器示例上调用 validate 方法。如果验证失败,用户将会自动重定向。在 AJAX 请求中,则会返回 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');

命名错误包

如果你一个页面中有多个表单,你可以通过命名包来检索特定表单的错误消息。只需给 withErrors 方法传递一个名字作为第二个参数:

return redirect('register')
            ->withErrors($validator, 'login');

然后你就可以从 $errors 变量中获取指定表单的错误消息:

{{ $errors->login->first('email') }}

验证后钩子

验证器还允许附加回调并在验证完成后执行,以便你进行下一步的验证,甚至在消息集合中添加更多的错误消息。使用它只需在验证实例上使用 after 方法:

$validator = Validator::make(...);

$validator->after(function ($validator) {
    if ($this->somethingElseIsInvalid()) {
        $validator->errors()->add('field', 'Something is wrong with this field!');
    }
});

if ($validator->fails()) {
    //
}

处理错误消息

通过 Validator 实例调用 errors 方法,会返回 Illuminate\Support\MessageBag 实例,它拥有各种方便的方法处理错误信息。自动提供给所有视图的 $errors 变量,也是 MessageBag 类的一个实例。

查看特定字段的第一个错误信息

要查看特定字段的第一个错误消息,可以使用 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')) {
    //
}

自定义错误消息

如果有需要,你也可以使用自定义错误信息代替默认值进行验证。有几种方法可以指定自定义信息。首先,你可以将自定义信息作为第三个参数传递给 Validator::make 方法:

$messages = [
    'required' => 'The :attribute field is required.',
];

$validator = Validator::make($input, $rules, $messages);

在这个例子中, :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 e-mail address!',
];

在 PHP 文件中指定自定义信息

在大多数情况下,您可能会在文件中指定自定义信息,而不是直接将它们传递给 Validator 。为此,需要把你的信息放置于 resources/lang/xx/validation.php 语言文件内的 custom 数组中。

'custom' => [
    'email' => [
        'required' => 'We need to know your e-mail address!',
    ],
],

在 PHP 文件中指定自定义属性

如果你希望将验证信息的 :attribute 部分替换为自定义属性名称,你可以在 resources/lang/xx/validation.php 语言文件的 attributes 数组中指定自定义名称:

'attributes' => [
    'email' => 'email address',
],

在 PHP 文件中指定自定义值

有时您可能需要将验证信息的 :value 替换为自定义的表示形式。例如,指定 payment_type 的值为 cc

$request->validate([
    'credit_card_number' => 'required_if:payment_type,cc'
]);

如果此验证规则失败,将生成以下错误信息:

The credit card number field is required when payment type is cc.

您可以通过在 validation 语言文件中定义 values 数组指定自定义值表示形式,而不是将 cc 显示为 payment_type 的值:

'values' => [
    'payment_type' => [
        'cc' => 'credit card'
    ],
],

如果验证失败,将生成以下信息:

The credit card number field is required when payment type is credit card.

可用验证规则

以下是所有可用验证规则及其功能的列表:

Accepted
Active URL
After (Date)
After Or Equal (Date)
Alpha
Alpha Dash
Alpha Numeric
Array
Bail
Before (Date)
Before Or Equal (Date)
Between
Boolean
Confirmed
Date
Date Equals
Date Format
Different
Digits
Digits Between
Dimensions (Image Files)
Distinct
E-Mail
Ends With
Exclude If
Exclude Unless
Exists (Database)
File
Filled
Greater Than
Greater Than Or Equal
Image (File)
In
In Array
Integer
IP Address
JSON
Less Than
Less Than Or Equal
Max
MIME Types
MIME Type By File Extension
Min
Not In
Not Regex
Nullable
Numeric
Password
Present
Regular Expression
Required
Required If
Required Unless
Required With
Required With All
Required Without
Required Without All
Same
Size
Sometimes
Starts With
String
Timezone
Unique (Database)
URL
UUID

accepted

验证字段必须是 yes, on, 1,或 true。这在确认「服务条款」是否同意时相当有用。

active_url

根据 PHP 函数 dns_get_record ,验证字段必须具有有效的 A 或 AAAA 记录。 所提供的URL的主机名是使用 parse_url 的 PHP 函数在传递到 dns_get_record 之前提取的。

after:date

验证字段必须是给定日期之后的值。日期值将传递到 PHP 函数 strtotime

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

您可以指定另一个要与日期进行比较的字段,而不是传递要由 strtotime 处理的日期字符串:

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

after_or_equal:date

验证字段必须是在给定日期之后或与此日期相同的值。更多信息,请参阅 after。

alpha

验证字段必须完全由字母构成。

alpha_dash

验证字段可能包含字母、数字,以及破折号 (-) 和下划线 ( _ )。

alpha_num

验证字段必须是完全是字母、数字。

array

验证的字段必须是一个 PHP 数组。

bail

在第一次验证失败后停止运行验证规则。

before:date

正在验证的字段必须是给定日期之前的值。这个日期将传递到 PHP 的 strtotime 函数中。此外,与 after 规则一样,另一个正在验证的字段可以作为 date 的值。

before_or_equal:date

验证字段必须是在给定日期之前或与之相同的日期。这个日期值将会被传递给 PHP 的 strtotime 函数来计算。

between:min,max

验证字段的大小必须在给定的 min 和 max 之间。字符串、数字、数组和文件的计算方式都使用 size 方法。

boolean

验证的字段必须可以转换为 Boolean 类型。 可接受的输入为 truefalse10"1""0"

confirmed

验证字段必须具有匹配字段 foo_confirmation 。例如,验证字段为 password ,输入中必须存在与之匹配的 password_confirmation 字段。

date

根据 PHP strtotime 函数,验证的字段必须是有效的日期。

dateequals:_date

验证字段必须等于给定日期。日期将传递到 PHP strtotime 函数。

dateformat:_format

验证字段必须匹配给定的日期格式。当验证某个字段的时候,你应该 只使用 date 或者 date_format ,而不是同时使用。此验证规则支持 PHP 所有的 DateTime 类。

different:field

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

digits:value

验证的字段必须为 numeric ,并且必须具有确切长度 value。

digitsbetween:_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 这样的 float 来指定:

'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

验证的字段必须符合 e-mail 地址格式。当前版本,此种验证规则由 egulias/email-validator 提供支持。默认使用 RFCValidation 验证样式,但你也可以使其他验证样式:

'email' => 'email:rfc,dns'

例子使用 RFCValidationDNSCheckValidation 验证样式。所有可用验证样式列表:

<div class="content-list" markdown="1">
- rfc: RFCValidation
- strict: NoRFCWarningsValidation
- dns: DNSCheckValidation
- spoof: SpoofCheckValidation
- filter: FilterEmailValidation
</div>

当下版本 filter 验证规则使用 PHP 的 filter_var 方法进行验证,在 5.8 版本接入 Laravel 。 dnsspoof 验证器需要 PHP 的 intl 扩展。

endswith:_foo,bar,…

验证的字段必须以给定的值之一结尾。

excludeif:_anotherfield,value

如果anotherfield字段等于value,验证下的字段将被 validatevalidated 方法返回的请求数据排除。

excludeunless:_anotherfield,value

验证下的字段将被 validatevalidated 方法返回的请求数据排除,除非 anotherfield 的字段等于 value

exists:table,column

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

Exists 规则的基本用法

'state' => 'exists:states'

如果未指定 column 选项,则将使用字段名称。

指定列名

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

如果你需要指定 exists 方法用来查询的数据库。你可以通过使用「点」语法将数据库的名称添加到数据表前面来实现这个目的:

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

你也可以使用关联模型来指定表名。

'user_id' => 'exists:App\User,id'

如果要自定义验证规则执行的查询,可以使用 Rule 类来定义规则。在这个例子中,我们使用数组指定验证规则,而不是使用 | 字符来分隔它们:

use Illuminate\Validation\Rule;

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

file

验证的字段必须是成功上传的文件。

filled

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

gt:field

验证字段必须大于给定的 field。两个字段必须是相同的类型。字符串、数字、数组和文件都使用 size 进行相同的评估。

gte:field

验证字段必须大于或等于给定的 field 。两个字段必须是相同的类型。字符串、数字、数组和文件都使用 size 进行相同的评估。

image

验证的文件必须是图片 (jpeg, png, bmp, gif, svg, or webp)

in:foo,bar,…

验证字段必须包含在给定的值列表中。由于此规则通常要求您 implode 数组,因此可以使用 Rule :: in 方法流畅地构造规则:

use Illuminate\Validation\Rule;

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

inarray:_anotherfield.*

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

integer

0

【【laravel7.x中文文档】表单验证隶属于分类: php laravel

它起初由本站用户:刘欣Eden于3年前 创建。

它被收录于如下合集: Laravel7中文文档

该内容的链接是:

目录