PHP Programming/OOP5/Advanced Input validation

This is a very flexible and advanced inputvalidator created by nemesiskoen. The example will demonstrate its power.

<?php

$pv = new InputValidator($_POST);

if($pv->exists('submit')) { // is the value 'submit' set in the $_POST array?

    $pv->hasValue('age', 'You must enter an age');
    $pv->hasValue('email', 'You must enter an email');
    // ...

    $pv->isInt('age', 'You must enter a valid age.');
    $pv->isEmail('email', 'You must enter a valid email.');
    $pv->hasMinLength('username', 2, "You're username needs to be at least 2 characters long.");
    $pv->matchbool(someFunction(), 'The function returned false!');
    $pv->matchRegex('username', REGEX_HERE, 'error message here');
    $pv->equals('password1', $pv->get('password2'), "Passwords don't match.");
    $pv->equals('password1', $pv->get('username'), "Password can't be the same as your username.");
    $pv->isUrl('website', 'You must enter a valid website.');

    if($pv->render()) {
        // form successfully submitted!
    }

}

$pv->assignToTemplate($tpl); // if you work with a template parser this will assign ALL values again, with the same name, but prefixed by 'p'.

// otherwise you can query the error array as followed:
$errors = $pv->getErrors();
// loop through the errors
echo 'The form couldn't submt because: <br />';
foreach($errors as $v) {
    echo $v . '<br />';
}

?>

<?php

/**
 * @package DP_InputValidator
 *
 */

class DP_InputValidator_Abstract {
        
        /**
         * Mainarray
         *
         * @access protected
         * @var array $_array
         */
        
        protected $_array = array();
        
        /**
         * All errorstring
         *
         * @access protected
         * @var array $_errorStrings
         */
        
        protected $_errorStrings = array();
        
        /**
         * Errorstrings
         *
         * @access public
         * @var string $noValueError
         * @var string $noIntError
         * @var string $noEmailError
         * @var string $noRegexError
         * @var string $equalError
         * @var string $noEqualError
         * @var string $noMinLengthError
         */
        
        public $noValueError = "%s has no value";
        public $noIntError = "%s is no int";
        public $noEmailError = "%s is not a valid email";
        public $noRegexError = "%s doesn't match a certain regex";
        public $equalError = "%s equals something that isn't allowed!";
        public $noEqualError = "%s doesn't equal something, which is required!";
        public $noMinLengthError = "%s must be a certain length!";
        public $noIssetError = "%s is not set!";
        
        /**
         * Set the array to validate
         *
         * @access protected
         * @param array &$array
         * @param bool $safe
         */     
        protected function __construct(&$array, $safe = true) {
                $this->_array = $array;
                if($safe) {
                        $array = null;
                }
        }
        
        /**
         * Get a secured item of the array
         *
         * @access public
         * @param string $key
         * @return mixed
         */
        public function get($key) {
                return $this->_secureArray($this->_array[$key]);
        }

        /**
         * Get a raw item of the array
         *
         * @access public
         * @param string $key
         * @return string
         */   
        public function value($key) {
                return $this->_array[$key];
        }
 
        /**
         * Get the whole array, if secured is set to true then the array will be secured
         * 
         * @access public
         * @param bool $secure = true
         * @param mixed $noSubmit = 'submit'
         * @return array
         */
        public function getArray($secure = true, $noSubmit = 'submit') {
                $array = $this->_array;
                if($secure) {
                        foreach($array as $k => $v) {
                                if(is_array($v)) {
                                        $array[$k] = $this->_secureArray($v);
                                } else {
                                        $array[$k] = htmlsecure($v);
                                }
                        }
                }
                
                if($noSubmit) {
                        unset($array[$noSubmit]);
                }
                
                return (array) $array;          
        }
        
        /**
         * Render method 
         * if a fault has a occurred, an no exception is thrown: 
         * this function will throw an exception (depending of the $throw parameter)
         * If the $reset parameter is set to true, all the errorArrays will be reset
         * throws Exception
         *
         * @access public
         * @param bool $reset
         * @return bool
         */
        public function render($reset = true) {
                $checks = $this->_getAllErrorArrays();
                $aantal = 0;
                foreach($checks as $v) {
                        $var = '_' . $v;
                        $count += count($this->$var);
                        if($reset) $this->$var = array();
                }
                $return = ($count == 0 && count($this->_errorStrings) == 0);
                if($reset && $return) $this->_errorStrings = array();
                return $return;
        }
        
        /**
         * Set a var, override if $override is set on true
         *
         * @param string $var
         * @param string $value
         * @param bool $overwrite
         */
        public function setVar($var, $value = "", $overwrite = true) {                
                if(is_array($var)) {
                        foreach($var as $k => $v) {
                                $this->setVar($k, $v, $value);
                        }
                } elseif(!isset($this->_array[$var]) || $overwrite) {
                        $this->_array[$var] = $value;
                }
        }
        
