From 75a77d7a09c38ad0ef60420ea4fd9e630f76bb74 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 14 Dec 2025 15:31:30 -0500 Subject: [PATCH] better defaults --- src/bootstrap/safer_io.php | 27 ++++ .../attributes/validators/my_validator.php | 12 +- src/classes/traits/form_validator.php | 139 +++++++++--------- 3 files changed, 106 insertions(+), 72 deletions(-) diff --git a/src/bootstrap/safer_io.php b/src/bootstrap/safer_io.php index ec84d6f..f3a243b 100644 --- a/src/bootstrap/safer_io.php +++ b/src/bootstrap/safer_io.php @@ -43,6 +43,7 @@ final class use_io { public $input_type; public $field_filter; public $escape_html; + public bool $error_on_null = false; public $validation_rule; public $validation_message; public $skip_the_db; @@ -91,6 +92,22 @@ final class safer_io { protected function __construct() { } + + // Get raw data for inputs, to be used by filters + public static function set_data_from(array|object $ao): void { + if (is_object($ao)) { + $a = get_object_vars($ao); + if ($a === false) { + return; // Error skip it + } + self::$DATA_INPUTS = array_merge(self::$DATA_INPUTS, $a); + return; + } + if (is_array($ao)) { + self::$DATA_INPUTS = array_merge(self::$DATA_INPUTS, $ao); + } + } + // Allow anything to set_data_inputs is desired here public static function set_data_input(string $var_name, mixed $data_in): void { if (! isset(self::$DATA_INPUTS[$var_name])) { @@ -489,6 +506,16 @@ final class safer_io { $safer_db_data = null; $safer_html_data = null; $meta[$input_field_name]['empty'] = true; + $skiper = $a->error_on_null ?? false; // should match public defined var of false + if ($skiper) { + $ret['name'] = $input_field_name; + $ret['meta']['missing'][] = $input_field_name; + $ret['errors'][$input_field_name] = "Missing Field $input_field_name"; + $ret['html'] = null; + $ret['db'] = false; + $ret['logic'] = false; + return $ret; + } } else { $field_filter_resolved = $field_type->resolve(); diff --git a/src/classes/attributes/validators/my_validator.php b/src/classes/attributes/validators/my_validator.php index cff3092..7c135bf 100644 --- a/src/classes/attributes/validators/my_validator.php +++ b/src/classes/attributes/validators/my_validator.php @@ -108,7 +108,15 @@ class my_validator { } } - public function validate(object $object, array $messages = []): void { + /** + * + * @param object $object + * @param array $messages defined in trait + * @param type $default null avoids an error on no-entry, false gives errors on no-entry + * @return void + */ + + public function validate(object $object, array $messages = [], $default = null): void { $handlers = [ Positive::class => function (string $name, $value, $attr, array $messages) { @@ -185,7 +193,7 @@ $handlers = [ foreach ($ref->getProperties() as $property) { $name = $property->getName(); $property->setAccessible(true); - $value = $property->getValue($object); + $value = $property->getValue($object) ?? $default; foreach ($property->getAttributes() as $attribute) { $class = $attribute->getName(); diff --git a/src/classes/traits/form_validator.php b/src/classes/traits/form_validator.php index c15bbd5..4fd03a6 100644 --- a/src/classes/traits/form_validator.php +++ b/src/classes/traits/form_validator.php @@ -31,124 +31,123 @@ trait form_validator { 'valid_domain' => 'The %s domain name is not active', ]; + /** + * + * @param array $data + * @param string $field + * @param mixed return: null avoids an error on no-entry; false gives errors on no-entry; default is the value + */ + private static function check_if_empty(array $data, string $field) { + $d = $data[$field] ?? null; + return match($d) { + null => true, // Pass validation as null or value unset + false => false, // Fail validation as user requested false on default + default => $d // Use value + }; + } + private static function is_positive(array $data, string $field): bool { - return (intval($data[$field]) >= 0) ? true : false; + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return (intval($r) >= 0) ? true : false; } private static function is_required(array $data, string $field): bool { - if (isset($data[$field])) { - if (common::get_count($data[$field])) { - return false; // Should not be an array here - } - if (is_string($data[$field])) { - return (trim($data[$field]) !== ''); - } - if (is_int($data[$field])) { - return true; - } + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + + if (common::get_count($r)) { + return false; // Should not be an array here + } + if (is_string($r)) { + return (trim($r) !== ''); + } + if (is_int($r)) { + return true; } - return false; } private static function is_email(array $data, string $field): bool { - if (empty($data[$field])) { - return true; - } - return (filter_var($data[$field], FILTER_VALIDATE_EMAIL) === false) ? false : true; + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return (filter_var($r, FILTER_VALIDATE_EMAIL) === false) ? false : true; } private static function is_min(array $data, string $field, string $min): bool { - if (!isset($data[$field])) { - return true; - } - - return mb_strlen($data[$field]) >= intval($min); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return mb_strlen($r) >= intval($min); } private static function is_max(array $data, string $field, string $max): bool { - if (!isset($data[$field])) { - return true; - } - - return mb_strlen($data[$field]) <= intval($max); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return mb_strlen($r) <= intval($max); } private static function is_greater_than(array $data, string $field, string $min): bool { - if (!isset($data[$field])) { - return true; - } - - return intval($data[$field]) > intval($min); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return intval($r) > intval($min); } private static function is_less_than(array $data, string $field, string $max): bool { - if (!isset($data[$field])) { - return true; - } - - return intval($data[$field]) < intval($max); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return intval($r) < intval($max); } private static function is_number_range(array $data, string $field, string $min, string $max): bool { - - if (!isset($data[$field])) { - return true; - } - - $no = intval($data[$field]); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + $no = intval($r); return $no >= intval($min) && $no <= intval($max); } private static function is_between(array $data, string $field, string $min, string $max): bool { - if (!isset($data[$field])) { - return true; - } - - $len = mb_strlen($data[$field]); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + $len = mb_strlen($r); return $len >= intval($min) && $len <= intval($max); } private static function is_same(array $data, string $field, string $other): bool { - if (isset($data[$field]) && isset($data[$other])) { - return $data[$field] === $data[$other]; + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + + if (isset($data[$other])) { + return $r === $data[$other]; } return false; } private static function is_alphanumeric(array $data, string $field): bool { - if (!isset($data[$field])) { - return true; - } - - return ctype_alnum($data[$field]); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return ctype_alnum($r); } private static function is_secure(array $data, string $field): bool { - if (!isset($data[$field])) { - return false; - } + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; // Is 8 to 64 CHRs $pattern = "#.*^(?=.{8,64})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$#"; - return preg_match($pattern, $data[$field]); + return preg_match($pattern, $r); } private static function is_valid_email_domain(array $data, string $field): bool { - if (!isset($data[$field])) { - return false; - } - - $domain = ltrim(stristr($data[$field], '@'), '@') . '.'; + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + $domain = ltrim(stristr($r, '@'), '@') . '.'; return checkdnsrr($domain, 'MX'); } private static function is_valid_domain(array $data, string $field): bool { - if (!isset($data[$field])) { - return false; - } - - return checkdnsrr($data[$field], 'A') - || checkdnsrr($data[$field], 'AAAA') - || checkdnsrr($data[$field], 'CNAME'); + $r = self::check_if_empty($data, $field); + if (is_bool($r)) return $r; + return checkdnsrr($r, 'A') + || checkdnsrr($r, 'AAAA') + || checkdnsrr($r, 'CNAME'); } } \ No newline at end of file