24.09.2024
Home / Linux Overview / Validated, validated... and validated! Comparing data validators in PHP. Validation and data cleaning using PHP Insane validation php

Validated, validated... and validated! Comparing data validators in PHP. Validation and data cleaning using PHP Insane validation php

It is very essential to have the input to your form validated before taking the form submission data for further processing. When there are many fields in the form, the PHP validation script becomes too complex. Moreover, since you are doing the same or similar validation for most of the forms that you make, just too much of duplicate effort is spent on form validations.

About this generic PHP form validation script

This generic PHP form validator script makes it very easy to add validations to your form.

We create and associate a set of “validation descriptors” with each element in the form. The “validation descriptor” is a string specifying the type of validation to be performed. For example, “req” means required, “alpha” means allow only alphabetic characters and so on.

Each field in the form can have zero, one or more validations. For example, the input should not be empty, should be less than 25 chars, should be alpha-numeric, etc

You can associate a set of validation descriptors for each input field in the form.

Download the PHP form validation script

You can download the PHP form validation script below:
The zip file contains the form validation script formvalidator.php, documentation and usage samples.

Using the PHP form validation script
  • Include formvalidator.php in your form processing script
  • require_once "formvalidator.php"
  • Create a FormValidator object and add the form validation descriptors.
  • $validator = new FormValidator(); $validator->addValidation("Name","req","Please fill in Name"); $validator->addValidation("Email","email", "The input for Email should be a valid email value"); $validator->addValidation("Email","req","Please fill in Email");

    The first argument is the name of the input field in the form. The second argument is the validation descriptor that tells the type of the validation required. The third argument is the error message to be displayed if the validation fails.

  • Validate the form by calling ValidateForm() function
  • if(!$validator->ValidateForm()) ( echo "Validation Errors:"; $error_hash = $validator->GetErrors(); foreach($error_hash as $inpname => $inp_err) ( echo "

    $inpname: $inp_err

    \n"; ) ) Example

    The example below will make the idea clearer

    Name: Email:

    Adding Custom Validation

    If you want to add a custom validation, which is not provided by the validation descriptors, you can do so. Here are the steps:

  • Create a class for the custom validation and override the DoValidate() function
  • class MyValidator extends CustomValidator ( function DoValidate(&$formars,&$error_hash) ( if(stristr($formars["Comments"],"http://")) ( $error_hash["Comments"]="No URLs allowed in comments"; return false; ) return true; ) )

  • Add the custom validation object
  • $validator = new FormValidator(); $validator->addValidation("Name","req","Please fill in Name"); $validator->addValidation("Email","email", "The input for Email should be a valid email value"); $validator->addValidation("Email","req","Please fill in Email"); $custom_validator = new MyValidator(); $validator->AddCustomValidator($custom_validator);

    The custom validation function will be called automatically after other validations.

    Table of Validation Descriptors

    Here is the list of all validation descriptors:

    Validation DescriptorUsage
    reqThe field should not be empty
    maxlen=???checks the length entered data to the maximum. For example, if the maximum size permitted is 25, give the validation descriptor as “maxlen=25”
    minlen=???checks the length of the entered string to the required minimum. example “minlen=5”
    alnumCheck the data if it contains any other characters other than alphabetic or numeric characters
    alnum_sAllows only alphabetic, numeric and space characters
    numCheck numeric data
    alphaCheck alphabetic data.
    alpha_sCheck alphabetic data and allow spaces.
    emailThe field is an email field and verify the validity of the data.
    lt=???
    lessthan=???
    Verify the data to be less than the value passed. Valid only for numeric fields.
    example: if the value should be less than 1000 give validation description as “lt=1000”
    gt=???
    greaterthan=???
    Verify the data to be greater than the value passed. Valid only for numeric fields.
    example: if the value should be greater than 10 give validation description as “gt=10”
    regexp=???Check with a regular expression the value should match the regular expression.
    example: “regexp=^(1.20)$” allow up to 20 alphabetic characters.
    dontselect=??This validation descriptor is for select input items (lists) Normally, the select list boxes will have one item saying ‘Select One’. The user should select an option other than this option. If the value of this option is ‘Select One’, the validation description should be “dontselect=Select One”
    dontselectchkThis validation descriptor is for check boxes. The user should not select the check given box. Provide the value of the check box instead of ??
    For example, dontselectchk=on
    shouldselchkThis validation descriptor is for check boxes. The user should select the given check box. Provide the value of the check box instead of ??
    For example, shouldselchk=on
    dontselectradioThis validation descriptor is for radio buttons. The user should not select the given radio button. Provide the value of the radio button instead of ??
    For example, dontselectradio=NO
    selectradioThis validation descriptor is for radio buttons. The user should select the given radio button. Provide the value of the radio button instead of ??
    For example, selectradio=yes
    selmin=??Select atleast n number of check boxes from a check box group.
    For example: selmin=3
    seloneMakes a radio group mandatory. The user should select atleast one item from the radio group.
    eqelmnt=???compare two elements in the form and make sure the values ​​are the same For example, ‘password’ and ‘confirm password’. Replace the ??? with the name of the other input element.
    For example: eqelmnt=confirm_pwd

    In a previous article I promised to write a comparison of my own library with other available solutions, so today we will look at validation using Aura.Filter, Respect Validation, Sirius Validation and Valitron.


    Let's imagine that we have a certain public service in development that involves registering users for full access to all functions. Thus, the registration form will contain the following fields:

  • name. Must contain exactly two words, where the first is the user's first name and the second is the last name.
  • login. If a value is passed, it must contain only Latin letters, hyphens and underscores.
  • email. Must contain a valid address email.
  • password. Must be set and be no more than 64 characters long.
  • agreed. A typical checkbox that a user must check to confirm their acceptance of the terms of service.
  • So, we have five fields that the user must fill out in order to register with our imaginary service. Let's imagine that we received completely invalid data as input:


    $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail "password" => Aura.Filter

    Validation using Aura.Filter starts with a filter factory. We need to create a so-called “subject filter”, since we will be validating an array, not an individual value.

    We define the rules use Aura\Filter\FilterFactory; $filter = (new FilterFactory)->newSubjectFilter(); $filter->validate("name") ->isNotBlank() ->is("two_words") ->setMessage("The name must be two words."); $filter->validate("login") ->isBlankOr("alnum") ->setMessage("If you specify a login, it must contain only Latin characters."); $filter->validate("email") ->isNotBlank() ->is("email") ->setMessage("Please enter a valid email address."); $filter->validate("password") ->isNotBlank() ->is("strlenMax", 64) ->setMessage("Please write your password."); $filter->validate("agreed") ->is("callback", function($subject, $field) ( return $subject->($field) === true; ))->setMessage("You need agree to the terms of service.");

    As you can see, the description of the rules is quite simple. Aura.Filter provides a whole set of useful rules out of the box and some of them were used in the example above:

  • isNotBlank method. Specifies that the field cannot have a null value.
  • alnum. This rule only allows Latin letters.
  • email. And it’s so clear :)
  • strlenMax. Specifies that the field cannot exceed the length specified by the second argument of the is method.
  • callback. This type of rule is similar to closures from Kontrolio. It allows you to define a rule in the form of a closure. Aura.Filter passes the “subject”, our array of data from the form, and the field to this closure. in this case agreed.
  • You probably noticed that I didn't specify the two_words rule. Naturally, there is no such rule in Aura.Filter, so we need to create one. As the documentation says, this is done using a separate class for the rule:


    /** * Rule that validates the username. * The username consists of two words: first and last name, separated by one space. */ class UserNameRule ( /** * Validates the user name. * * @param object|array $subject * @param string $field * @param int $max * * @return bool */ public function __invoke($subject, $field , $max = null) ( $value = $subject->($field); if (! is_scalar($value)) ( return false; ) return (bool) preg_match("/^+\s+$/u", $value);

    The second step is to let the filter factory know about our new rule. It’s done by passing the first argument as an array of rules to the filter factory:


    The next step is to notify Aura.Filter that we have created a new rule and want to use it. This is done by passing an array of rules to the first argument of the factory:


    use Aura\Filter\FilterFactory; $rules = [ "two_words" => function() ( return new UserNameRule; ) ]; $filter = (new FilterFactory($rules))->newSubjectFilter();

    Now our two_words rule can be used in the same way as any other standard rule.

    Feedback

    As you remember, the incoming data that we validate is completely invalid, because each field contains an incorrect value or does not contain it at all. Therefore, it is assumed that as a result of validation we will receive errors and corresponding messages about them.


    We validate with Aura.Filter as follows:


    $valid = $filter->apply($data); if (! $valid) ( $failures = $filter->getFailures(); $messages = $failures->getMessages(); )

    IN $messages an array is being written, so to display messages we need two nested foreach:


    Respect Validation

    The second library I used in the comparison is a relatively popular solution called Respect Validation. Since people trust her, I think there is something to see there.


    For the purity of the experiment, when comparing libraries, we will use the same data set defined at the beginning:


    use Respect\Validation\Validator as v; $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail here "password" => "" // The password is not specified at all // "agreed" is not in the array because the user did not check the box ]; Defining the rules

    As with Aura.Filter, we need our own validation rule for the username, so let's start there:


    namespace MyNamespace; use Respect\Validation\Rules\AbstractRule; class UserNameRule extends AbstractRule ( public function validate($input) ( return (bool) preg_match("/^+\s+$/u", $input); ) )

    The external rules API is almost identical to Aura.Filter, only the validate() method is used instead of the __invoke() magic. It seemed to me, this API, simpler and more understandable. Well, it’s closer to Kontrolio :)


    I did not find any mention of this in the documentation, however, in addition to the rule itself, you need to create your own exception type for it. The name of the exception class must consist of the name of the rule class and a postfix Exception.


    use Respect\Validation\Exceptions\NestedValidationException; class UserNameRuleException extends NestedValidationException ( // )

    Well, finally we can validate our data. First, we pass our new rule to the validator so that he knows about it and we can use it in the future. In Respect Validation, this is done by calling the with() method, passing the namespace in which the non-standard rules are located.


    v::with("MyNamespace\\");

    Now all non-standard rules located in the namespace MyNamespace, will be “recognized” by the validator. The next step is to describe the necessary rules and perform validation.


    v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) ->attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data);

    Notice how we apply our rule to the attribute name. Here the name of the rule class has been transformed into the name of the validator method. The rest of the rules are, in general, intuitive.


    It’s worth mentioning separately why we provide the array $data to the object. The fact is that Respect Validation accepts objects, not arrays, as input. This should be taken into account when developing using this library.

    Feedback

    Unlike Aura.Filter, the Respect validator throws an exception when validation fails. And this exception contains validation error messages. Therefore, the example that was just shown should be written as follows:


    try ( v::with("RespectValidationExample\\"); v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) - >attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data ) catch (NestedValidationException $ex) ( $messages = $ex->getMessages(); )

    Using getMessages() we will get a flat array of all messages that the validator collected during the validation process. By dumping the array, we get something like this:


    array(5) ( => string(29) “Data validation failed for %s” => string(60) “login must contain only letters (a-z), digits (0–9) and “-_”” => string (25) “email must be valid email” => string(26) “password must not be empty” => string(32) “Attribute agreed must be present” )

    You can change the messages to your own. Perhaps I somehow misunderstood this library, but this process did not seem so obvious to me: you need to use the findMessages() method on a handled exception, in which you define messages not for attributes, but for rules.


    $ex->findMessages([ "userNameRule" => "The username must consist of two words.", "alnum" => "We don't like your login.", "email" => "You obviously don't want to give us your e-mail.", "notEmpty" => "Well, where is your password?", "agreed" => "It's a pity that you disagree." ]);

    I don't know what's wrong, but there are a couple of things I still don't understand. This is what we get by defining the rules in the above way:


    array(5) ( => string(40) “The username must be two words.” => string(31) “We don’t like your login.” => string(25) “email must be valid email” => string(5) “Well, where is your password?” => string(9) “It’s a pity that you don’t agree.”

    As you can see, the message for the email field was not applied, the standard one remained. But the message at index 4 is the opposite! And this despite the fact that I did not use the name of the rule, but the name of the field. Whereas if I had used the rule name (trueVal), my message would have gotten lost somewhere. Comments from experienced users of this library are very welcome.

    Sirius Validation

    Ok, let's move on to the next library and see how it handles similar tasks.

    Defining the rules

    Once again we need to define a rule for the username. We'll write it something like this:


    class UserNameRule extends AbstractRule ( // Error Messages const MESSAGE = "The username must be two words."; const LABELED_MESSAGE = "(label) must be two words."; public function validate($value, $valueIdentifier = null ) ( return (bool) preg_match("/^+\s+$/u", $value); ) )

    Please note the difference in approaches compared to the libraries already discussed. We define two kinds of messages in constants rather than using properties, methods or rule arguments.


    Now let's describe the validation logic:


    $validator = new Validator; $validator ->add("name", "required | MyApp\Validation\Rule\UserNameRule") ->add("login", "required | alphanumhyphen", null, "Login can only contain Latin letters, dashes and underscores. ") ->add("email", "required | email", null, "Please enter a correct e-mail.") ->add("password", "required | maxlength(64)", null, "Your password, sir.") ->add("agree", "required | equal(true)", null, "Why didn't you agree?");

    As you can see, the set of rules is very simple and readable. For description, we use names separated by horizontal bars. This approach is similar to that used in Laravel and Kontrolio.


    The fourth argument to the add() method describes the validation error message that Sirius will use if the validation fails. Why didn't we add a message for our new rule? UserNameRule?


    $validator->add("name", "required | MyApp\Validation\Rule\UserNameRule")

    This is because the messages are already described in the class constants:


    class UserNameRule extends AbstractRule ( // Error messages const MESSAGE = "The username must be two words."; ...

    Another option is to use the addMessage() method of the validator itself:


    $validator->addMessage("email", "Please enter a valid e-mail.");

    Please note that custom rules are identified by the full name of their class, while in Kontrolio you can specify an alias/alias.

    Feedback

    To perform validation, we call the validator method validate() , passing the data to it:


    $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail here "password" => "" // The password is not specified at all // "agreed" is not in the array because the user did not check the box ]; $validator->validate($data);

    Unlike Respect, Sirius will not throw an exception, but will simply return false. Validation error messages can be obtained through the getMessages() validator method. It returns errors grouped by attributes, so we need two foreach loops to go through the errors:


    foreach ($validator->getMessages() as $attribute => $messages) ( foreach ($messages as $message) ( echo $message->getTemplate() . "\n"; ) )

    Here $message is a class object Sirius\Validation\ErrorMessage, which has a getTemplate() method that returns the very message we need.

    ValitronDefining the rules

    The first difference: to add a new rule, you do not need to create a separate class. You can simply use a closure that returns a boolean result.


    To add custom rules, Valitron has a static method addRule(), in which the first two arguments are required, and the third is optional. I liked this method, since here the rule identifier, logic and error message are indicated in one place.


    use Valitron\Validator; Validator::addRule("two_words", function($field, $value) ( ​​return (bool) preg_match("/^+\s+$/u", $value); ), "The username must consist of exactly two words ");

    The second difference is how the rules are applied to attributes. In all previous cases, we saw that an attribute is, as it were, a primary thing.


    Valitron took a different route and put validation rules first. By describing rules, you seem to be applying attributes to these rules, and not vice versa.


    $validator = new Validator($data); $validator ->rule("two_words", "name")->label("") ->rule("required", [ "name", "login", "email", "password", "agreed" ] ) ->rule("slug", "login") ->rule("email", "email") ->rule("accepted", "agreed");

    As can be seen from the example, in the rule() method we first write the name of the rule, and only then indicate the attributes that must correspond to this rule. A more explicit example is the required rule, which shows how attributes "belong" to that rule.


    Valitron (like other solutions that we have reviewed) provides standard error messages. If you just use them, you will see that each message begins with the name of the corresponding attribute.


    Valitron substitutes attribute names into the message text even when non-standard error messages are used. That's why we used the label() method with an empty string to remove the attribute name.


    $validator->rule("two_words", "name")->label("") Feedback

    Specifically regarding validation, the Valitron library API is practically no different from what we have already seen in the article. To perform validation we call the validator method validate() :


    $validator->validate();

    Validation error messages can be retrieved using the getErrors() method:


    $validator->errors();

    Messages here are grouped by attributes in the same way as in Sirius Validation, except that there is no separate class for the message, and we get a regular multi-dimensional array.


    foreach ($validator->errors() as $attribute => $messages) ( foreach ($messages as $message) ( echo $message . "\n"; ) ) Kontrolio

    And finally, the last library for today is my own development called Kontrolio.

    Defining the rules

    Again, for the fifth time, we will create a validation rule for the username. Everything is relatively simple and standard:


    namespace MyProject\Validation\Rules; use Kontrolio\Rules\AbstractRule; class TwoWords extends Kontrolio\Rules\AbstractRule ( public function isValid($input = null) ( return (bool) preg_match("/^+\s+$/u", $input); ) )

    Now we create a factory and register a rule in it using the extend() method:


    namespace MyProject; use Kontrolio\Factory; use MyProject\Validation\Rules\TwoWords; $factory = Kontrolio\Factory::getInstance()->extend();

    After registering the rule, we can use it, including by name - two_words. Let's create a validator:


    $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail here "password" => "" // The password is not specified at all // "agreed" is not in the array because the user did not check the box ]; $rules = [ "name" => "two_words", "login" => "sometimes|alphadash", "email" => "email", "password" => "length:1.64", "agreed" = > "accepted" ]; $messages = [ "name" => "The username must consist of two words.", "login" => "We don't like your login.", "email" => "You obviously don't want to give us your email .", "password" => "Well, where is your password?", "agreed" => "It's a pity that you don't agree." ]; $validator = $factory->make($data, $rules, $messages);

    We described the rules using a syntax similar to that used in Laravel, although we could have used a more verbose version:


    $rules = [ "name" => new TwoWords, "login" => , "email" => new Email, "password" => new Length(1, 64), "agreed" => new Accepted ]; Feedback

    Validation is started using the same validate() method:


    $validator->validate();

    Now we can get error messages using one of the getErrors() or getErrorsList() methods. The first method allows for more complex error output, while the second returns a flat array. Using getErrors() we can output messages like this:



    And with getErrorsList() you can make a simpler list of messages:


    Bottom line

    In this article I showed examples of using the following libraries:

  • Aura.Filter
  • Respect Validation
  • Sirius Validation
  • Valitron
  • control
  • A “real world example” may seem too simple. I have to agree, since, indeed, some library capabilities were left out of the article. In principle, if you are interested, you can study their features yourself.


    Each of the libraries offers its own features and has its dark sides, so I think it’s a matter of taste and challenge to choose the one.


    Thanks for reading. Make the right choice.

    Tags: Add tags

    Good evening everyone (more like night - editor's note). Today we will improve that one a little. First, let's learn how to do form validation in PHP and do some security manipulations.

    So, look at the code below and note the following changes and the following reasons for the changes. I highlighted all new lines with color.

    The name of the form fields has been changed. You may ask – why the hell do we need this? It’s simple, I’ll answer you. As far as I know, some spam bots scour sites looking for forms and fill them out based on the names of these fields. In theory, if they don’t find a match, then they go home, which is what we want. Of course, I don’t think the degree of this protection is particularly great, but it won’t hurt us, and if spam emails decrease by 1 letter, that will be good =).

    Checking whether the email address is entered correctly. Line 17 uses the elseif operator, which will be checked if if returned a positive answer to us, that is, it said that the email address was missing at all, that is, it was not entered. Here we use the preg_match function, which allows us to compare the entered address with regular expression. Perhaps I’ll write briefly about regular expressions later, but for now it’s worth knowing that regular expression creates a template against which our string is checked. And if, in our case, the entered address does not match the expression, then again an error will be displayed. For example, here are a couple more regular expressions:
    |^[-а-яе\s\.,;:\?!]+$|i– this regular expression allows you to use only the Russian alphabet and some characters such as space, period, comma, etc.
    #http://[-a-z0-9_.]+[-a-z0-9_:@&?=+,.!/~*’%$]*\.(html?|php)#i– and this expression allows you to check the correct spelling of an address on the Internet.

    Next, we use the else operator, where all our code for sending a letter has already been transferred. You can create verification rules yourself in any quantity, just add new ones if, such as for checking an email address, and you will be happy.




    Contact person:



    Contact email:



    Message:






    This is how you can validate your PHP forms without resorting to anything extraneous. Next time in a post on the topic of forms, I think, validation of forms in jQuery will be considered. In the meantime, I'm waiting for your comments and wishes. Good night and happy morning everyone =).

    We will talk about the validation of POST or GET data, although in principle this can also be applied to data received by other methods, such as cookies. As you develop any web application, you need to write an interface for interacting with users and naturally create various forms for users to send data to the server. for example, these could be comments. I think it’s clear and obvious to everyone that the received data needs to be checked to see if it corresponds to the type, size, and specified range. First of all, this is required for the security of the system, website or database, because... Incorrectly transmitted data or a deliberately poorly formed request can open access to an attacker.

    Secondly, unverified data, if incorrect, can cause unstable operation of the script, the system or the entire server. Therefore, all data needs to be checked and double-checked; perhaps someone will say that there is no need for excessive paranoia, but I believe that in this matter it simply cannot be excessive.

    Do not trust data received from users, under any pretext, under any circumstances. It happens that we are simply too lazy to write code that checks the received data once again, or we hope that existing methods checking is enough, as a result of which we make concessions to ourselves.

    A little digression from the topic:
    Working on projects, developing and programming websites, scripts, and other systems takes up almost all of my free time (besides working time), in other words, I do this work for the maximum possible number of hours a day. From time to time there is a need to test something, for fun or just curiosity. As a result, sites made in haste, using homemade engines or CMS of ancient versions, become similar testing laboratory rats. Of course, all of the above suffers from crookedly written code, lack of data control and is simply teeming with various bugs. Actually, in most cases, in an hour of my experiments on such sites, I manage to find several serious vulnerabilities, and most of them lie in insufficient validation of the incoming data. IN lately This is often found in scripts that process POST data coming from JavaScript + Ajax.

    Apparently, the programmers who wrote these scripts using Ajax believe that since all requests occur in the background, without the user’s knowledge or simply without reloading the page, then the data need not be particularly checked.

    As a rule, quite a few of these scripts turn out to be so full of holes that without much effort they manage to make a larger hole and flood their shell. of course, solely for the purpose of experimentation and nothing more (the administration of such sites is always informed of existing vulnerabilities).

    I think the importance of validation is clear to everyone. For a long time, I wrote the same piece of code each time, then used my own data validation functions, many of which were very primitive and usually scattered throughout different parts(attached) files. Soon I began to get acquainted with the PHP frameworks Zend, CI, Kohana, each of which implemented its own class for validating data that I borrowed for my projects. In the end, I decided to tailor one of the CI classes to my needs, but it turned out that the author of one of the programming blogs had already taken care of this. Next, I share his works, namely the modified CodeIgniter library.

    Let's look at the following code:

    View code PHP

    require_once "validator.class.php" ; $validator = new Validator() ; $validator -> set_rules ("name" , "Your name" , array ("required" => , "alpha" => ) ) ; $validator -> set_rules ("email" , "Your email" , array ("required" => "Field %s is required" , "valid_email" => ) ) ; if ($validator -> run () ) ( echo "Validation was successful" ; ) else ( echo $validator -> get_string_errors () ; )

    As you can see from the example, in the first line we include the class file validator.calss.php to our script. Next, we create an instance of the class and save the object to a variable $validator.
    Then using the method $validator->set_rules($field, $label, $rules) set the fields for validation.

    This method takes 3 parameters:

  • $field- name of the validation field (the value of the name attribute in the tag)
  • $label- name of the validation field, will be inserted into error messages
  • $rules- an array of validation rules, in which the validation rule is used as the key, and the error message for this rule is used as the value
  • After all the fields for validation are set, we launch the validator using the method $validator->run(). If validation was successful, this method will return the value TRUE, otherwise, if there are any errors, it will return FALSE.

    There are three methods to receive error messages:

  • get_string_errors()- returns all error messages as a string
  • get_array_errors()— returns all messages as an array, where the field name is used as the key, and the error description for this field is used as the value.
  • form_error($field)- returns an error message for the field passed as the $field parameter
  • By default, error messages are wrapped in a tag . To set your design, use the method set_error_delimiters($prefix, $suffix). For example like this:

    Now error messages will turn into div with class "error"

    As you can see, everything is very simple.

    View code PHP

    $validator -> set_error_delimiters ( " " , " " ) ;

    To set validation rules, you can use the method set_rules($fields) pass a multidimensional associative array. Let's look at an example:

    View code PHP

    $rules = array ( array ( "field" => "name" , "label" => "Your name" , "rules" => array ( "required" => "Field %s is required" , "alpha" => "Field %s must contain only letters" ) , array ( "field" => "email" , "label" => "Your email" , "rules" => array ( "required" => "Field % s is required" , "valid_email" => "Field %s must contain a valid email address" ) ) ) ; $validator -> set_rules ($rules ) ;

    As you can see, I wrote down the same validation rules as in the first example, only in the form of a multidimensional associative array. You can use any of the methods that suit you best in a given situation.

    So, what validation rules does this class support?

    I brought to this class the most common validation rules that everyone encounters. Here full list these rules:

    requiredReturns FALSE if the field is empty
    integerReturns FALSE if the value is not an integer
    floatReturns FALSE if the value is not a numeric value
    valid_urlReturns FALSE if value is not a valid URL
    valid_emailReturns FALSE if value is not a valid email address
    valid_ipReturns FALSE if the IP address is not valid
    matchesReturns FALSE if the element does not match the value of another field element
    alphaReturns FALSE if the element contains more than just letters
    valid_captchaReturns FALSE if the value in the session field is not equal to the value of the form field
    valid_dateReturns FALSE if the element contains an invalid date

    Most of these rules use filters, which became available in PHP 5.

    If you wish, you can always expand the set of rules for validation by adding the necessary functions to the Validator class.

    To get the processed POST data value, use the following method:

    View code PHP

    Typically this method is called to clear the form upon successful processing of the form.


    In a previous article I promised to write a comparison of my own library with other available solutions, so today we will look at validation using Aura.Filter, Respect Validation, Sirius Validation and Valitron.


    Let's imagine that we have a certain public service in development that requires users to register for full access to all functions. Thus, the registration form will contain the following fields:

  • name. Must contain exactly two words, where the first is the user's first name and the second is the last name.
  • login. If a value is passed, it must contain only Latin letters, hyphens and underscores.
  • email. Must contain a valid email address.
  • password. Must be set and be no more than 64 characters long.
  • agreed. A typical checkbox that a user must check to confirm their acceptance of the terms of service.
  • So, we have five fields that the user must fill out in order to register with our imaginary service. Let's imagine that we received completely invalid data as input:


    $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail "password" => Aura.Filter

    Validation using Aura.Filter starts with a filter factory. We need to create a so-called “subject filter”, since we will be validating an array, not an individual value.

    We define the rules use Aura\Filter\FilterFactory; $filter = (new FilterFactory)->newSubjectFilter(); $filter->validate("name") ->isNotBlank() ->is("two_words") ->setMessage("The name must be two words."); $filter->validate("login") ->isBlankOr("alnum") ->setMessage("If you specify a login, it must contain only Latin characters."); $filter->validate("email") ->isNotBlank() ->is("email") ->setMessage("Please enter a valid email address."); $filter->validate("password") ->isNotBlank() ->is("strlenMax", 64) ->setMessage("Please write your password."); $filter->validate("agreed") ->is("callback", function($subject, $field) ( return $subject->($field) === true; ))->setMessage("You need agree to the terms of service.");

    As you can see, the description of the rules is quite simple. Aura.Filter provides a whole set of useful rules out of the box and some of them were used in the example above:

  • isNotBlank method. Specifies that the field cannot have a null value.
  • alnum. This rule only allows Latin letters.
  • email. And it’s so clear :)
  • strlenMax. Specifies that the field cannot exceed the length specified by the second argument of the is method.
  • callback. This type of rule is similar to closures from Kontrolio. It allows you to define a rule in the form of a closure. To this closure, Aura.Filter passes the “subject”, our data array from the form, and a field, in this case agreed .
  • You probably noticed that I didn't specify the two_words rule. Naturally, there is no such rule in Aura.Filter, so we need to create one. As the documentation says, this is done using a separate class for the rule:


    /** * Rule that validates the username. * The username consists of two words: first and last name, separated by one space. */ class UserNameRule ( /** * Validates the user name. * * @param object|array $subject * @param string $field * @param int $max * * @return bool */ public function __invoke($subject, $field , $max = null) ( $value = $subject->($field); if (! is_scalar($value)) ( return false; ) return (bool) preg_match("/^+\s+$/u", $value);

    The second step is to let the filter factory know about our new rule. It’s done by passing the first argument as an array of rules to the filter factory:


    The next step is to notify Aura.Filter that we have created a new rule and want to use it. This is done by passing an array of rules to the first argument of the factory:


    use Aura\Filter\FilterFactory; $rules = [ "two_words" => function() ( return new UserNameRule; ) ]; $filter = (new FilterFactory($rules))->newSubjectFilter();

    Now our two_words rule can be used in the same way as any other standard rule.

    Feedback

    As you remember, the incoming data that we validate is completely invalid, because each field contains an incorrect value or does not contain it at all. Therefore, it is assumed that as a result of validation we will receive errors and corresponding messages about them.


    We validate with Aura.Filter as follows:


    $valid = $filter->apply($data); if (! $valid) ( $failures = $filter->getFailures(); $messages = $failures->getMessages(); )

    IN $messages an array is being written, so to display messages we need two nested foreach:


    Respect Validation

    The second library I used in the comparison is a relatively popular solution called Respect Validation. Since people trust her, I think there is something to see there.


    For the purity of the experiment, when comparing libraries, we will use the same data set defined at the beginning:


    use Respect\Validation\Validator as v; $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail here "password" => "" // The password is not specified at all // "agreed" is not in the array because the user did not check the box ]; Defining the rules

    As with Aura.Filter, we need our own validation rule for the username, so let's start there:


    namespace MyNamespace; use Respect\Validation\Rules\AbstractRule; class UserNameRule extends AbstractRule ( public function validate($input) ( return (bool) preg_match("/^+\s+$/u", $input); ) )

    The external rules API is almost identical to Aura.Filter, only the validate() method is used instead of the __invoke() magic. It seemed to me, this API, simpler and more understandable. Well, it’s closer to Kontrolio :)


    I did not find any mention of this in the documentation, however, in addition to the rule itself, you need to create your own exception type for it. The name of the exception class must consist of the name of the rule class and a postfix Exception.


    use Respect\Validation\Exceptions\NestedValidationException; class UserNameRuleException extends NestedValidationException ( // )

    Well, finally we can validate our data. First, we pass our new rule to the validator so that he knows about it and we can use it in the future. In Respect Validation, this is done by calling the with() method, passing the namespace in which the non-standard rules are located.


    v::with("MyNamespace\\");

    Now all non-standard rules located in the namespace MyNamespace, will be “recognized” by the validator. The next step is to describe the necessary rules and perform validation.


    v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) ->attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data);

    Notice how we apply our rule to the attribute name. Here the name of the rule class has been transformed into the name of the validator method. The rest of the rules are, in general, intuitive.


    It’s worth mentioning separately why we provide the array $data to the object. The fact is that Respect Validation accepts objects, not arrays, as input. This should be taken into account when developing using this library.

    Feedback

    Unlike Aura.Filter, the Respect validator throws an exception when validation fails. And this exception contains validation error messages. Therefore, the example that was just shown should be written as follows:


    try ( v::with("RespectValidationExample\\"); v::attribute("name", v::userNameRule()) ->attribute("login", v::alnum("-_")) - >attribute("email", v::email()) ->attribute("password", v::notEmpty()->stringType()->length(null, 64)) ->attribute("agreed", v::trueVal()) ->assert((object) $data ) catch (NestedValidationException $ex) ( $messages = $ex->getMessages(); )

    Using getMessages() we will get a flat array of all messages that the validator collected during the validation process. By dumping the array, we get something like this:


    array(5) ( => string(29) “Data validation failed for %s” => string(60) “login must contain only letters (a-z), digits (0–9) and “-_”” => string (25) “email must be valid email” => string(26) “password must not be empty” => string(32) “Attribute agreed must be present” )

    You can change the messages to your own. Perhaps I somehow misunderstood this library, but this process did not seem so obvious to me: you need to use the findMessages() method on a handled exception, in which you define messages not for attributes, but for rules.


    $ex->findMessages([ "userNameRule" => "The username must consist of two words.", "alnum" => "We don't like your login.", "email" => "You obviously don't want to give us your e-mail.", "notEmpty" => "Well, where is your password?", "agreed" => "It's a pity that you disagree." ]);

    I don't know what's wrong, but there are a couple of things I still don't understand. This is what we get by defining the rules in the above way:


    array(5) ( => string(40) “The username must be two words.” => string(31) “We don’t like your login.” => string(25) “email must be valid email” => string(5) “Well, where is your password?” => string(9) “It’s a pity that you don’t agree.”

    As you can see, the message for the email field was not applied, the standard one remained. But the message at index 4 is the opposite! And this despite the fact that I did not use the name of the rule, but the name of the field. Whereas if I had used the rule name (trueVal), my message would have gotten lost somewhere. Comments from experienced users of this library are very welcome.

    Sirius Validation

    Ok, let's move on to the next library and see how it handles similar tasks.

    Defining the rules

    Once again we need to define a rule for the username. We'll write it something like this:


    class UserNameRule extends AbstractRule ( // Error Messages const MESSAGE = "The username must be two words."; const LABELED_MESSAGE = "(label) must be two words."; public function validate($value, $valueIdentifier = null ) ( return (bool) preg_match("/^+\s+$/u", $value); ) )

    Please note the difference in approaches compared to the libraries already discussed. We define two kinds of messages in constants rather than using properties, methods or rule arguments.


    Now let's describe the validation logic:


    $validator = new Validator; $validator ->add("name", "required | MyApp\Validation\Rule\UserNameRule") ->add("login", "required | alphanumhyphen", null, "Login can only contain Latin letters, dashes and underscores. ") ->add("email", "required | email", null, "Please enter a correct e-mail.") ->add("password", "required | maxlength(64)", null, "Your password, sir.") ->add("agree", "required | equal(true)", null, "Why didn't you agree?");

    As you can see, the set of rules is very simple and readable. For description, we use names separated by horizontal bars. This approach is similar to that used in Laravel and Kontrolio.


    The fourth argument to the add() method describes the validation error message that Sirius will use if the validation fails. Why didn't we add a message for our new rule? UserNameRule?


    $validator->add("name", "required | MyApp\Validation\Rule\UserNameRule")

    This is because the messages are already described in the class constants:


    class UserNameRule extends AbstractRule ( // Error messages const MESSAGE = "The username must be two words."; ...

    Another option is to use the addMessage() method of the validator itself:


    $validator->addMessage("email", "Please enter a valid e-mail.");

    Please note that custom rules are identified by the full name of their class, while in Kontrolio you can specify an alias/alias.

    Feedback

    To perform validation, we call the validator method validate() , passing the data to it:


    $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail here "password" => "" // The password is not specified at all // "agreed" is not in the array because the user did not check the box ]; $validator->validate($data);

    Unlike Respect, Sirius will not throw an exception, but will simply return false. Validation error messages can be obtained through the getMessages() validator method. It returns errors grouped by attributes, so we need two foreach loops to go through the errors:


    foreach ($validator->getMessages() as $attribute => $messages) ( foreach ($messages as $message) ( echo $message->getTemplate() . "\n"; ) )

    Here $message is a class object Sirius\Validation\ErrorMessage, which has a getTemplate() method that returns the very message we need.

    ValitronDefining the rules

    The first difference: to add a new rule, you do not need to create a separate class. You can simply use a closure that returns a boolean result.


    To add custom rules, Valitron has a static method addRule(), in which the first two arguments are required, and the third is optional. I liked this method, since here the rule identifier, logic and error message are indicated in one place.


    use Valitron\Validator; Validator::addRule("two_words", function($field, $value) ( ​​return (bool) preg_match("/^+\s+$/u", $value); ), "The username must consist of exactly two words ");

    The second difference is how the rules are applied to attributes. In all previous cases, we saw that an attribute is, as it were, a primary thing.


    Valitron took a different route and put validation rules first. By describing rules, you seem to be applying attributes to these rules, and not vice versa.


    $validator = new Validator($data); $validator ->rule("two_words", "name")->label("") ->rule("required", [ "name", "login", "email", "password", "agreed" ] ) ->rule("slug", "login") ->rule("email", "email") ->rule("accepted", "agreed");

    As can be seen from the example, in the rule() method we first write the name of the rule, and only then indicate the attributes that must correspond to this rule. A more explicit example is the required rule, which shows how attributes "belong" to that rule.


    Valitron (like other solutions that we have reviewed) provides standard error messages. If you just use them, you will see that each message begins with the name of the corresponding attribute.


    Valitron substitutes attribute names into the message text even when non-standard error messages are used. That's why we used the label() method with an empty string to remove the attribute name.


    $validator->rule("two_words", "name")->label("") Feedback

    Specifically regarding validation, the Valitron library API is practically no different from what we have already seen in the article. To perform validation we call the validator method validate() :


    $validator->validate();

    Validation error messages can be retrieved using the getErrors() method:


    $validator->errors();

    Messages here are grouped by attributes in the same way as in Sirius Validation, except that there is no separate class for the message, and we get a regular multi-dimensional array.


    foreach ($validator->errors() as $attribute => $messages) ( foreach ($messages as $message) ( echo $message . "\n"; ) ) Kontrolio

    And finally, the last library for today is my own development called Kontrolio.

    Defining the rules

    Again, for the fifth time, we will create a validation rule for the username. Everything is relatively simple and standard:


    namespace MyProject\Validation\Rules; use Kontrolio\Rules\AbstractRule; class TwoWords extends Kontrolio\Rules\AbstractRule ( public function isValid($input = null) ( return (bool) preg_match("/^+\s+$/u", $input); ) )

    Now we create a factory and register a rule in it using the extend() method:


    namespace MyProject; use Kontrolio\Factory; use MyProject\Validation\Rules\TwoWords; $factory = Kontrolio\Factory::getInstance()->extend();

    After registering the rule, we can use it, including by name - two_words. Let's create a validator:


    $data = [ "name" => "Albert", // Must be two words "login" => "@lbert", // "Forbidden" character @ "email" => "something wrong", / / There should be an e-mail here "password" => "" // The password is not specified at all // "agreed" is not in the array because the user did not check the box ]; $rules = [ "name" => "two_words", "login" => "sometimes|alphadash", "email" => "email", "password" => "length:1.64", "agreed" = > "accepted" ]; $messages = [ "name" => "The username must consist of two words.", "login" => "We don't like your login.", "email" => "You obviously don't want to give us your email .", "password" => "Well, where is your password?", "agreed" => "It's a pity that you don't agree." ]; $validator = $factory->make($data, $rules, $messages);

    We described the rules using a syntax similar to that used in Laravel, although we could have used a more verbose version:


    $rules = [ "name" => new TwoWords, "login" => , "email" => new Email, "password" => new Length(1, 64), "agreed" => new Accepted ]; Feedback

    Validation is started using the same validate() method:


    $validator->validate();

    Now we can get error messages using one of the getErrors() or getErrorsList() methods. The first method allows for more complex error output, while the second returns a flat array. Using getErrors() we can output messages like this:



    And with getErrorsList() you can make a simpler list of messages:


    Bottom line

    In this article I showed examples of using the following libraries:

  • Aura.Filter
  • Respect Validation
  • Sirius Validation
  • Valitron
  • control
  • A “real world example” may seem too simple. I have to agree, since, indeed, some library capabilities were left out of the article. In principle, if you are interested, you can study their features yourself.


    Each of the libraries offers its own features and has its dark sides, so I think it’s a matter of taste and challenge to choose the one.


    Thanks for reading. Make the right choice.

    Tags:

    • data validation
    • php
    • bicycle building
    Add tags