3v4l.org

run code in 150+ php & hhvm versions
Bugs & Features
<?php namespace schlaus\schimile; /** * * Schimile is a validation class * */ class schimile { private static $_ruleset = array(); private static $_errorHandler = null; private static $_latestErrors = null; private static $_currentInstance; private $_currentIndex = 0; private $_optional = array(); private $_nextIndex = 0; private $_inputType; private $_not; private $_queue = array(); private $_queueIndex = 0; private $_errors = array(); private $_haltOnError = false; private $_currentValue; private $_currentValidatorAccepts = array("boolean", "integer", "double", "string", "array", "object"); public function __construct($inputType, $index) { $this->_inputType = $inputType; $this->_updateIndex($index); } private function _accept() { $shortForms = array( "arr" => "array", "str" => "string", "bool" => "boolean", "obj" => "object", "int" => "integer", "float" => "double" ); $accepted = func_get_args(); if (empty($accepted)) $accepted = array("bool", "int", "float", "str", "arr", "obj"); if (count($accepted) == 1 && is_string($accepted)) { $accepted = preg_split('/(, |,|\|)/', $accepted, -1, PREG_SPLIT_NO_EMPTY); } elseif (is_array($accepted[0])) { $accepted = $accepted[0]; } foreach ($accepted as &$val) { if (array_key_exists($val, $shortForms)) $val = $shortForms[$val]; } $this->_currentValidatorAccepts = $accepted; } private function _isValidType($var, $accepted) { return in_array(gettype($var), $accepted); } private function _pushToQueue($validator, $nonNegatedMessage, $negatedMessage, $params = array()) { $message = ($this->_not) ? $negatedMessage : $nonNegatedMessage; $this->_queue[$this->_queueIndex][] = array( "validator" => $validator, "message" => $message, "negate" => $this->_not, "inputType" => $this->_inputType, "accepts" => $this->_currentValidatorAccepts, "useIndex" => $this->_currentIndex, "params" => $params ); $this->_accept(); } private function _reset() { $this->_currentIndex = 0; $this->_nextIndex = 0; $this->_queue = array(); $this->_queueIndex = 0; $this->_errors = array(); } public static function assert($ruleset, $input) { if (is_object($ruleset)) { $instance = $ruleset; } elseif (is_string($ruleset) && array_key_exists($ruleset, self::$_ruleset)) { $instance = clone self::$_ruleset[$ruleset]; } else { throw new InvalidArgumentException("Invalid argument provided for schimile::loadRuleset() (Ruleset object or name expected)"); } return $instance->execute($input); } public static function getErrors() { return self::$_latestErrors; } private function _handleErrors() { self::$_latestErrors = $this->_errors; return false; } private function _pushError($item, $message) { $this->_errors[$item][] = $message; } public function execute($input) { foreach ($this->_queue as $index => $testArrays) { foreach ($testArrays as $testNr => $testBlock) { switch ($testBlock['inputType']) { case "input": $value = &$input; break; case "val": if (is_object($input)) { $value =& $input->$testBlock['useIndex']; } else { $value =& $input[$testBlock['useIndex']]; } break; case "key": $value = key($input); break; } $matcher = !$testBlock['negate']; array_unshift($testBlock['params'], $value); if ($this->_isValidType($value, $testBlock['accepts'])) { try { $result = call_user_func_array($testBlock['validator'], $testBlock['params']); if (!is_bool($result)) { $value = $result; $result = true; } } catch (ValidationFailException $e) { $this->_haltOnError = true; $result = null; } } else { throw new InvalidInputTypeException($testBlock['accepts'], $value); } if ($result === $matcher) { //pass } else { //fail $this->_pushError($this->_currentIndex, $testBlock['message']); if ($this->_haltOnError) { break 2; } } } } if (!empty($this->_errors)) { if (is_null(self::$_errorHandler)) return $this->_handleErrors(); else return self::$_errorHandler($this->_errors); } return true; } private function _composite($params) { $not = $this->_not; foreach ($params as $test) { if (isset($test['negate']) && $test['negate']) { $this->isNot(); } else { $this->is(); } $params = (empty($test['params'])) ? array() : $test['params']; call_user_func_array(array($this, $test['test']), $params); } $this->_not = $not; return $this; } public static function registerErrorHandler($fn) { if (is_callable($fn)) { self::$_errorHandler = $fn; } else { throw new InvalidArgumentException("Invalid argument provided for schimile::registerErrorHandler() (Callable expetcer, " . gettype($fn) . " received)."); } } /** * Gets the currently loaded ruleset * @return Array */ public static function getRuleset() { return self::$_ruleset; } public static function loadRuleset($ruleset) { if (is_object($ruleset)) { self::$_ruleset[] = $ruleset; end(self::$_ruleset[]); return key(self::$_ruleset[]); } elseif (is_array($ruleset)) { self::$_ruleset = array_merge(self::$_ruleset, $ruleset); } else { throw new InvalidArgumentException("Invalid argument provided for schimile::loadRuleset() (Array or Object expected, " . gettype($ruleset) . " received)."); } } private static function _init($type, $index = false) { $self = __CLASS__; $self::$_currentInstance = new $self($type, $index); } private function _nextItem($type, $index = false) { $this->_inputType = $type; $this->_queueIndex++; $this->_updateIndex($index); } private function _updateIndex($index) { if ($index === false) { $this->_currentIndex = $this->_nextIndex++; } else { $this->_currentIndex = $index; } } public static function input() { self::_init("input"); return self::$_currentInstance; } public static function val($index = false) { self::_init("val", $index); return self::$_currentInstance; } public function next($index = false) { $this->_updateIndex($index); return $this; } public function arr() { $this->_pushToQueue(function($input) { return is_array($input); }, "{{name}} must be an array", "{{name}} can't be an array"); return $this; } public function top() { $this->_inputType = "input"; $this->_updateIndex(0); return $this; } public function validPer($ruleset) { $this->_pushToQueue(function($input, $ruleset) { $self = __CLASS__; return $self::assert($ruleset, $input); }, "null", "null", array($ruleset)); return $this; } public function is() { $this->_not = false; return $this; } public function isNot() { $this->_not = true; return $this; } public function noneOf() { $rulesets = func_get_args(); $this->_pushToQueue(function($input, $rulesets) { $self = __CLASS__; $status = false; foreach ($rulesets as $ruleset) { $status = ($status || $self::assert($ruleset, $input)); } return !$status; }, "null", "null", array($rulesets)); return $this; } public function allOf() { $rulesets = func_get_args(); $this->_pushToQueue(function($input, $rulesets) { $self = __CLASS__; $status = true; foreach ($rulesets as $ruleset) { $status = ($status && $self::assert($ruleset, $input)); } return $status; }, "null", "null", array($rulesets)); return $this; } public function oneOf() { $rulesets = func_get_args(); $this->_pushToQueue(function($input, $rulesets) { $self = __CLASS__; $status = false; foreach ($rulesets as $ruleset) { $status = ($status || $self::assert($ruleset, $input)); } return $status; }, "null", "null", array($rulesets)); return $this; } public function haltOnFail() { $this->_haltOnError = true; return $this; } public function continueOnFail() { $this->_haltOnError = false; return $this; } public function required() { if ($key = array_search($this->_currentIndex, $this->_optional) !== false) { unset($this->_optional[$key]); } return $this; } public function optional() { $this->_optional[] = $this->_currentIndex; return $this; } public function string() { //$this->_accept("string", $strict); $this->_pushToQueue(function($input) { return is_string($input); }, "{{name}} must be a string", "{{name}} can't be a string"); return $this; } public function int() { $this->_pushToQueue(function($input) { return is_int($input); }, "{{name}} must be an integer", "{{name}} can't be an integer"); return $this; } public function atStart($param) { $this->_pushToQueue(function($input, $param) { return strpos($input, $param) === 0; }, "{{name}} must start with $param", "{{name}} can't start with $param", array($param)); return $this; } public function atEnd($param) { $this->_pushToQueue(function($input, $param) { return substr($haystack, -strlen($needle)) === $needle; }, "{{name}} must end with $param", "{{name}} can't end with $param", array($param)); return $this; } public function contains($param) { $this->_pushToQueue(function($input, $param) { return strpos($input, $param) !== false; }, "{{name}} must start with $param", "{{name}} can't start with $param", array($param)); return $this; } public function like($type, $keepType = true) { $this->_pushToQueue(function($input, $type) { switch($type) { case "float": case "double": $pattern = '/^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/'; break; case "int": case "integer": $pattern = '/^[-+]?[0-9]+$/'; break; default: throw new InvalidInputTypeException("Invalid comparison type provided for schimile->like() operator"); break; } if (preg_match($pattern, $input)) { if ($keepType) return true; if ($type === "float") return (float) $input; return (int) $input; } else { if ($keepType) return false; throw new ValidationFailException(); } }, "{{name}} must be a valid $type", "{{name}} can't be a $type", array($type)); return $this; } public function likeRegex($pattern) { $this->_pushToQueue(function($input, $pattern) { return (bool) preg_match($pattern, $input); }, "{{name}} must match regex $pattern", "{{name}} can't match regex $pattern", array($pattern)); return $this; } public function numeric() { $this->_pushToQueue(function($input) { return is_numeric($input); }, "{{name}} must be numeric", "{{name}} can't be numeric"); return $this; } public function alnum() { $this->_pushToQueue(function($input) { return ctype_alnum($input); }, "{{name}} must consist of only letters and numbers", "{{name}} can't consist of just letters or numbers"); return $this; } public function charList($characters) { $this->_pushToQueue(function($input, $characters) { $incl = array(); $pattern = preg_replace_callback('/([a-z]\-[a-z])|([0-9]\-[0-9])|([A-Z]\-[A-Z])/', function($matches) use (&$incl) { $incl = array_merge($incl, $matches); return ""; }, $characters); $pattern = preg_quote($pattern); $pattern = $pattern . implode("", array_unique($incl)); $pattern = '/^['.$pattern.']+$/'; return (bool) preg_match($pattern, $input); }, "{{name}} can only contain the characters $characters", "{{name}} can't consist entirely of the characters $characters", array($characters)); return $this; } public function lengthBetween($min = 0, $max = null) { $this->_pushToQueue(function($input, $min, $max) { $resultmin = false; $resultmax = false; if (strlen($input) >= $min) $resultmin = true; if ($max === null || strlen($input) <= $max) $resultmax = true; return $resultmin && $resultmax; }, "{{name}} must be between $min and $max characters", "{{name}} can't be between $min and $max characters", array($min, $max)); return $this; } public function email() { $this->_pushToQueue(function($input) { return (bool) preg_match('/^.+@.+\..+$/', $input); }, "{{name}} must be a valid e-mail address", "{{name}} can't be an e-mail address"); return $this; } public function equalTo($comparison, $strict = true) { $this->_pushToQueue(function($input, $comparison, $strict) { if ($strict) { return $input === $comparison; } else { return $input == $comparison; } }, "{{name}} must be equal to $comparison", "{{name}} can't be $comparison", array($comparison, $strict)); return $this; } public function entropyMin($value) { $this->_pushToQueue(function($input, $value) { $h=0; $size = strlen($string); foreach (count_chars($string, 1) as $v) { $p = $v/$size; $h -= $p*log($p)/log(2); } return $h >= $value; }, "{{name}} must be equal to $comparison", "{{name}} can't be $comparison", array($value)); return $this; } }
Output for 5.4.0 - 7.1.0