        /**
         * Unset a var
         *
         * @param string $varName
         */
        public function unsetVar($varName) {
                if($this->exists($varName)) {
                        unset($this->_array[$varName]);
                }
        }
        
        /**
         * Get all the occurred errorStrings, if the $multiD parameter is set to true
         * the return array will be multiDimensional
         * otherwise it will be a 1D array
         *
         * @access public
         * @param bool $multiD = false
         * @return array
         */ 
        public function getErrorStrings($multiD = false) {
                if($multiD) {
                        return $this->_errorStrings;
                }
                
                $return = array();
                foreach($this->_errorStrings as $array) {
                        foreach($array as $value) {
                                $return[] = $value;
                        }
                }
                
                return (array) $return;
        }
        
        
        /**
         * Assign the errors to a templatePower template.
         *
         * @access public
         * @param string $tpl
         * @param string $block
         * @param string $var
         * @return InputValidator_Abstract
         */
        public function assignToTemplate($tpl) {
                $tpl->assign($this->getArray(), true, false, 'p_');
                $errorstrings = $this->getErrorStrings();
                
                $tpl->assign('error', count($errorstrings) > 0);
                $tpl->assign('errors', $errorstrings);
                
                return $this;
        }
        
        /**
         * If one of the 'check'-methods is given an array as argument, this method will handle this
         *
         * @access protected
         * @param bool $multiD
         * @return array
         */ 
        protected function _handleArray($keys, $function, $errorString) {
                $ok = true;
                foreach($keys as $v) {
                        if(!$this->$function($v, $errorString)) $ok = false;
                }
                return $ok;
        }
        
        /**
         * Secure a multi-dimensional array or a string
         *
         * @access protected
         * @param mixed $array
         * @return mixed
         */ 
        protected function _secureArray($input) {
                $return = '';
                if(is_array($input)) {
                        $return = array();
                        foreach($input as $k => $v) {
                                if(is_array($v)) {
                                        $return[$k] = $this->_secureArray($v);
                                } else {
                                        $return[$k] = htmlentities($v);
                                }
                        }
                } else {
                        $return = htmlentities($input);
                }
                return $return;
        }
        
        /**
         * Add an error string
         * if alternative is given, it will be used in the 'sprintf' statement
         *
         * @access protected
         * @param string $key
         * @param string $string
         * @param string $alternative = ""
         * @return bool (false)
         */
          protected function _addErrorString($key, $string) {
                if(!isset($this->_errorStrings[$key])) {
                        $this->_errorStrings[$key] = array();
                }
                $this->_errorStrings[$key][] = $string;
                return false;
        }
        
        /**
         * This function will return all the error Arrays that are used by the 'check'-methods
         *
         * @access protected
         * @param void
         * @return array
         */
        protected function _getAllErrorArrays() {
                return array('noValue', 'noInt', 'noEmail', 'noRegex', 'equals', 'noEquals', 'noMinLength');
        }
        
        
        /**
         * Process an error
         *
         * @access protected
         * @param string $type
         * @param string $key
         * @param string $errorString
         * @return InputValidator_Abstract
         */
        protected function _processError($type, $key, $errorString) {
                if(isset($this->$type) && is_array($this->$type)) {
                        array_push($this->$type, $key);
                        $this->_addErrorString($key, $errorString);
                }
                return $this;
        }
        
        /**
         * Is called by __call when the user wants to withdraw an error
         *
         * @access protected
         * @param string $method
         * @param array $arg
         * @return string
         */
        protected function _handleFetchError($method, $arg) {
                list($key, $name, $string) = $arg;
                $errorstring = $method . "Error";
                $n = $name != null ? $name : $key;
                $errstr = $string != null ? $string : $this->$errorstring;
                return in_array($key, $this->$var) ? sprintf($errstr, $n) : "";
        }
        
        /**
         * Is called by __call to validate a field.
         *
         * @access protected
         * @param string $method
         * @param array $arg
         * @return mixed
         */
        protected function _handleValidate($method, $arg) {
                $key = $arg[0];
                if(is_array($key) && (count($key) == 1 || count($key) == 2)) {
                        return $this->_handleArray($key, $method, $arg[1]);
                } else {
                        if(is_bool($key)) {
                                if(!in_array($method, $this->_boolFunctions)) 
                                        return false;
                        } elseif(!$this->exists($key) && $method != "_Validate_isset") {
                                return false;
                        }
                        if(!call_user_func_array(array($this, $method), $arg)) {
                                return $this->_addErrorString($key, end($arg));
                        }
                }
                return true;
        }
        
