数据验证如何验证

tech2022-09-02  107

数据验证如何验证

Validation is an important aspect of every application’s interaction with data. Instead of reinventing the wheel every time, the community collaborated on some useful packages like Symfony, Laravel, Zend, etc. In this article, we’re going to introduce a lesser known package called Respect Validation, which provides some nice new features. Let’s get started.

验证是每个应用程序与数据交互的重要方面。 社区没有每次都重新发明轮子,而是协作了一些有用的软件包,例如Symfony,Laravel,Zend等。在本文中,我们将介绍一个鲜为人知的软件包,称为Respect Validation ,该软件包提供了一些不错的新功能。 让我们开始吧。

When using a framework, there is a great chance that you have a validation component shipped with it. The Symfony Validator Component provides a set of standard validation rules that you’ll need for your application.

使用框架时,很有可能会附带一个验证组件。 Symfony验证程序组件提供了应用程序所需的一组标准验证规则。

class UserSubscriptionForm { protected $email; public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('email', new \Assert\Email([ 'message' => 'Invalid email.' ])); } }

I’m sure your subscription form contains more than just an email, but let’s keep it simple. Inside your controller you’ll have to trigger the validation like so:

我确定您的订阅表格不仅包含一封电子邮件,而且让我们保持简单。 在控制器内部,您必须像这样触发验证:

