PHP 8.4+ Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
CodeHydrater/src/classes/validator.php

234 lines
7.5 KiB

<?php
declare(strict_types=1);
/**
* Modified from phptutorial.net
* @link https://www.phptutorial.net/php-tutorial/php-validation/
*/
namespace CodeHydrater;
class validator {
const DEFAULT_VALIDATION_ERRORS = [
'required' => 'Please enter the %s',
'email' => 'The %s is not a valid email address',
'less_than' => 'The %s number must be less than %d',
'greater_than' => 'The %s number must be greater than %d',
'number_range' => 'The %s number must be in range of %d to %d',
'min' => 'The %s must have at least %s characters',
'max' => 'The %s must have at most %s characters',
'between' => 'The %s must have between %d and %d characters',
'same' => 'The %s must match with %s',
'alphanumeric' => 'The %s should have only letters and numbers',
'secure' => 'The %s must have between 8 and 64 characters and contain at least one number, one upper case letter, one lower case letter and one special character',
'valid_email_domain' => 'The %s email address is not active',
'valid_domain' => 'The %s domain name is not active',
];
private static function make_arrays(array $data, $field): array {
$dataset = [];
if (isset($data[$field])) {
if (common::get_count($data[$field])) {
foreach($data[$field] as $the_data) {
$dataset[] = $the_data;
}
} else {
$dataset[] = $data[$field];
}
} else {
$dataset[] = null; // If field is null, force null set
}
return $dataset;
}
public static function validate(
array $data,
array $fields,
array $messages = []
): array {
// Split the array by a separator, trim each element
// and return the array
$split = fn($str, $separator) => array_map('trim', explode($separator, $str));
// get the message rules
$rule_messages = array_filter($messages, fn($message) => is_string($message));
// overwrite the default message
$validation_errors = array_merge(self::DEFAULT_VALIDATION_ERRORS, $rule_messages);
$errors = [];
foreach ($fields as $field => $option) {
foreach(self::make_arrays($data, $field) as $index=>$v) {
$data[$field] = $v; // Force update on arrays
$rules = $split($option, '|');
foreach ($rules as $rule) {
// get rule name params
$params = [];
// if the rule has parameters e.g., min: 1
if (strpos($rule, ':')) {
[$rule_name, $param_str] = $split($rule, ':');
$params = $split($param_str, ',');
} else {
$rule_name = trim($rule);
}
// by convention, the callback should be is_<rule> e.g.,is_required
$fn = 'is_' . $rule_name;
$callable = self::class . "::{$fn}";
if (is_callable($callable)) {
$pass = $callable($data, $field, ...$params);
if (!$pass) {
// get the error message for a specific field and rule if exists
// otherwise get the error message from the $validation_errors
$errors[$field] = sprintf(
$messages[$field][$rule_name] ?? $validation_errors[$rule_name],
$field,
...$params
);
}
}
}
}
}
return $errors;
}
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;
}
}
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);
}
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);
}
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);
}
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);
}
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);
}
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]);
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]);
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];
}
return false;
}
private static function is_alphanumeric(array $data, string $field): bool {
if (!isset($data[$field])) {
return true;
}
return ctype_alnum($data[$field]);
}
private static function is_secure(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
// Is 8 to 64 CHRs
$pattern = "#.*^(?=.{8,64})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$#";
return preg_match($pattern, $data[$field]);
}
private static function is_valid_email_domain(array $data, string $field): bool {
if (!isset($data[$field])) {
return false;
}
$domain = ltrim(stristr($data[$field], '@'), '@') . '.';
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');
}
}
/*
$data = ['email'=>'jim@aol.com'];
$fields = ['email' => 'required | email'];
$errors = \CodeHydrater\validator::validate($data, $fields);
print_r($errors);
*/
/*
* 'firstname' => 'required | max:255',
'lastname' => 'required | max: 255',
'address' => 'required | min: 10 | max:255',
'zipcode' => 'between: 5,6',
'username' => 'required | alphanumeric | between: 3,255',
'email' => 'required | email | valid_email_domain',
*/