Using PHP filter functions like filter_var_array () there is a way to check if the length of the input string does not exceed some value

I have been playing around with the PHP filter library. I liked it, but I can't seem to execute a simple filter function. I essentially want to invalidate those values ​​in my input array that are strings and are longer than a certain value. Is there a way to do this, for example

$data = array('input_string_array' => array('aaa', 'abaa', 'abaca'));
$args = array(
    'component'    => array('filter'    => FILTER_DEFAULT,
                            'flags'     => FILTER_REQUIRE_ARRAY, 
                            'options'   => array('min_length' => 1, 'max_length' => 10)
                           )
);

var_dump(filter_var_array($data, $args));

      

I tried this and it gave me an error. because presumably there is no min_length / max_length option. But then how to implement it? There is also a place that mentions all the parameters like max_range, min_range, regexp.

Also I had another doubt about the filters in the FILTER_CALLBACK filter. I wanted to know if there is a way to pass a parameter other than data to the called function? something like that,

echo filter_var($string, FILTER_CALLBACK, array("options"=> array("lengthChecker", "5")));

      

Many thanks for the help.

+2


source to share


3 answers


If there is no better, more direct filter +, you can use FILTER_VALIDATE_REGEXP

$data = array('input_string_array' => array('', 'aaa', 'abaa', 'abaca'));
$args = array(
  'input_string_array' => array(
    'filter' => FILTER_VALIDATE_REGEXP,
    'flags'     => FILTER_REQUIRE_ARRAY|FILTER_NULL_ON_FAILURE,
    'options'   => array('regexp'=>'/^.{1,3}$/')
  )
);
var_dump(filter_var_array($data, $args));

      

prints



array(1) {
  ["input_string_array"]=>
  array(4) {
    [0]=>
    NULL
    [1]=>
    string(3) "aaa"
    [2]=>
    NULL
    [3]=>
    NULL
  }
}

      

To get rid of NULL elements, you can use eg. array_filter () .

+11


source


I believe the original problem was that the field in the data array was not named the same as the field in the filters array.



+2


source


Introduction

You will need at least PHP 5.4+ for this answer (due to at least array syntax).

If the goal is to do something like this:

$filteredArray = filter_var_array($arrayToFilter, $filterInstuctionsArray);

      

... and use the return results of the main PHP functions (along with the decision logic) to check the length of the string ( mb_strlen()

, strlen()

) of the string, the key must have different Array filter commands. To pass arguments to your callback function (for reuse, encapsulation and generalization purposes, etc.), I believe there are at least two scenarios.

Scripts

A ) Forms of class / object.

'options' => [$this, 'callbackMethod']

'options' => [$this->object, 'callbackMethod']

'options' => [$object, 'callbackMethod']

      

B ) Procedural form.

'options' => 'callbackFunction'

      

Decision

1 ) Replace either in script A with an instance of an object right then and there, passing its constructor in any arguments. This seems unlikely as it attacks tightly coupled code. $this

$object

new

Alternatively, one would be able to inject the prepopulated object into a class of a Validator

specific type and run filter_input_array()

from that class Validator

. Thus, passing arguments to callbackMethod

is unnecessary.

or

2 ) Replace in script B with PHP Anonymous Function and implement syntax for passing class arguments / constraints . 'callbackFunction'

use

Validator

function ($value) use ($min, $max) {
    $length = mb_strlen($value, 'UTF-8');
    return ($length >= $min) && ($length <= $max);
}

      

Attempt # 1: filter command with anonymous functions

Here is a step-by-step example of working with scalar values.

$filterInstructionsArray[
                            'fName' = ['filter'  => FILTER_CALLBACK,
                                       'flags'   => FILTER_REQUIRE_SCALAR,
                                       'options' => function ($value) use ($min, $max) {
                                                          $length = mb_strlen($value, 'UTF-8');
                                                          return ($length >= $min) && ($length <= $max);}],
                            'lName' = ['filter'  => FILTER_CALLBACK,
                                       'flags'   => FILTER_REQUIRE_SCALAR,
                                       'options' => function ($value) use ($min, $max) {
                                                          $length = mb_strlen($value, 'UTF-8');
                                                          return ($length >= $min) && ($length <= $max);}]
                         ];

      

