123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
<?php
/*
UserSpice 4
An Open Source PHP User Management System
by the UserSpice Team at http://UserSpice.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class Validate
{
public
$_errors = [],
$_db = null;
public function __construct() {
$this->_db = DB::getInstance();
}
public function check($source, $items=[], $sanitize=true) {
$this->_errors = [];
foreach ($items as $item => $rules) {
$item = sanitize($item);
$display = $rules['display'];
unset($rules['display']);
foreach ($rules as $rule => $rule_value) {
$value = $source[$item];
if ($sanitize)
$value = sanitize(trim($value));
$length = is_array($value) ? count($value) : strlen($value);
$verb = is_array($value) ? "are" : "is";
if ($rule=='required') {
if ($rule_value && $length==0) $this->addError(["{$display} {$verb} required",$item]);
}
else
if ($length != 0) {
switch ($rule) {
case 'min':
if (is_array($rule_value))
$rule_value = max($rule_value);
if ($length < $rule_value)
$this->addError(["{$display} must be a minimum of {$rule_value} characters",$item]);
break;
case 'max':
if (is_array($rule_value))
$rule_value = min($rule_value);
if ($length > $rule_value)
$this->addError(["{$display} must be a maximum of {$rule_value} characters",$item]);
break;
case 'matches':
if (!is_array($rule_value))
$array = [$rule_value];
foreach ($array as $rule_value)
if ($value != $source[$rule_value])
$this->addError(["{$items[$rule_value]['display']} and {$display} must match",$item]);
break;
case 'unique':
$table = is_array($rule_value) ? $rule_value[0] : $rule_value;
$fields = is_array($rule_value) ? $rule_value[1] : [$item, '=', $value];
if ($this->_db->get($table, $fields)) {
if ($this->_db->count())
$this->addError(["{$display} already exists. Please choose another {$display}",$item]);
} else
$this->addError(["Cannot verify {$display}. Database error",$item]);
break;
case 'unique_update':
$t = explode(',', $rule_value);
$table = $t[0];
$id = $t[1];
$query = "SELECT * FROM {$table} WHERE id != {$id} AND {$item} = '{$value}'";
$check = $this->_db->query($query);
if ($check->count())
$this->addError(["{$display} already exists. Please choose another {$display}",$item]);
break;
case 'is_numeric': case 'is_num':
if ($rule_value && !is_numeric($value))
$this->addError(["{$display} has to be a number. Please use a numeric value",$item]);
break;
case 'valid_email':
if(!filter_var($value,FILTER_VALIDATE_EMAIL))
$this->addError(["{$display} must be a valid email address",$item]);
break;
case '<' :
case '>' :
case '<=' :
case '>=' :
case '!=' :
case '==' :
$array = is_array($rule_value) ? $rule_value : [$rule_value];
foreach ($array as $rule_value)
if (is_numeric($value)) {
$rule_value_display = $rule_value;
if (!is_numeric($rule_value) && isset($source[$rule_value])) {
$rule_value_display = $items[$rule_value]["display"];
$rule_value = $source[$rule_value];
}
if ($rule=="<" && $value>=$rule_value)
$this->addError(["{$display} must be smaller than {$rule_value_display}",$item]);
if ($rule==">" && $value<=$rule_value)
$this->addError(["{$display} must be larger than {$rule_value_display}",$item]);
if ($rule=="<=" && $value>$rule_value)
$this->addError(["{$display} must be equal {$rule_value_display} or smaller",$item]);
if ($rule==">=" && $value<$rule_value)
$this->addError(["{$display} must be equal {$rule_value_display} or larger",$item]);
if ($rule=="!=" && $value==$rule_value)
$this->addError(["{$display} must be different from {$rule_value_display}",$item]);
if ($rule=="==" && $value!=$rule_value)
$this->addError(["{$display} must equal {$rule_value_display}",$item]);
}
else
$this->addError(["{$display} has to be a number. Please use a numeric value",$item]);
break;
case 'is_integer': case 'is_int':
if ($rule_value && filter_var($value, FILTER_VALIDATE_INT)===false)
$this->addError(["{$display} has to be an integer",$item]);
break;
case 'is_timezone':
if ($rule_value)
if (array_search($value, DateTimeZone::listIdentifiers(DateTimeZone::ALL)) === FALSE)
$this->addError(["{$display} has to be a valid time zone name",$item]);
break;
case 'in':
$verb = "have to be";
$list_of_names = []; // if doesn't match then display these in an error message
$list_of_values = []; // to compare it against
if (!is_array($rule_value))
$rule_value = [$rule_value];
foreach($rule_value as $val)
if (!is_array($val)) {
$list_of_names[] = $val;
$list_of_values[] = strtolower($val);
} else
if (count($val) > 0) {
$list_of_names[] = $val[0];
$list_of_values[] = strtolower((count($val)>1 ? $val[1] : $val[0]));
}
if (!is_array($value)) {
$verb = "has to be one of the following";
$value = [$value];
}
foreach ($value as $val) {
if (array_search(strtolower($val), $list_of_values) === FALSE) {
$this->addError(["{$display} {$verb}: ".implode(', ',$list_of_names),$item]);
break;
}
}
break;
case 'is_datetime':
if ($rule_value !== false) {
$object = DateTime::createFromFormat((empty($rule_value) || is_bool($rule_value) ? "Y-m-d H:i:s" : $rule_value), $value);
if (!$object || DateTime::getLastErrors()["warning_count"]>0 || DateTime::getLastErrors()["error_count"]>0)
$this->addError(["{$display} has to be a valid time",$item]);
}
break;
case 'valid_date':
$d = DateTime::createFromFormat('Y-m-d', $value);
if(!($d && $d->format('Y-m-d') == $value)) {
$this->addError(["{$display} must be a date with a format of YYYY-MM-DD.", $item]);
}
break;
case 'valid_month':
$d = DateTime::createFromFormat('F Y', $value);
if(!($d && $d->format('F Y') == $value)) {
$this->addError(["{$display} must be a date with a format of 'Month Year' ('F Y').", $item]);
}
break;
case 'valid_time':
$DateTime = \DateTime::createFromFormat('d/m/Y '.$rule_value, '10/10/2010 '.$value);
if ($DateTime && $DateTime->format('d/m/Y '.$rule_value) == '10/10/2010 '.$value) $valid = true;
else $valid = false;
if($valid != true) {
$this->addError(["{$display} must be a time with a format of HH:MM:SS.", $item]);
}
break;
case 'valid_futuredate':
$today = date("Y-m-d H:i:s");
$checkDate = date('Y-m-d H:i:s', strtotime($value));
if(!($today && $checkDate && $checkDate > $today)) {
$this->addError(["{$display} must be a date in the future.", $item]);
}
break;
case 'in_array':
if (!in_array($value, array_flip($rule_value))) {
$allowed = '<ul>';
foreach ($rule_value as $rule => $ruleDescription) {
$allowed .= "<li>{$ruleDescription}</li>";
}
$allowed .= '</ul>';
$this->addError(["{$display} must be any of these values: {$allowed}", $item]);
}
break;
}
}
}
}
return $this;
}
public function addError($error) {
if (array_search($error, $this->_errors) === FALSE)
$this->_errors[] = $error;
}
public function display_errors() {
$html = "<UL CLASS='bg-danger'>";
foreach($this->_errors as $error) {
if (is_array($error))
$html .= "<LI CLASS='text-danger'>{$error[0]}</LI>
<SCRIPT>jQuery('document').ready(function(){jQuery('#{$error[1]}').parent().closest('div').addClass('has-error');});</SCRIPT>";
else
$html .= "<LI CLASS='text-danger'>{$error}</LI>";
}
$html .= "</UL>";
return $html;
}
public function errors(){
return $this->_errors;
}
public function passed(){
return empty($this->_errors) ? 'true' : false;
}
}