classes/yf_validate.class.php
<?php
/**
* Validation common methods, part of this was inspired by codeigniter 2.1 form_validate.
*/
class yf_validate
{
/** @var int Minimal nick length */
public $MIN_NICK_LENGTH = 2;
/** @var array Allowed nick symbols (display for user) */
public $NICK_ALLOWED_SYMBOLS = ['a-z', '0-9', '_', '\-', '@', '#', ' '];
/** @var array Reserved words for the profile url (default) */
public $reserved_words = ['login', 'logout', 'admin', 'admin_modules', 'classes', 'modules', 'functions', 'uploads', 'fonts', 'pages_cache', 'core_cache', 'templates'];
/**
* Catch missing method call.
* @param mixed $name
* @param mixed $args
*/
public function __call($name, $args)
{
return main()->extend_call($this, $name, $args);
}
/***/
public function _init()
{
$this->MB_ENABLED = _class('utf8')->MULTIBYTE;
$this->db = db();
}
/***/
public function _prepare_reserved_words()
{
if ($this->_reserved_words_prepared) {
return $this->reserved_words;
}
$user_modules = main()->get_data('user_modules');
// Merge them with default ones
if (is_array($user_modules)) {
$this->reserved_words = array_merge($this->reserved_words, $user_modules);
}
$this->_reserved_words_prepared = true;
return $this->reserved_words;
}
/**
* Method by form-less checking of any custom data for validity.
* @param mixed $input
* @param mixed $validate_rules
*/
public function _input_is_valid($input, $validate_rules = [])
{
if ( ! is_array($input)) {
$input = ['input' => $input];
}
$rules = [];
$global_rules = isset($this->_params['validate']) ? $this->_params['validate'] : $this->_replace['validate'];
foreach ((array) $global_rules as $name => $_rules) {
$rules[$name] = $_rules;
}
if ( ! is_array($validate_rules)) {
$validate_rules = ['__before__' => $validate_rules];
}
foreach ((array) $validate_rules as $name => $_rules) {
$rules[$name] = $_rules;
}
$rules = $this->_validate_rules_cleanup($rules);
$ok = $this->_do_check_data_is_valid($rules, $input);
return (bool) $ok;
}
/**
* @param mixed $func
* @param mixed $data
*/
public function _apply_existing_func($func, $data)
{
if (is_array($data)) {
$self = __FUNCTION__;
foreach ($data as $k => $v) {
$data[$k] = $this->$self($func, $v);
}
return $data;
}
return $func($data);
}
/**
* @param mixed $rules
*/
public function _do_check_data_is_valid($rules = [], &$data)
{
$validate_ok = true;
$_all = '__all__';
if (isset($rules[$_all])) {
$rules_for_all = $rules[$_all];
foreach ((array) $data as $name => $_tmp) {
if (isset($rules[$name])) {
foreach ((array) $rules_for_all as $_rule) {
$rules[$name][] = $_rule;
}
} else {
$rules[$name] = $rules_for_all;
}
}
unset($rules[$_all]);
}
foreach ((array) $rules as $name => $_rules) {
$is_required = false;
foreach ((array) $_rules as $rule) {
if (is_string($rule[0]) && substr($rule[0], 0, strlen('required')) === 'required') {
$is_required = true;
break;
}
}
foreach ((array) $_rules as $rule) {
$is_ok = true;
$error_msg = '';
$func = $rule[0];
$param = $rule[1];
// PHP pure function, from core or user
if (is_string($func) && function_exists($func)) {
$data[$name] = $this->_apply_existing_func($func, $data[$name], $error_msg);
} elseif (is_callable($func)) {
$is_ok = $func($data[$name], null, $data, $error_msg);
} else {
$is_ok = _class('validate')->$func($data[$name], ['param' => $param], $data, $error_msg);
if ( ! $is_ok && empty($error_msg)) {
$error_msg = t('form_validate_' . $func, ['%field' => $name, '%param' => $param]);
}
}
// In this case we do not track error if field is empty and not required
if ( ! $is_ok && ! $is_required && ! strlen($data[$name])) {
$is_ok = true;
$error_msg = '';
}
if ( ! $is_ok) {
$validate_ok = false;
if ( ! $error_msg) {
$error_msg = 'Wrong field ' . $name;
}
_re($error_msg, $name);
// In case when we see any validation rule is not OK - we stop checking further for this field
continue 2;
}
}
}
return $validate_ok;
}
/**
* Examples of validate rules setting:
* 'name1' => 'trim|required',
* 'name2' => array('trim', 'required'),
* 'name3' => array('trim|required', 'other_rule|other_rule2|other_rule3'),
* 'name4' => array('trim|required', function() { return true; } ),
* 'name5' => array('trim', 'required', function() { return true; } ),
* 'name6,name7,name8' => array('trim', 'required', function() { return true; } ),
* '__before__' => 'trim',
* '__after__' => 'some_method2|some_method3',.
* @param mixed $validate_rules
*/
public function _validate_rules_cleanup($validate_rules = [])
{
// Trim names with spaces
foreach ((array) $validate_rules as $name => $raw) {
$trimmed = trim($name);
$tlen = strlen($trimmed);
if ($trimmed === $name && $tlen) {
continue;
}
if ($tlen) {
$validate_rules[$trimmed] = $raw;
}
unset($validate_rules[$name]);
}
// Prepare rule keys, containing several keys, splitted by comma. Example: "test1,test2,test3" => 'required'
foreach ((array) $validate_rules as $name => $raw) {
if (strpos($name, ',') === false) {
continue;
}
foreach (explode(',', trim($name)) as $_name) {
$_name = trim($_name);
if ( ! strlen($_name)) {
continue;
}
// Merge with existing rules with same key, for example we want to mass add some more rule to existing.
if (isset($validate_rules[$_name])) {
if ( ! is_array($validate_rules[$_name])) {
$validate_rules[$_name] = [$validate_rules[$_name]];
}
$validate_rules[$_name] = array_merge($validate_rules[$_name], is_array($raw) ? $raw : [$raw]);
} else {
$validate_rules[$_name] = $raw;
}
}
unset($validate_rules[$name]);
}
// Add these rules to all validation rules, before them
$_name = '__before__';
$all_before = [];
if (isset($validate_rules[$_name])) {
$all_before = (array) $this->_validate_rules_array_from_raw($validate_rules[$_name]);
unset($validate_rules[$_name]);
}
// Add these rules to all validation rules, after them
$_name = '__after__';
$all_after = [];
if (isset($validate_rules[$_name])) {
$all_after = (array) $this->_validate_rules_array_from_raw($validate_rules[$_name]);
unset($validate_rules[$_name]);
}
unset($_name);
// Special case when only __before__ or __after__ passed
if (( ! empty($all_after) || ! empty($all_before)) && empty($validate_rules)) {
$validate_rules = ['__all__' => ''];
}
$out = [];
foreach ((array) $validate_rules as $name => $raw) {
$is_html_array = (false !== strpos($name, '['));
if ($is_html_array) {
$name = str_replace(['[', ']'], ['.', ''], trim($name, ']['));
}
$rules = (array) $this->_validate_rules_array_from_raw($raw);
if ($all_before) {
$tmp = $all_before;
foreach ((array) $rules as $_item) {
$tmp[] = $_item;
}
$rules = $tmp;
unset($tmp);
}
if ($all_after) {
$tmp = $rules;
foreach ((array) $all_after as $_item) {
$tmp[] = $_item;
}
$rules = $tmp;
unset($tmp);
}
// Here we do last parse of the rules params like 'matches[user.email]' into rule item array second element
foreach ((array) $rules as $k => $rule) {
if ( ! is_string($rule[0])) {
continue;
}
$val = trim($rule[0]);
$param = null;
// Parsing these: min_length:6, matches:form_item, is_unique:table.field
// skip regex
if (strpos($val, ':') !== false && substr($val, -1) != ']') {
if (strpos($val, 'regex') !== false || strpos($val, 'regex_match') !== false) {
list($_val, $param) = explode(':', $val, 2);
} else {
list($_val, $param) = explode(':', $val);
}
$param = trim($param);
$val = trim($_val);
// Parsing these: min_length[6], matches[form_item], is_unique[table.field]
} elseif (strpos($val, '[') !== false) {
list($_val, $param) = explode('[', $val);
$param = trim(trim(trim($param), ']['));
$val = trim($_val);
}
if ( ! is_callable($val) && empty($val)) {
unset($rules[$k]);
continue;
}
$rules[$k] = [
0 => $val,
1 => $param,
];
}
if ($rules) {
$out[$name] = array_values($rules); // array_values needed here to make array keys straight, unit tests will pass fine
}
}
return $out;
}
/**
* This method used by validate() function to do standalone validation processing.
* @param mixed $raw
*/
public function _validate_rules_array_from_raw($raw = '')
{
$rules = [];
// esxape '|' to '\|'
$delimeter = '|';
$delimeter_regexp = '~(?<![^\\\]\\\)' . preg_quote($delimeter, '~') . '~';
// At first, we merging all rules sets variants into one array
if (is_string($raw)) {
// foreach((array)explode('|', $raw) as $_item) {
foreach ((array) preg_split($delimeter_regexp, $raw) as $_item) {
$_item = str_replace('\|', '|', $_item);
$rules[] = [$_item, null];
}
} elseif (is_array($raw)) {
foreach ((array) $raw as $_raw) {
if (is_string($_raw)) {
// foreach((array)explode('|', $_raw) as $_item) {
foreach ((array) preg_split($delimeter_regexp, $_raw) as $_item) {
$_item = str_replace('\|', '|', $_item);
$rules[] = [$_item, null];
}
} elseif (is_callable($_raw)) {
$rules[] = [$_raw, null];
}
}
} elseif (is_callable($raw)) {
$rules[] = [$raw, null];
}
return $rules;
}
/**
* Returns md5() from input string, or null. Usually used to update password inside admin panel or not change it if new value not passed.
* Example: ["password" => 'trim|min_length[6]|max_length[32]|password_update'].
*/
public function password_update(&$in)
{
if ( ! strlen($in)) {
$in = null; // Somehow unset($in) not working here...
} else {
$in = md5($in);
}
return true;
}
/**
* Returns md5() from given input string, only if not empty.
* Example usage: ["password" => 'trim|min_length[6]|max_length[32]|md5_not_empty'].
*/
public function md5_not_empty(&$in)
{
if (strlen($in)) {
$in = md5($in);
}
return true;
}
/**
* Returns hash() from given input string, only if not empty. Get list of available algorithms by running: php -r 'echo implode(" ", hash_algos());'.
* Most popular are: md5 sha1 sha224 sha256 sha384 sha512 ripemd128 ripemd160 ripemd256 ripemd320 gost crc32
* Example usage: ["password" => 'trim|min_length[6]|max_length[32]|hash_not_empty[sha256]'].
* @param mixed $params
*/
public function hash_not_empty(&$in, $params = [])
{
$hash_name = is_array($params) ? $params['param'] : $params;
if (strlen($in) && $hash_name) {
$in = hash($hash_name, $in);
}
return true;
}
/**
* Returns FALSE if form field is empty.
* @param mixed $in
*/
public function required($in)
{
if (is_array($in)) {
$func = __FUNCTION__;
foreach ($in as $v) {
$result = $this->$func($v);
if ($result) {
return true;
}
}
return false;
}
return trim($in) !== '';
}
/**
* Returns true when selected other passed field will be non-empty
* Examples: required_if[other_field].
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function required_if($in, $params = [], $fields = [])
{
$param = trim(is_array($params) ? $params['param'] : $params);
if ( ! strlen($param)) {
return false;
}
if (isset($fields[$param]) && ! empty($fields[$param])) {
return $this->required($in);
}
return true;
}
/**
* Returns true when _ANY_ of passed fields will be non-empty
* Examples: required_any[duration_*] or required_any[duration_day,duration_week,duration_month].
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function required_any($in, $params = [], $fields = [])
{
$param = trim(is_array($params) ? $params['param'] : $params);
$wildcard = false;
// Example: duration_day,duration_week,duration_month
if (false !== strpos($param, ',')) {
$field_names = explode(',', $param);
// Example: duration_*
} else {
$wildcard = $param;
}
foreach ((array) $fields as $k => $v) {
$skip = true;
if ($wildcard && wildcard_compare($wildcard, $k)) {
$skip = false;
} elseif ($field_names && in_array($k, $field_names)) {
$skip = false;
}
if ($skip) {
continue;
}
if ($this->required($v)) {
return true;
}
}
return false;
}
/**
* Returns FALSE if field does not match field(s) in parameter.
* Example: matches[password_again].
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function matches($in, $params = [], $fields = [])
{
$field = is_array($params) ? $params['param'] : $params;
return isset($fields[$field], $_POST[$field]) ? ($in === $_POST[$field]) : false;
}
/**
* Returns FALSE if form field(s) defined in parameter are not filled in.
* Example: depends_on[field_name].
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function depends_on($in, $params = [], $fields = [])
{
$field = is_array($params) ? $params['param'] : $params;
return isset($fields[$field], $_POST[$field]);
}
/**
* The field under validation must be a valid URL according to the checkdnsrr PHP function.
* @param mixed $in
*/
public function active_url($in)
{
return checkdnsrr(str_replace(['http://', 'https://', 'ftp://'], '', strtolower($in)));
}
/**
* The field under validation must be a value after a given date. The dates will be passed into the PHP strtotime function.
* Examples: after_date[2012-01-01], after_date[day ago].
* @param mixed $in
* @param mixed $params
*/
public function after_date($in, $params = [])
{
$param = is_array($params) ? $params['param'] : $params;
if ( ! $param) {
return false;
}
if (isset($params['format'])) {
return DateTime::createFromFormat($params['format'], $in) > DateTime::createFromFormat($params['format'], $param);
}
$date = strtotime($param);
if ( ! $date) {
return strtotime($in) > strtotime($this->getValue($param));
}
return strtotime($in) > $date;
}
/**
* The field under validation must be a value preceding the given date. The dates will be passed into the PHP strtotime function.
* Example: before_date[2020-12-31], after_date[+1 day].
* @param mixed $in
* @param mixed $params
*/
public function before_date($in, $params = [])
{
$param = is_array($params) ? $params['param'] : $params;
if ( ! $param) {
return false;
}
if (isset($params['format'])) {
return DateTime::createFromFormat($params['format'], $in) < DateTime::createFromFormat($params['format'], $param);
}
$date = strtotime($param);
if ( ! $date) {
return strtotime($in) < strtotime($this->getValue($param));
}
return strtotime($in) < $date;
}
/**
* The field under validation must be a valid date according to the strtotime PHP function.
* @param mixed $in
*/
public function valid_date($in)
{
if ($in instanceof DateTime) {
return true;
}
if (strtotime($in) === false) {
return false;
}
$date = date_parse($in);
return checkdate($date['month'], $date['day'], $date['year']);
}
/**
* The field under validation must match the format defined according to the date_parse_from_format PHP function.
* @param mixed $in
* @param mixed $params
*/
public function valid_date_format($in, $params = [])
{
$param = is_array($params) ? $params['param'] : $params;
$parsed = date_parse_from_format($param, $in);
return $parsed['error_count'] === 0 && $parsed['warning_count'] === 0;
}
/**
* Returns FALSE if form field is not valid text (letters, numbers, whitespace, dashes, periods and underscores are allowed).
* @param mixed $in
*/
public function standard_text($in)
{
return (bool) preg_match('~^[a-z0-9\s\t,\._-]+$~ims', $in);
}
/**
* The field under validation must have a size between the given min and max. Strings, numerics, and files are evaluated in the same fashion as the size rule.
* Examples: between[a,z] between[44,99].
* @param mixed $in
* @param mixed $params
*/
public function between($in, $params = [])
{
$param = is_array($params) ? $params['param'] : $params;
list($min, $max) = explode(',', $param);
return $in >= $min && $in <= $max;
}
/**
* Returns FALSE if field contains characters not in the parameter.
* Example: chars[a,b,c,d,1,2,3,4].
* @param mixed $in
* @param mixed $params
*/
public function chars($in, $params = [])
{
$param = is_array($params) ? $params['param'] : $params;
$chars = [];
foreach (explode(',', trim($param)) as $char) {
$char = trim($char);
if (strlen($char)) {
$chars[$char] = $char;
}
}
if ( ! count((array) $chars)) {
return false;
}
$regex = '~^[' . preg_quote(implode($chars), '~') . ']+$~ims';
return (bool) preg_match($regex, $in);
}
/**
* Returns TRUE if given field value is unique inside given database table.field
* Examples: is_unique[user.login]
* Alias.
* @param mixed $in
* @param mixed $params
*/
public function unique($in, $params = [])
{
return $this->is_unique($in, $params);
}
/**
* Returns TRUE if given field value is unique inside given database table.field
* Examples: is_unique[user.login].
* @param mixed $in
* @param mixed $params
*/
public function is_unique($in, $params = [])
{
if ( ! $in) {
return true;
}
$param = is_array($params) ? $params['param'] : $params;
if ($param) {
list($check_table, $check_field) = explode('.', $param);
}
if ($check_table && $check_field && $in) {
$exists = $this->db
->select($this->db->es($check_field))
->from($check_table)
->where($this->db->es($check_field), '=', $this->db->es($in))
->get_one();
if ($exists == $in) {
return false;
}
}
return true;
}
/**
* Returns TRUE if given field value is unique inside given database table.field.pk_value
* Examples: is_unique_without[user.id.1].
* @param mixed $in
* @param mixed $params
*/
public function is_unique_without($in, $params = [])
{
if ( ! $in) {
return true;
}
$param = is_array($params) ? $params['param'] : $params;
$id_field = $params['id_field'] ?: 'id';
if ($param) {
list($check_table, $check_field, $check_id) = explode('.', $param);
}
if ($check_table && $check_field && $check_id && $in) {
$exists = $this->db
->select($this->db->es($check_field))
->from($check_table)
->where($this->db->es($check_field), '=', $this->db->es($in))
->where($this->db->es($id_field), '!=', $this->db->es($check_id))
->get_one();
if ($exists == $in) {
return false;
}
}
return true;
}
/**
* Returns TRUE if given field value exists inside database
* Examples: exists[user.email].
* @param mixed $in
* @param mixed $params
*/
public function exists($in, $params = [])
{
if ( ! $in) {
return false;
}
$param = is_array($params) ? $params['param'] : $params;
if ($param) {
list($check_table, $check_field) = explode('.', $param);
}
if ($check_table && $check_field && $in) {
$exists = $this->db
->select($this->db->es($check_field))
->from($check_table)
->where($this->db->es($check_field), '=', $this->db->es($in))
->get_one();
if ($exists == $in) {
return true;
}
}
return false;
}
/**
* Custom regex matching.
* Example: regex_match[/^[a-z0-9]+$/]
* Alias.
* @param mixed $in
* @param mixed $params
*/
public function regex($in, $params = [])
{
return $this->regex_match($in, $params);
}
/**
* Custom regex matching.
* Example: regex_match[/^[a-z0-9]+$/].
* @param mixed $in
* @param mixed $params
*/
public function regex_match($in, $params = [])
{
$regex = is_array($params) ? $params['param'] : $params;
return (bool) preg_match($regex, $in);
}
/**
* Returns TRUE if given field value differs from compared field value
* Example: differs[address_2].
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function differs($in, $params = [], $fields = [])
{
$field = is_array($params) ? $params['param'] : $params;
return ! (isset($fields[$field]) && $_POST[$field] === $in);
}
/**
* Alias.
* @param mixed $in
*/
public function host($in)
{
return $this->valid_hostname($in);
}
/**
* The original specification of hostnames in RFC 952, mandated that labels could not start with a digit or with a hyphen, and must not end with a hyphen.
* However, a subsequent specification (RFC 1123) permitted hostname labels to start with digits.
* http://tools.ietf.org/html/rfc952, http://tools.ietf.org/html/rfc1123
* Each label within a valid hostname may be no more than 63 octets long.
* the total length of the hostname must not exceed 255 characters. For more information, please consult RFC-952 and RFC-1123.
* see also:
* http://stackoverflow.com/questions/106179/regular-expression-to-match-hostname-or-ip-address
* http://data.iana.org/TLD/tlds-alpha-by-domain.txt.
* @param mixed $in
*/
public function valid_hostname($in = '')
{
$len = strlen($in);
if ( ! $len && $len > 255) {
return false;
}
foreach ((array) explode('.', $in) as $v) {
if (strlen($v) > 63) {
return false;
}
}
return (bool) preg_match('/^([a-z0-9]|[a-z0-9][a-z0-9\-]{0,61}[a-z0-9])(\.([a-z0-9]|[a-z0-9][a-z0-9\-]{0,61}[a-z0-9]))*$/i', $in);
}
/**
* Returns TRUE if given field contains valid url. Checking is done in combination of regexp and php built-in filter_val() to ensure most correct results
* Alias.
* @param mixed $in
* @param mixed $params
*/
public function url($in, $params = [])
{
return $this->valid_url($in, $params);
}
/**
* Returns TRUE if given field contains valid url. Checking is done in combination of regexp and php built-in filter_val() to ensure most correct results.
* @param mixed $in
* @param mixed $params
*/
public function valid_url($in, $params = [])
{
if (empty($in)) {
return false;
} elseif (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $in, $matches)) {
if (empty($matches[2])) {
return false;
} elseif ( ! in_array($matches[1], ['http', 'https'], true)) {
return false;
}
$in = $matches[2];
}
$in = 'http://' . $in;
return filter_var($in, FILTER_VALIDATE_URL) !== false;
}
/**
* Returns TRUE if given field contains valid email address. Alias.
* @param mixed $in
*/
public function email($in)
{
return $this->valid_email($in);
}
/**
* Returns TRUE if given field contains valid email address.
* @param mixed $in
*/
public function valid_email($in)
{
return (bool) filter_var($in, FILTER_VALIDATE_EMAIL);
}
/**
* Returns TRUE if given field contains several valid email addresses.
* @param mixed $in
*/
public function valid_emails($in)
{
if ( ! $in) {
return false;
}
if (strpos($in, ',') === false) {
return $this->valid_email(trim($in));
}
foreach (explode(',', $in) as $email) {
if (trim($email) !== '' && $this->valid_email(trim($email)) === false) {
return false;
}
}
return true;
}
/**
* Returns TRUE if given field contains correct base64-encoded string.
* @param mixed $in
*/
public function valid_base64($in)
{
return strlen($in) && (base64_encode(base64_decode($in)) === $in);
}
/**
* Returns TRUE if given field contains valid IP address, ipv4 by default, ipv6 supported too.
* @param mixed $in
* @param mixed $params
*/
public function valid_ip($in, $params = [])
{
$which = is_array($params) ? $params['param'] : $params;
return $this->_valid_ip($in, $which);
}
/**
* Returns TRUE if given field length is no more than specified, excluding exact length.
* Example: min_length[10].
* @param mixed $in
* @param mixed $params
*/
public function min_length($in, $params = [])
{
$val = is_array($params) ? $params['param'] : $params;
if ( ! is_numeric($val)) {
return false;
}
$val = (int) $val;
return ($this->MB_ENABLED == 1) ? ($val <= mb_strlen($in)) : ($val <= strlen($in));
}
/**
* Returns TRUE if given field length is more than specified, including exact length.
* Example: max_length[10].
* @param mixed $in
* @param mixed $params
*/
public function max_length($in, $params = [])
{
$val = is_array($params) ? $params['param'] : $params;
if ( ! is_numeric($val)) {
return false;
}
$val = (int) $val;
return ($this->MB_ENABLED == 1) ? ($val >= mb_strlen($in)) : ($val >= strlen($in));
}
/**
* Returns TRUE if given field length is more than specified, including exact length.
* Example: exact_length[10].
* @param mixed $in
* @param mixed $params
*/
public function exact_length($in, $params = [])
{
$val = is_array($params) ? $params['param'] : $params;
if ( ! is_numeric($val)) {
return false;
}
$val = (int) $val;
return ($this->MB_ENABLED == 1) ? (mb_strlen($in) === $val) : (strlen($in) === $val);
}
/**
* Returns FALSE if the field is too long or too short.
* Examples: length[1,30] - between 1 and 30 characters long. length[30] - exactly 30 characters long.
* @param mixed $in
* @param mixed $params
*/
public function length($in, $params = [])
{
$val = is_array($params) ? $params['param'] : $params;
if (false === strpos($val, ',')) {
return $this->exact_length($in, $params);
}
list($min, $max) = explode(',', $val);
$min_check = true;
if ($min) {
$min_check = $this->min_length($in, $min);
}
$max_check = true;
if ($max) {
$max_check = $this->max_length($in, $max);
}
return $min_check && $max_check;
return false;
}
/**
* Returns TRUE if given field value is a number and greater than specified, not including exact value
* Example: greater_than[10].
* @param mixed $in
* @param mixed $params
*/
public function greater_than($in, $params = [])
{
$min = is_array($params) ? $params['param'] : $params;
return is_numeric($in) ? ($in > $min) : false;
}
/**
* Alias.
* @param mixed $in
* @param mixed $params
*/
public function gt($in, $params = [])
{
return $this->greater_than($in, $params);
}
/**
* Returns TRUE if given field value is a number and less than specified, not including exact value
* Example: less_than[10].
* @param mixed $in
* @param mixed $params
*/
public function less_than($in, $params = [])
{
$max = is_array($params) ? $params['param'] : $params;
return is_numeric($in) ? ($in < $max) : false;
}
/**
* Alias.
* @param mixed $in
* @param mixed $params
*/
public function lt($in, $params = [])
{
return $this->less_than($in, $params);
}
/**
* Returns TRUE if given field value is a number and greater than specified, including exact value
* Example: greater_than_equal_to[10].
* @param mixed $in
* @param mixed $params
*/
public function greater_than_equal_to($in, $params = [])
{
$min = is_array($params) ? $params['param'] : $params;
return is_numeric($in) ? ($in >= $min) : false;
}
/**
* Alias.
* @param mixed $in
* @param mixed $params
*/
public function gte($in, $params = [])
{
return $this->greater_than_equal_to($in, $params);
}
/**
* Returns TRUE if given field value is a number and less than specified, including exact value
* Example: less_than_equal_to[10].
* @param mixed $in
* @param mixed $params
*/
public function less_than_equal_to($in, $params = [])
{
$max = is_array($params) ? $params['param'] : $params;
return is_numeric($in) ? ($in <= $max) : false;
}
/**
* Alias.
* @param mixed $in
* @param mixed $params
*/
public function lte($in, $params = [])
{
return $this->less_than_equal_to($in, $params);
}
/**
* Returns TRUE if given field value contains only latin1 letters, lower and uppercase allowed.
* @param mixed $in
*/
public function alpha($in)
{
return ctype_alpha($in);
}
/**
* Returns TRUE if given field value contains only latin1 letters, lower and uppercase allowed, and digits.
* @param mixed $in
*/
public function alpha_numeric($in)
{
if (is_array($in) || is_object($in) || (is_callable($in) && ! function_exists($in))) {
return false;
}
return ctype_alnum((string) $in);
}
/**
* Returns TRUE if given field value contains only latin1 letters, lower and uppercase allowed, and spaces.
* @param mixed $in
*/
public function alpha_spaces($in)
{
return (bool) preg_match('/^[A-Z ]+$/i', $in);
}
/**
* Returns TRUE if given field value contains only latin1 letters, lower and uppercase allowed, and spaces and digits.
* @param mixed $in
*/
public function alpha_numeric_spaces($in)
{
return (bool) preg_match('/^[A-Z0-9 ]+$/i', $in);
}
/**
* Returns TRUE if given field value contains only latin1 letters, lower and uppercase allowed, and dash and underscore symbols.
* @param mixed $in
*/
public function alpha_dash($in)
{
return (bool) preg_match('/^[a-z0-9_-]+$/i', $in);
}
/**
* Returns TRUE if given field value contains only latin1 letters, lower and uppercase allowed, and dash and underscore and dots symbols.
* @param mixed $in
*/
public function alpha_dash_dots($in)
{
return (bool) preg_match('/^[a-z0-9_\.-]+$/i', $in);
}
/**
* Same as alpha(), but including unicode characters too.
* @param mixed $in
*/
public function unicode_alpha($in)
{
return (bool) preg_match('/^[\pL\pM]+$/u', $in);
}
/**
* Same as alpha_numeric(), but including unicode characters too.
* @param mixed $in
*/
public function unicode_alpha_numeric($in)
{
return (bool) preg_match('/^[\pL\pM\pN]+$/u', $in);
}
/**
* Same as alpha_spaces(), but including unicode characters too.
* @param mixed $in
*/
public function unicode_alpha_spaces($in)
{
return (bool) preg_match('/^[\pL\pM\s]+$/u', $in);
}
/**
* Same as alpha_numeric_spaces(), but including unicode characters too.
* @param mixed $in
*/
public function unicode_alpha_numeric_spaces($in)
{
return (bool) preg_match('/^[\pL\pM\pN\s]+$/u', $in);
}
/**
* Same as alpha_dash(), but including unicode characters too.
* @param mixed $in
*/
public function unicode_alpha_dash($in)
{
return (bool) preg_match('/^[\pL\pM\pN_-]+$/u', $in);
}
/**
* Returns TRUE if given field value contains only numbers, including integers, floats and decimals.
* @param mixed $in
*/
public function numeric($in)
{
return (bool) preg_match('/^[\-+]?[0-9]*\.?[0-9]+$/', $in);
}
/**
* Returns TRUE if given field value contains only integers.
* @param mixed $in
*/
public function integer($in)
{
return (bool) preg_match('/^[\-+]?[0-9]+$/', $in);
}
/**
* Returns TRUE if given field value contains only decimals.
* @param mixed $in
*/
public function decimal($in)
{
return (bool) preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $in);
}
/**
* Returns TRUE if given field value contains only numbers that are natural.
* @param mixed $in
*/
public function is_natural($in)
{
return ctype_digit((string) $in);
}
/**
* Returns TRUE if given field value contains only numbers that are natural except 0.
* @param mixed $in
*/
public function is_natural_no_zero($in)
{
return $in != 0 && ctype_digit((string) $in);
}
/**
* Do url preparation, not validates anything.
* @param mixed $in
*/
public function prep_url($in)
{
if ($in === 'http://' or $in === '') {
return '';
}
if (strpos($in, 'http://') !== 0 && strpos($in, 'https://') !== 0) {
return 'http://' . $in;
}
return $in;
}
/**
* Returns TRUE is captcha user input value is valid.
* @param mixed $in
*/
public function captcha($in)
{
return _class('captcha')->check('captcha', $in);
}
/**
* Clean string from possible XSS, using security class.
* @param mixed $in
*/
public function xss_clean($in)
{
return _class('security')->xss_clean($in);
}
/**
* Internal IP validity checking method.
* @param mixed $ip
* @param mixed $ip_version
*/
public function _valid_ip($ip, $ip_version = 'ipv4')
{
$ip_version = strtolower($ip_version);
if ( ! $ip_version) {
$ip_version = 'ipv4';
}
if ($ip_version == 'ipv6') {
$filter_flag = FILTER_FLAG_IPV6;
} else {
$filter_flag = FILTER_FLAG_IPV4;
}
return (bool) filter_var($ip, FILTER_VALIDATE_IP, $filter_flag);
}
/**
* Cleanup input phone to match international notation. Examples good: +380631234567, 063 123 45 67. See more valid examples inside unit tests.
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function phone_cleanup($in, $params = [], $fields = [], &$error = '')
{
$error = false;
$country_prefix = $params['param'] ?: '38';
$p_len = strlen($country_prefix);
$phone = preg_replace('/[^0-9]+/ims', '', strip_tags($in));
if (strlen($phone) == 10) { // 063 123 45 67 (spaces here for example readability)
$phone = '+' . $country_prefix . $phone;
} elseif (strlen($phone) == 9) { // 63 123 45 67 (spaces here for example readability)
$phone = '+' . $country_prefix . '0' . $phone;
} elseif (strlen($phone) == (10 + $p_len)) {
if (substr($phone, 0, $p_len) != $country_prefix) {
$error = t('phone error: incorrect country') . ': ' . $phone;
} else {
$phone = '+' . $phone;
}
} else {
$error = t('phone error: number is incorrect') . ': ' . $phone;
$phone = '';
}
$phone = $phone ? '+' . ltrim($phone, '+') : '';
return $phone;
}
/**
* Ensures input phone has valid international format.
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function valid_phone($in, $params = [], $fields = [], &$error = '')
{
$phone = $this->phone_cleanup($in, $params, $fields, $error);
return empty($error) ? true : false;
}
/**
* Check user nick.
* @param mixed $CUR_VALUE
* @param null|mixed $force_value_to_check
* @param mixed $name_in_form
*/
public function _check_user_nick($CUR_VALUE = '', $force_value_to_check = null, $name_in_form = 'nick')
{
// TODO: rewrite me
$TEXT_TO_CHECK = $_POST[$name_in_form];
if ($force_value_to_check !== null) {
$TEXT_TO_CHECK = $force_value_to_check;
$OVERRIDE_MODE = true;
}
$_nick_pattern = implode('', $this->NICK_ALLOWED_SYMBOLS);
if (empty($TEXT_TO_CHECK) || (strlen($TEXT_TO_CHECK) < $this->MIN_NICK_LENGTH)) {
_re(t('Nick must have at least @num symbols', ['@num' => $this->MIN_NICK_LENGTH]));
} elseif ( ! preg_match('/^[' . $_nick_pattern . ']+$/iu', $TEXT_TO_CHECK)) {
_re(t('Nick can contain only these characters: @text1', ['@text1' => _prepare_html(stripslashes(implode('" , "', $this->NICK_ALLOWED_SYMBOLS)))]));
if ( ! $OVERRIDE_MODE) {
$_POST[$name_in_form] = preg_replace('/[^' . $_nick_pattern . ']+/iu', '', $_POST[$name_in_form]);
}
} elseif ($TEXT_TO_CHECK != $CUR_VALUE) {
// TODO: convert into query buidler
$NICK_ALREADY_EXISTS = ($this->db->query_num_rows('SELECT id FROM ' . $this->db->_real_name('user') . ' WHERE nick="' . $this->db->es($TEXT_TO_CHECK) . '"') >= 1);
if ($NICK_ALREADY_EXISTS) {
_re(t('Nick "@name" is already reserved. Please try another one.', ['@name' => $TEXT_TO_CHECK]));
}
}
}
/**
* Check user profile url.
* @param mixed $CUR_VALUE
* @param null|mixed $force_value_to_check
* @param mixed $name_in_form
*/
public function _check_profile_url($CUR_VALUE = '', $force_value_to_check = null, $name_in_form = 'profile_url')
{
// TODO: rewrite me
$TEXT_TO_CHECK = $_POST[$name_in_form];
// Override value to check
if ($force_value_to_check !== null) {
$TEXT_TO_CHECK = $force_value_to_check;
$OVERRIDE_MODE = true;
}
// Ignore empty values
if (empty($TEXT_TO_CHECK)) {
return false;
}
$this->_prepare_reserved_words();
if ( ! empty($CUR_VALUE)) {
_re('You have already chosen your profile url. You are not allowed to change it!');
} elseif ( ! preg_match('/^[a-z0-9]{0,64}$/ims', $TEXT_TO_CHECK)) {
_re('Wrong Profile url format! Letters or numbers only with no spaces');
} elseif (in_array($TEXT_TO_CHECK, $this->reserved_words)) {
_re('This profile url ("' . $TEXT_TO_CHECK . '") is our site reserved name. Please try another one.');
// TODO: convert into query buidler
} elseif ($this->db->query_num_rows('SELECT id FROM ' . $this->db->_real_name('user') . ' WHERE profile_url="' . $this->db->es($TEXT_TO_CHECK) . '"') >= 1) {
_re('This profile url ("' . $TEXT_TO_CHECK . '") has already been registered with us! Please try another one.');
}
}
/**
* Check user login.
*/
public function _check_login()
{
// TODO: rewrite me
if ($_POST['login'] == '') {
_re('Login required');
// TODO: convert into query buidler
} elseif ($this->db->query_num_rows('SELECT id FROM ' . $this->db->_real_name('user') . ' WHERE login="' . $this->db->es($_POST['login']) . '"') >= 1) {
_re('This login ' . $_POST['login'] . ' has already been registered with us!');
}
}
/**
* Check selected location (country, region, city).
* @param mixed $cur_country
* @param mixed $cur_region
* @param mixed $cur_city
*/
public function _check_location($cur_country = '', $cur_region = '', $cur_city = '')
{
// TODO: rewrite me
if (FEATURED_COUNTRY_SELECT && ! empty($_POST['country']) && substr($_POST['country'], 0, 2) == 'f_') {
$_POST['country'] = substr($_POST['country'], 2);
}
if ( ! empty($_POST['country'])) {
if ( ! isset($GLOBALS['countries'])) {
$GLOBALS['countries'] = main()->get_data('countries');
}
if ( ! isset($GLOBALS['countries'][$_POST['country']])) {
$_POST['country'] = '';
$_POST['region'] = '';
$_POST['state'] = '';
$_POST['city'] = '';
} else {
$GLOBALS['_country_name'] = $GLOBALS['countries'][$_POST['country']];
}
}
if ( ! empty($_POST['region'])) {
// TODO: convert into query buidler
$region_info = $this->db->query_fetch('SELECT * FROM ' . $this->db->_real_name('geo_regions') . ' WHERE country = "' . $this->db->es($_POST['country']) . '" AND code="' . $this->db->es($_POST['region']) . '"');
if (empty($region_info)) {
$_POST['region'] = '';
$_POST['state'] = '';
$_POST['city'] = '';
} else {
$GLOBALS['_region_name'] = $region_info['name'];
}
}
if ( ! empty($_POST['city'])) {
// TODO: convert into query buidler
$city_info = $this->db->query_fetch('SELECT * FROM ' . $this->db->_real_name('geo_city_location') . ' WHERE region = "' . $this->db->es($_POST['region']) . '" AND country = "' . $this->db->es($_POST['country']) . '" AND city="' . $this->db->es($_POST['city']) . '"');
if (empty($city_info)) {
$_POST['city'] = '';
}
}
}
/**
* Check user birth date.
* @param mixed $CUR_VALUE
*/
public function _check_birth_date($CUR_VALUE = '')
{
// TODO: rewrite me
$_POST['birth_date'] = $CUR_VALUE;
$_POST['year_birth'] = (int) ($_POST['year_birth']);
$_POST['month_birth'] = (int) ($_POST['month_birth']);
$_POST['day_birth'] = (int) ($_POST['day_birth']);
if ($_POST['year_birth'] >= 1915 && $_POST['year_birth'] <= (date('Y') - 17)
&& $_POST['month_birth'] >= 1 && $_POST['month_birth'] <= 12
&& $_POST['day_birth'] >= 1 && $_POST['day_birth'] <= 31
) {
if ($_POST['month_birth'] < 10) {
$_POST['month_birth'] = '0' . $_POST['month_birth'];
}
if ($_POST['day_birth'] < 10) {
$_POST['day_birth'] = '0' . $_POST['day_birth'];
}
$_POST['birth_date'] = $_POST['year_birth'] . '-' . $_POST['month_birth'] . '-' . $_POST['day_birth'];
}
if ( ! empty($_POST['birth_date'])) {
$_POST['age'] = _get_age_from_birth($_POST['birth_date']);
}
}
/**
* Internal method.
* @param mixed $email
* @param mixed $check_mx
* @param mixed $check_by_smtp
* @param mixed $check_blacklists
*/
public function _email_verify($email = '', $check_mx = false, $check_by_smtp = false, $check_blacklists = false)
{
return _class('remote_files', 'classes/common/')->_email_verify($email, $check_mx, $check_by_smtp, $check_blacklists);
}
/**
* Internal method.
* @param mixed $url
*/
public function _validate_url_by_http($url)
{
return _class('remote_files', 'classes/common/')->_validate_url_by_http($url);
}
/**
* Alias.
* @param mixed $in
*/
public function _url_verify($in = '')
{
return $this->valid_url($in);
}
/**
* Alias.
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function valid_image($in, $params = [], $fields = [])
{
return $this->image($in, $params, $fields);
}
/**
* The file under validation must be an image (jpeg, png, bmp, or gif).
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function image($in, $params = [], $fields = [])
{
// TODO
}
/**
* The file under validation must have a MIME type corresponding to one of the listed extensions. mime:jpeg,bmp,png.
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function mime($in, $params = [], $fields = [])
{
// TODO
}
/**
* Returns FALSE if credit card is not valid.
* Examples: credit_card[mastercard].
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function credit_card($in, $params = [], $fields = [])
{
// TODO
}
/**
* Same as is_unique(), but tells form validator to include ajax form checking.
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function ajax_is_unique($in, $params = [], $fields = [])
{
return $this->is_unique($in, $params, $fields);
}
/**
* Same as is_unique_without(), but tells form validator to include ajax form checking.
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function ajax_is_unique_without($in, $params = [], $fields = [])
{
return $this->is_unique_without($in, $params, $fields);
}
/**
* Same as exists(), but tells form validator to include ajax form checking.
* @param mixed $in
* @param mixed $params
* @param mixed $fields
*/
public function ajax_exists($in, $params = [], $fields = [])
{
return $this->exists($in, $params, $fields);
}
}