Of course, this violates DRY principles . So you can define an anonymous function as a property of a class Validator

(or just assign it to a variable), making it a named instance of an object Closure

.

private $checkNameLength = function ($value) use ($this->nameMin, $this->nameMax) {
        $length = mb_strlen($value, 'UTF-8');
        return ($length >= $this->nameMin) && ($length <= $this->nameMax);
    };

      

or

$checkNameLength = function ($value) use ($min, $max) {
        $length = mb_strlen($value, 'UTF-8');
        return ($length >= $min) && ($length <= $max);
    };

      

So, I hope one of two things will work.

Attempt # 2: Array filter command with named anonymous functions

$filterInstructionsArray[
                            'fName' = ['filter'  => FILTER_CALLBACK,
                                       'flags'   => FILTER_REQUIRE_SCALAR,
                                       'options' => [$this, 'checkNameLength']]
                         ];

      

or

$filterInstructionsArray[
                            'fName' = ['filter'  => FILTER_CALLBACK,
                                       'flags'   => FILTER_REQUIRE_SCALAR,
                                       'options' => 'checkNameLength']
                         ];

      

Potential complications

Closure

instances $this->checkNameLength

and $checkNameLength

are objects, not regular "methods / functions". But, if PHP is not complaining, I will not tear my hair. I am guessing one can try to define a function inside an anonymous function.

$checkName = function ($value) use ($min, $max) {

        function lengthTest($string, $min, $max){
            $length = mb_strlen($string, 'UTF-8');
            return ($length >= $min) && ($length <= $max);
        }
    };

      

Then your array of filter commands will look like this.

$filterInstructionsArray[
                            'fName' = ['filter'  => FILTER_CALLBACK,
                                       'flags'   => FILTER_REQUIRE_SCALAR,
                                       'options' => [$checkName, 'lengthTest']]
                         ];

      

Or perhaps it is ...

$filterInstructionsArray[
                            'fName' = ['filter'  => FILTER_CALLBACK,
                                       'flags'   => FILTER_REQUIRE_SCALAR,
                                       'options' => 'lengthTest']
                         ];

      

Conclusion

There is a better way to create a generic string length checker than using PHP filter_var_array()

and anonymous functions. Usage 'filter' => FILTER_VALIDATE_REGEXP

may make it easier to check the length of a single string, but this does not replace DRY principles. You end up with many operators in your array of filter instructions, just to handle the lengths of the strings in the input array.

    //If you just want to test only the lengths first, this is
    //very inefficient. Assume each $regex is only checking string length.

    $filterLengthInstructions = [
                'fName'    => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $fNameRegex]],
                'lName'    => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $lNameRegex]],
                'company'  => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $comanyRegex]],
                'address1' => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $address1Regex]],
                'address2' => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $address2Regex]],
                'zip'      => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $zipRegex]],
                'website'  => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $urlRegex]],
                'email'  => ['filter'  => FILTER_VALIDATE_REGEXP,
                               'flags'   => FILTER_REQUIRE_SCALAR,
                               'options' => ['regexp' => $emailRegex]]
     ];

      

This can be done if you are trying to create a pure class filter_input_array()

Validator

or subroutine. But you'll have to do multiple passes filter_var_array()

