PHP Programming/OOP5/Advanced Input validation
<?php
/* created by nemesiskoen */
$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;
}
}
?>