Validating user input with functions in PHP

Validating user input with functions in PHP

Created:09 Sep 2017 21:07:45 , in  Web development

User input validation is one of the oldest and most frequently occurring problems in computer programming. It crops up regardless of programming language and at almost every project.

If not dealt with skillfully, in particular when larger amount of user input is involved, it can quickly turn any project into a difficult to complete and susceptible to hacks nightmare.

Technically, the problem is not the most demanding one, though.

When I think of input validation at the high level, a simple mapping from one boolean data type value to itself or to the other comes to my mind.

To put this in simple terms, at the beginning I make an assumption, perhaps too optimistically, that all the input is correct. Though, in the second step, I start looking at every bit of the data more and more closely. This is the part when tools like functions prove indispensable. All of them return either true or false. My initial assumption about the input remains unchanged unless one of the validating functions returns boolean false. If none of them returns the value, my program moves on to the next stage, perhaps one that involves the input manipulation. Otherwise, some input parts have to be corrected before the next stage can be reached.

Now, how this high level, somewhat abstract thinking of input validation can be turned into flexible and easy to use code?

My approach is described best by a tiny PHP class called SWWWValidation.

The class validates input ( passed as an associative array of values), with help of rules. Each such rule checks for just one particular property of input data, like whether required part of it exists, is an array, or perhaps is a number in range from 0 to 100. The rules rely upon functions for checks entirely. Once all the rules have been run, validation result is known. Input is either valid or not. Validation errors are set in the same time.

Validation class

Here is SWWWValidation class listing:

/*
  Class: SWWWValidation 
  Description: Validate user input
  Author: Sylwester Wojnowski
  WWW: wojnowski.net.pl

  Methods:
    instnce($input) - public static - get instance of SWWWValidation
      parameters:
        $input - array - associative array of key/value pairs
        return - object - instance of SWWWValidation
        
    rule($key,$func,$args,$error) - public - set validation rule
      parameters: 
        $key - string - index in $input array
        $func - function - callback
        [$args] - array - arguments to be passed to $func
        [$error] - string - error message
      return - string - feedback for the score
      
    ckeck() - public - check input for validity
      return - bool
    
    errors($key) - public - recover errors
      parameters:
        [$key] - string - index in $input array
      return - array - array of arrays of error strings
    
    error($key,$error) - public - set error
      parameters:
        $key - string index in $input array
        $error - string
      return - object - validation            
*/

class SWWWValidation{
  
  const INVALID_INPUT = "Input should be given as array of key/value pairs.";

  private $rules = array();
  private $errors = array();
  private $input = null;

  // get instance
  public static function instance($input = array()){
    return new SWWWValidation($input); 
  }

  public function __construct($input){
    if(!is_array($input)){ throw new Exception(self::INVALID_INPUT); }
    $this -> input = $input; 
  }

  // add rule   
  public function rule($key,$func,$args = array(':value'),$error = ''){
    $params = array();
    if(!array_key_exists($key,$this -> rules)){ $this -> rules[$key] = array(); }
    $func = is_array($func) && count($func) === 1 ? $func[0] : $func;
    // replace :value,:validation,:data
    foreach($args as $arg){
      switch($arg){
        case ':value':
          $params[] = $this -> input[$key]; 
        break;
        case ':validation':
          $params[] = $this;
        break;
        case ':input':
          $params[] = $this -> input; 
        break;
        default:
          $params[] = $arg;
      }
    }
    $this -> rules[$key][] = array($func,$params,$error);

    return $this;
  }
  
  // validate input
  public function check(){ 
    foreach($this -> rules as $key => $ruleset){
      foreach($ruleset as $rule){
        $result = null;     
        $result = call_user_func_array($rule[0],$rule[1]);  
        if(!$result){
          // set error
          $this -> error($key,$rule[2]); 
        }
      }  
    }
    return empty($this -> errors);  
  }
 
  // return error messages 
  public function errors($key = ''){
    if(!empty($key)){
      return $this -> errors[$key];
    }
    // return all errors
    return $this -> errors;
  }
  
  // set error message
  public function error($key,$error){
    if(!array_key_exists($key,$this -> errors)){
      $this -> errors[$key] = array(); 
    }
    $this -> errors[$key][] = $error;
    return $this;      
  }
} 

Configuration