, with multiple arrays of filter commands (because the length of a string isn't the only thing that makes it valid or invalid).

For website

and email

you will want to use 'filter' => FILTER_VALIDATE_URL

and 'filter' => FILTER_VALIDATE_EMAIL.

. In other cases, you will want to take advantage of 'filter' => FILTER_VALIDATE_IP

. Also, especially in case email

, you can restrict valid email addresses to a subset of the official regex RFCs. To keep it clean, you would not put this regex in $filterLengthInstructions

.

The underlying causes in order to change min_length

and max_length

the ability to write business logic once and use it everywhere.

At a minimum, my advice is to create an abstract class Validator

and define one (1) method that checks the length of strings.

Class check

Now you can split this method or delegate this task to the injected method of the object StringTester

.

Testing a class with StringTester

It doesn't matter, but by defining concrete child classes Validator

, all you have to do is define your test parameters in an array, create a loop, and call:

$this->testString($string, $min, $max, $pattern, $errorMessage);

      

or

$this->stringTester->testString($string, $min, $max, $pattern, $errorMessage);

      

... inside the loop. Be sure to consider $ errorMessage.

abstract Class Tester
{

}

      


class StringTester extends Tester
{
    private function testString($string, $min, $max, $pattern, &$errorMessage)
    {
        $length = mb_strlen($string, 'UTF-8');

        if($length < $min)      //Test string against minimum length.
        {
            $errorMessage = 'Too small! ('.$min.' min, ' .$length. ' given.)';
        }
        elseif($length > $max)  //Test string against maximum length.
        {
            $errorMessage = 'Too large! ('.$max.' max, ' .$length. ' given.)';
        }
        elseif(preg_match($pattern, $string) === 0)  //Test string pattern.
        {
            $errorMessage = 'Invalid string format!';
        }
        else
        {
            $errorMessage = '';  //The error message is the empty string.
        }

        return;
    }
}

      


abstract Class Validator
{
    //Arrays
    protected $inputArray;
    protected $errorMessagesArray = [];
    protected $stringTestRulesArray;  //I know. I know. :-)

    //Objects
    protected $stringTester;

    //Abstract functions
    abstract public function validate();

    public function __construct(Tester $stringTester, array $inputArray, array $stringTestRutlesArray)
    {
        $this->stringTester         = $stringTester;
        $this->inputArray           = $inputArray;
        $this->stringTestRulesArray = $stringTestRulesArray
    }

    public function getInput()
    {
        return $this->inputArray;
    }

    public function getErrorMessages()
    {
        return $this->errorMessagesArray();
    }

    protected function validateStrings()
    {
        //Notice how input values correspond to error message elements via $key.
        foreach($this->stringTestRulesArray as $key = $valuesArr)
        {
            $this->stringTester->testString($this->inputArray[$key], $valuesArr['min'], $valuesArr['max'], $valuesArr['pattern'], $this->errorMessagesArray[$key]);
        }

        return;
    }

}

      


class ContactValidator extends Validator
{
    public function __construct(Tester $stringTester, Sanitizer $sanitizer)
    {
        $stringTestRulesArray = [
                                  'fName' => ['min' => 1, 'max' => 25, 'pattern' => '/[A-Za-z\' -]/'],
                                  'lName' => ['min' => 1, 'max' => 40, 'pattern' => '/[A-Za-z\' -]/']
                                ];

        parent::__construct($stringTester, $sanitizer->getInput(), $stringTestRulesArray);
    }

    public function validate()
    {
        $this->validateStrings();
        //Other, contact form specific validation stuff.
    }
}

      


class RegisterValidator extends Validator
{
    public function __construct(Tester $stringTester, Sanitizer $sanitizer)
    {
        $stringTestRulesArray = [
                                  'fName' => ['min' => 1, 'max' => 30, 'pattern' => '/[A-Za-z\' -]/'],
                                  'lName' => ['min' => 1, 'max' => 45, 'pattern' => '/[A-Za-z\' -]/']
                                ];

        parent::__construct($stringTester, $sanitizer->getInput(), $stringTestRulesArray);
    }

    public function validate()
    {
        $this->validateStrings();
        //Other, register form specific validation stuff.
    }
}

      

0


source







All Articles