. */ 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 = '