As mentioned above, SWWWValidation (or more accurately its instance method) accepts an associative array of values to be checked for validity. Not much more there is to say in this place. We shall move on to an use example next.

Use example

Let's assume that, an array of input data like the one below is to be validated using SWWWValidation:


$input = array(
  'firstname' => null,
  'surename' => 'Trewin',
  'age' => 22,
  'email' => 'email@domain.ext',
  'repeat_email' => 'email@domain.ext'
);

Some functions, will be needed to validate the above. The three given below are anonymous ones. Each of them returns the boolean data type (either true or false).


// check for value existence
$exists = function($value){
  return isset($value);
};
    
// check whether value is an empty string or not
$not_empty = function($value){
  return !empty((string)$value);
};
    
// check whether value matches $input['repeat_email'] - a specific one     
$matches = function($value,$input){
  return $value === $input['repeat_email'];
};

SWWWValidation can accept not just anonymous functions but any type of function available in PHP programming language like built-in functions, object methods or static class methods.

Here a callback given as a static class method.


class SWWWValidationCallbacks{
  // invalid email error message
  const INVALID_EMAIL = 'Email is invalid';
  // valid email
  public static function email($value){
    return (bool)preg_match('/^[A-Z0-9._-]+@[A-Z0-9.-]+\.[A-Z0-9.-]+$/i',$value);
  }
}

The class contains an error message which can be passed together with the function to a rule.

Moving on to the nitty-gritty of validating input with SWWWValidation:

Obtain validation object:


$v = SWWWValidation::instance($input);

Add rules to fields you need validated:


// use callback function
$v -> rule('surename',$not_empty,array(':value'));
// use built-in in_array function
$v -> rule('age','in_array',array(':value',range(0,100)));
// check whether email matches repeat_email with anonymous function
$v -> rule('email',$matches,array(':value',':input'));
// use static class method as a callback
$v -> rule(
  'email',
   array('SWWWValidationCallbacks','email'),
   array(':value'),
   SWWWValidationCallbacks::INVALID_EMAIL
);

Check, whether the input is valid:


$v -> check();
=> true

Let's add some rule that makes the input invalid and check again:


$v -> rule('firstname', $exists, array(':value'),'First name not given!');
$v -> check();
=> false

Now, incidentally, the last rule has the fourth parameter specified. It is an error message which, if the rule did not pass, would be recovered in the manner shown below.

Obtaining errors

All the errors can be obtained by calling errors method:


$v -> errors();
=> array(
     'firstname' => array('First name not given!')
   )

Errors for a particular key of input array can be recovered by passing the key to the method:


$v -> errors('firstname')
=> array('First name not given!')

Each piece of input data can have as many rules check it as necessary. Each of these rules can have an error message passed to it.

A word about rules

Rule is just a validation object method, it can accept up to 4 parameters.

First of them is a key in input array value at which in the array to be validated.

The second is a function to be used to validated the value.

The third parameter is an array of values to be passed to the callback function.

Apart from standard parameters, this array can contain strings like:

:value - gets replaced with value at the given key in input array before being passed to callback function

:validation - gets replaced with validation object before being passed to callback function.

:input - gets replaced with input array before being passed to callback function.

The fourth, optional parameter, is already mentioned error string.

And that's all there is to SWWWValidation.

Final thoughts

As I mentioned above,at the high level input validation can be thought of as a mapping from either one boolean value to itself or to the other. Functions are a crucial linchpin in the process. SWWWValidation is just my implementation of this basic idea in PHP.

I hope you enjoyed the article, found it instructive and the code easy to get.

This post was updated on 09 Sep 2017 21:10:20

Tags:  php 


Author, Copyright and citation

Author

Sylwester Wojnowski

Author of the above article, Sylwester Wojnowski, is sWWW admin and owner.He enjoys doing Maths and studying algorithms, writing code in scripting and command languages, Thrash Metal music and playing electric guitar.

Copyrights

©Copyright, 2019 Sylwester Wojnowski. This article may not be reproduced or published as a whole or in parts without permission from the author. If you share it, please give author credit and do not remove embedded links.

Computer code, if present in the article, is excluded from the above and licensed under GPLv3.

Citation

Cite this article as:

Wojnowski, Sylwester. "Validating user input with functions in PHP." From sWWW - Code For The Web . https://wojnowski.net.pl//main/index/validating-user-input-with-functions-in-php