public function store(Request $request){ $userSubscriptionForm = UserSubscriptionForm::fromInput($request->all()); $validator = $this->get('validator'); $errors = $validator->validate($userSubscriptionForm); if (count($errors) > 0) { // redirect with errors } // return success }

After creating a new UserSubscriptionForm from the user input, we will trigger the validation and collect the validation errors if we found any.

根据用户输入创建新的UserSubscriptionForm后,我们将触发验证并收集验证错误(如果发现任何错误)。

Laravel also ships with the Illuminate validation package. It does the same job, but in a different way. Let’s use our previous validation example and convert it to Laravel.

Laravel还附带有Illuminate验证包 。 它执行相同的工作,但方式不同。 让我们使用之前的验证示例并将其转换为Laravel。

class UserSubscriptionController extends Controller { public function store(Request $request) { $validator = \Validator::make( [ 'email' => $request->get('email') ], [ 'email' => 'required|email' ] ); if($validator->fails()){ $errors = $validator->messages(); // redirect with errors } // return success } }

The Zend validator package is not much different from the others. For the same previous example, we can do the following:

Zend验证程序包与其他程序没有太大区别。 对于相同的先前示例,我们可以执行以下操作:

class UserSubscriptionController extends Controller { public function store(Request $request) { $validator = new Zend\Validator\EmailAddress(); if(!$validator->isValid($request->get('email'))){ $errors = $validator->getMessages(); // redirect with errors } // return success } }

I’m sure you’re already familiar with at least one of the packages mentioned above. In this article, we are going to introduce Respect/Validation and we will highlight the main differences from the other packages.

我确定您已经至少熟悉上述软件包之一。 在本文中,我们将介绍尊重/验证 ,我们将重点介绍与其他软件包的主要区别。

尊重验证 (Respect Validation)

The Respect validator introduces a simple way of validating your data. Let’s start by completing the same previous example.

尊重验证器介绍了一种验证数据的简单方法。 让我们从完成前面的相同示例开始。

class UserSubscriptionController extends Controller { public function store(Request $request) { $emailValidator = \Respect\Validation\Validator::email(); if (!$emailValidator->validate($email)) { // redirect with errors } // return success } }

So, nothing new! The first thing you’ll notice is that we didn’t retrieve the list of errors after a validation failure. To retrieve the list of errors, we need to use the assert method which throws an exception containing the list of error messages.

所以,没有什么新的! 您会注意到的第一件事是,验证失败后我们没有检索到错误列表。 要检索错误列表,我们需要使用assert方法,该方法将引发包含错误消息列表的异常。

class UserSubscriptionController extends Controller { public function store(Request $request) { $emailValidator = \Respect\Validation\Validator::email(); try{ $emailValidator->assert($request->get('email')); } catch(\Respect\Validation\Exceptions\NestedValidationExceptionInterface $ex){ $errors = $ex->getMainMessage(); // redirect with errors } // return success } }

We also have the ability to add multiple rules to the same value by chaining methods.

我们还可以通过链接方法将多个规则添加到同一值。

Validator::string()->noWhitespace()->length(4, 10); Validator::numeric()->between(5, 10); Validator::date()->between(5, 10);

Another way to validate multiple rules is to use the allOf rule which accepts a list of rules.

验证多个规则的另一种方法是使用allOf规则,该规则接受规则列表。

$inputValidator = \Respect\Validation\Validator::allOf( new String(), new Length(4, 10) );

You probably need to validate some data to match at least one of your business rules. Let’s take the login form as an example where the user can either enter their email address or username. The username must be alpha numeric and between 4 and 16 characters long. You can check the documentation for more details about the list of available rules.

您可能需要验证一些数据,以至少匹配您的业务规则之一。 让我们以登录表单为例,用户可以输入其电子邮件地址或用户名。 用户名必须是字母数字,长度在4到16个字符之间。 您可以查看文档以获取有关可用规则列表的更多详细信息。

$usernameOrEmailValidator = \Respect\Validation\Validator::oneOf( new \Respect\Validation\Rules\Email(), \Respect\Validation\Validator::string()->alnum()->noWhitespace()->length(4, 16) );

One feature that you don’t often see in validation packages is the rule negation functionality. You can specify the rules that you don’t want to match, for example.

验证包中您通常不会看到的一项功能是规则否定功能。 您可以指定的规则,你不想匹配,例如。

$inputValidator = \Respect\Validation\Validator::not(\Respect\Validation\Validator::numeric());

自定义错误消息 (Custom Error Messages)

As mentioned earlier, when an assertion exception is thrown, you can get error messages using one of the following methods.

如前所述,当引发断言异常时,可以使用以下方法之一获取错误消息。

getFullMessage: returns a general error message with a list of the failing rules. Asserting Validator::email()->assert('notAValidEmail') will throw the following message.

getFullMessage :返回常规错误消息,其中包含失败规则的列表。 声明Validator::email()->assert('notAValidEmail')将引发以下消息。

\-These rules must pass for "notAValidEmail" \-"notAValidEmail" must be valid email

getMainMessage: returns a general error message without specifying the failing rules. The email example returns These rules must pass for "notAValidEmail.

getMainMessage :返回常规错误消息,而不指定失败的规则。 电子邮件示例返回These rules must pass for "notAValidEmail 。

findMessages: accepts an array as a parameter containing the list of messages for the failing rules.

findMessages :接受一个数组作为参数,其中包含失败规则的消息列表。

$this->messages = [ 'alpha' => '{{name}} must only contain alphabetic characters.', 'alnum' => '{{name}} must only contain alpha numeric characters and dashes.', 'numeric' => '{{name}} must only contain numeric characters.', 'noWhitespace' => '{{name}} must not contain white spaces.', 'length' => '{{name}} must length between {{minValue}} and {{maxValue}}.', 'email' => 'Please make sure you typed a correct email address.', 'creditCard' => 'Please make sure you typed a valid card number.', 'date' => 'Make sure you typed a valid date for the {{name}} ({{format}}).', 'password_confirmation' => 'Password confirmation doesn\'t match.' ]; // inside the try catch block try { $this->rules[$input]->assert($value); } catch (\Respect\Validation\Exceptions\NestedValidationExceptionInterface $ex) { dump($ex->findMessages($this->messages)); }

This will return a custom message if one the failing rules exists inside our messages array. You can read more about custom messages in the documentation.

如果在我们的消息数组中存在一个失败的规则,这将返回一条自定义消息。 您可以在文档中阅读有关自定义消息的更多信息。

To make things a little more practical, we will be validating a user subscription form. The form contains a set of fields to identify the user, and a small section for the billing info.

为了使事情更实用,我们将验证用户订阅表单。 该表格包含一组用于标识用户的字段,以及一小部分的帐单信息。

用户订阅验证 (User Subscription Validation)

I will be using Laravel for my example, but I think it doesn’t matter in this case since we don’t use any Laravel magic. You can start by adding the package using composer: composer require respect/validation. The user subscription form will look like this:

我将使用Laravel作为示例,但是在这种情况下,我认为这并不重要,因为我们不使用任何Laravel魔术。 您可以从使用composer添加软件包开始: composer require respect/validation 。 用户订阅表单将如下所示:

// resources/views/home.blade.php <form action="/send" method="POST"> <legend>Profile</legend> <input class="form-control" name="username" type="text" autofocus="" value="{{\Input::old('username')}}"> <input class="form-control" name="email" type="email" value="{{\Input::old('email')}}"> <input class="form-control" name="password" type="password" value=""> <input class="form-control" name="password_confirmation" type="password" > <legend>Billing</legend> <input class='form-control' size='4' type='text' name="cardHolderName" value="{{\Input::old('cardHolderName')}}"> <input class='form-control' size='20' type='text' name="cardNumber" value="{{\Input::old('cardNumber')}}"> <input class='form-control' size='20' type='text' name="billingAddress" value="{{\Input::old('billingAddress')}}"> <input class='form-control' size='4' type='text' name="cvc" value="{{\Input::old('cvc')}}"> <input class='form-control' size='2' type='text' name="expirationMonth" value="{{\Input::old('expirationMonth')}}"> <input class='form-control' size='4' type='text' name="expirationYear" value="{{\Input::old('expirationYear')}}"> <button class="btn btn-primary">Join</button> </form> // app/Http/routes.php Route::get('/', 'UserSubscriptionController@index'); Route::post('/send', 'UserSubscriptionController@send');

Our UserSubscriptionController class will have two methods. One for printing the form and another for processing the form submission. We will create another separate class to process the form validation.

我们的UserSubscriptionController类将具有两个方法。 一个用于打印表单,另一个用于处理表单提交。 我们将创建另一个单独的类来处理表单验证。

// app/Http/Controllers/UserSubscriptionController class UserSubscriptionController extends Controller { protected $userSubscription; public function __construct(UserSubscriptionValidator $userSubscription) { $this->userSubscription = $userSubscription; } public function index() { return view('home'); } public function send(Request $request, Redirector $redirector) { $inputs = $request->all(); $isValid = $this->userSubscription->assert($inputs); if (!$isValid) { return $redirector->back()->withInput()->with('errors', $this->userSubscription->errors()); } return "Everything is Good!"; } }

The App\Validation\UserSubscriptionValidator class will be exposed through two methods (assert and errors).

App\Validation\UserSubscriptionValidator类将通过两种方法( assert和errors )公开。

// app/Validation/UserSubscriptionValidator.php use \Respect\Validation\Validator as V; class UserSubscriptionValidator { /** * List of constraints * * @var array */ protected $rules = []; /** * List of customized messages * * @var array */ protected $messages = []; /** * List of returned errors in case of a failing assertion * * @var array */ protected $errors = []; /** * Just another constructor * * @return void */ public function __construct() { $this->initRules(); $this->initMessages(); } /** * Set the user subscription constraints * * @return void */ public function initRules() { $dateFormat = 'd-m-Y'; $now = (new \DateTime())->format($dateFormat); $tenYears = (new \DateTime('+10 years'))->format($dateFormat); $this->rules['username'] = V::alnum('_')->noWhitespace()->length(4, 20)->setName('Username'); $this->rules['password'] = V::alnum()->noWhitespace()->length(4, 20)->setName('password'); $this->rules['email'] = V::email(); $this->rules['cardHolderName'] = V::alpha()->setName('Card holder name'); $this->rules['cardNumber'] = V::creditCard()->setName('card number'); $this->rules['billingAddress'] = V::string()->length(6)->setName('billing address'); $this->rules['cvc'] = V::numeric()->length(3, 4)->setName('CVC'); $this->rules['expirationDate'] = V::date($dateFormat)->between($now, $tenYears)->setName('expiration date'); } }

Our constructor calls the initRules method which sets the validation constraints. The setName method value is injected into the error messages template. The initMessages method sets the list of customized messages; this can be moved outside the class if you’re going to use them again for another form.

我们的构造函数调用initRules方法,该方法设置验证约束。 将setName方法的值注入到错误消息模板中。 initMessages方法设置自定义消息的列表; 如果您要再次将它们用于另一种形式,则可以将其移到班级之外。

// app/Validation/UserSubscriptionValidator.php /** * Set user custom error messages * * @return void */ public function initMessages() { $this->messages = [ 'alpha' => '{{name}} must only contain alphabetic characters.', 'alnum' => '{{name}} must only contain alpha numeric characters and dashes.', 'numeric' => '{{name}} must only contain numeric characters.', 'noWhitespace' => '{{name}} must not contain white spaces.', 'length' => '{{name}} must length between {{minValue}} and {{maxValue}}.', 'email' => 'Please make sure you typed a correct email address.', 'creditCard' => 'Please make sure you typed a valid card number.', 'date' => 'Make sure you typed a valid date for the {{name}} ({{format}}).', 'password_confirmation' => 'Password confirmation doesn\'t match.' ]; }

The {{name}} tag will be updated with the corresponding name passed previously using the setName method. Some rules contain more variables, like {{minValue}} and {{maxValue}} for the length rule. Same thing for the date rule. The next step is to define our assert method to perform the actual validation.

{{name}}标签将使用之前使用setName方法传递的相应名称进行更新。 一些规则包含更多变量,例如length规则的{{minValue}}和{{maxValue}} 。 date规则也一样。 下一步是定义我们的assert方法以执行实际验证。

/** * Assert validation rules. * * @param array $inputs * The inputs to validate. * @return boolean * True on success; otherwise, false. */ public function assert(array $inputs) { $expirationMonth = array_get($inputs, 'expirationMonth'); $expirationYear = array_get($inputs, 'expirationYear'); $inputs['expirationDate'] = '01-' . $expirationMonth . '-' . $expirationYear; foreach ($this->rules as $rule => $validator) { try { $validator->assert(array_get($inputs, $rule)); } catch (\Respect\Validation\Exceptions\NestedValidationExceptionInterface $ex) { $this->errors = $ex->findMessages($this->messages); return false; } } $passwordConfirmed = $this->assertPasswordConfirmation($inputs); return $passwordConfirmed; }

The first step is to create a valid date from the expiration month and year. This will help us to easily validate it against actual date values. We loop through the list of validation rules and test if the user input matches the defined rule. If an assertion fails, we set the errors message attribute and return false to the controller.

第一步是从到期月份和年份创建一个有效日期。 这将帮助我们轻松地根据实际日期值对其进行验证。 我们遍历验证规则列表,并测试用户输入是否与定义的规则匹配。 如果断言失败,则设置错误消息属性,并将false返回给控制器。

Currently, the package doesn’t provide a rule to automaticaly validate password confirmation. The assertPasswordConfirmation method will only test if the passed values are equal and set the error message in case of failure.

当前,该程序包不提供自动验证密码确认的规则。 assertPasswordConfirmation方法将仅测试传递的值是否相等,并在失败的情况下设置错误消息。

public function assertPasswordConfirmation(array $inputs) { $passwordConfirmation = array_get($inputs, 'password_confirmation'); if ($inputs['password'] !== $passwordConfirmation) { $this->errors['password_confirmation'] = $this->messages['password_confirmation']; return false; } else { return true; } }

The last part is to return the errors to the user if it fails, and we also need to update our home template to print errors in case of failure.

最后一部分是将错误返回给用户,如果失败,我们还需要更新home模板以打印错误。

public function errors() { return $this->errors; } // home.blade.php @if(\Session::has('errors')) <div class="alert alert-danger"> @foreach(\Session::get('errors') as $error) @if(!empty($error)) <p>{{$error}}</p> @endif @endforeach </div> @endif

创建自己的规则 (Creating Your Own Rules)

You can create your own business rules and use the with method to add your namespace to the lookup array. You can check the documentation for more details about creating your own constraints.

您可以创建自己的业务规则,并使用with方法将名称空间添加到查找数组。 您可以查看文档以获取有关创建自己的约束的更多详细信息。

Respect\Validation\Validator::with('App\\Validation\\User\\Rules\\');

If you found that the rules you’re trying to use exist in a Zend or Symfony validation package, you can directly use them using one of the following methods.

如果您发现要使用的规则存在于Zend或Symfony验证包中,则可以使用以下方法之一直接使用它们。

Respect\Validation\Validator::sf('Language')->validate('Arabic'); Respect\Validation\Validator::zend('EmailAddress')->validate('me@gmail.com');

结论 (Conclusion)

This article briefly introduced the Respect validation package. We saw how simple the API is and how it integrates with other validators like Symfony and Zend. It’s also easy to extend and add new rules to the validation process. If you’ve never used it before, I really encourage you to give it a try. If you’ve already used it in some of your projects, I would really love to know what you think about it and how it fits your use case in the long term – let us know in the comments below!

本文简要介绍了Respect验证程序包。 我们看到了API的简单性,以及它如何与Symfony和Zend等其他验证器集成。 扩展和向验证过程添加新规则也很容易。 如果您以前从未使用过它,我强烈建议您尝试一下。 如果您已经在某些项目中使用过它,那么我真的很想知道您对此有何想法以及从长远来看它如何适合您的用例–在下面的评论中告诉我们!

翻译自: https://www.sitepoint.com/validating-your-data-with-respect-validation/

数据验证如何验证

相关资源:RespectValidate有史以来最了不起的PHP验证引擎
最新回复(0)