        /**
         * The __call method is used to process to situations:
         * - if you want to check for errors
         * - if you want to withdraw the errors
         * 
         * @access protected
         * @param string $method
         * @param array $arg
         * @return mixed
         */
        protected function __call($method, $arg) {
                
                $validateMethod = '_Validate_' . $method;
                /*
                 if the method exists "_Validate_' . $method" try to call it with 2 or 3 arguments
                 the rest will be handled as a public method itself, and not via __call
                */
                if(method_exists($this, $validateMethod)) {
                        return $this->_handleValidate($validateMethod, $arg);
                }
                /*
                 Otherwise lets see if the requested array is set, if the call is for example:
                 _noInt('age', 'leeftijd', '%s moet een getal zijn')
                */
                $var = '_' . $method;
                if(isset($this->$var) && is_array($this->$var) && $this->$var != $this->_array) {
                        return $this->_handleFetchError($method, $arg);
                }
                return null;
        }

}

?>

Add new methods to this class to validate.

<?php

/**
 * @package DP_InputValidator
 *
 */

class DP_InputValidator extends DP_InputValidator_Abstract {
        
        /**
         * All error arrays
         *
         * @access protected
         * @var array $_noValue
         * @var array $_noInt
         * @var array $_noEmail
         * @var array $_noRegex
         * @var array $_equals
         * @var array $_noEquals
         * @var array $_noMinLength
         */
        
        protected $_noValue = array();
        protected $_noInt = array();
        protected $_noEmail = array();
        protected $_noRegex = array();
        protected $_equals = array();
        protected $_noEquals = array();
        protected $_noMinLength = array();
        protected $_noIsset = array();
        
        /**
         * An array of all the functions that accept a boolean instead of a key.
         * 
         * @access protected
         * @var array $_boolFunctions
         */
        
        protected $_boolFunctions = array('_Validate_matchBool');
        
        /**
         * Pass through to the Parent Constructor
         *
         * @param array &$array
         * @param bool $safe
         */     
        
        public function __construct(&$array, $safe = true) {
                parent::__construct($array, $safe);
        }
 
        /**
         * Does an array key exist
         *
         * @param string $key
         * @return bool
         */ 
        public function exists($key) {
                if(is_string($key) || is_int($key)) {
                        return array_key_exists($key, $this->_array);
                }
                return true;
        }
        
        /**
         * Does it have a value?
         *
         * @access protected
         * @param string $key
         * @return bool
         */ 
        public function _Validate_hasValue($key) {
                return ($this->_array[$key] != "");
        }
        
        /**
         * Is it an integer?
         *
         * @access protected
         * @param string $key
         * @return bool
         */ 
        public function _Validate_isInt($key) {
                return (strval(intval($this->_array[$key])) == $this->_array[$key]);
        }
        
        /**
         * Is it a valid email?
         *
         * @access protected
         * @param string $key
         * @return bool
         */ 
        public function _Validate_isEmail($key) {         
                if(!validateEmailFormat($this->_array[$key])) { // ADD YOUR OWN EMAIL VALIDATION FUNCTION HERE
                        return ($this->_array[$key] == '');
                }
                
                return true;
        }
        
        /**
         * Is it a valid url?
         *
         * @access protected
         * @param string $key
         * @return bool
         */
        public function _Validate_isUrl($key) {
                if(!validateUrlFormat($this->_array[$key])) {
                        return ($this->_array[$key] == '');
                }
                
                return true;
        }
        
        /**
         * Is it set?
         * 
         * @access protected
         * @param string $key
         * @return  bool
         */
        public function _Validate_isset($key) {
                return isset($this->_array[$key]); 
        }
        
        /**
         * Does it match a given regex?
         * 
         * @access protected
         * @param mixed $key
         * @param string $match
         * @return bool
         */ 
        public function _Validate_matchRegex($key, $match) {
                
                return (preg_match($match, $this->_array[$key]));
                
        }
        
        /**
         * Does it equals '$value'?
         * 
         * @access public
         * @param mixed $key
         * @param string $value
         * @param bool $case
         * @return bool
         */      
        public function _Validate_equals($key, $value, $case) {            
                if($case == false) {
                        return (strtolower($this->_array[$key]) === strtolower($value));
                }
                return ($this->_array[$key] === $value);
                        
        }
        
        /**
         * Does the length differs from '$value'?
         * 
         * @access public
         * @param mixed $key
         * @param string $value
         * @return bool
         */      
        public function _Validate_noEquals($key, $value) {
                
                return ($this->_array[$key] === $value);
        }
        
        /**
         * Is the length longer than $length?
         * 
         * @access public
         * @param mixed $key
         * @param string $value
         * @return bool
         */
        public function _Validate_hasMinLength($key, $length) {
                
                return (strlen(trim($this->_array[$key])) >= $length);
                
        }       
        
        /**
         * Is a bool true or false
         * USE:
         * $pv->matchBool(memberCheck($pv->get('member')), 'The member is already registered')
         * 
         * @access public
         * @param mixed $key
         * @return bool
         */ 
        public function _Validate_matchBool($bool) {
                return $bool ? true : false;
        }

}

?>
Last modified on 16 July 2009, at 20:51