Adding custom validators and filters is made easy by using callback functions.
/*
Create a custom validation rule named "is_object".
The callback receives 4 arguments:
The field, the input array, any rule parameters, and the field value.
It should return a boolean indicating whether the value is valid.
*/
validate::add_validator("is_object", function($field, $input, $params = [], $value = null) {
return is_object($input[$field]);
});
/*
Create a custom filter named "upper".
The callback function receives two arguments:
The value to filter, and any parameters used in the filter rule. It should returned the filtered value.
*/
validate::add_filter("upper", function($value, $params = []) {
return strtoupper($value);
});
Alternately, you can simply create your own rules by creating or adding in the Validator class helper.
class MyValidator extends \Simple\Validation\Validator
{
protected function filter_myfilter($value, array $params = [])
{
// ...
}
protected function validate_myvalidator($field, array $input, array $params = [], $value = null)
{
// ...
}
}
Remember to create protected methods with the correct parameter types and parameter counts.
- For filter methods, prepend the method name with "filter_".
- For validator methods, prepend the method name with "validate_".
Customize Validation Error Messages
You can override error messages at three levels:
- Globally — affects every use of a rule via
Validate::set_error_message()
- Per-field, per-rule — overrides for specific field/rule combinations via
$v->set_fields_error_messages()
- Inline — in the
is_valid() third argument
Available Placeholders
| Placeholder | Replaced With | Example |
{field} | Field name (or readable name if set) | username |
{param} | All parameters joined by comma | 3, 100 |
{param[0]} | First parameter | 3 |
{param[1]} | Second parameter | 100 |
Per-Field Custom Messages
use Simple\Validation\Validator as Validate;
$v = new Validate;
$v->validation_rules([
'username' => 'required|alpha_numeric|between_len,3;20',
'email' => 'required|valid_email',
'age' => 'required|integer|min_numeric,18',
'password' => 'required|strong_password'
]);
$v->set_fields_error_messages([
'username' => [
'required' => 'Please choose a username',
'alpha_numeric' => 'Usernames can only contain letters and numbers',
'between_len' => 'Username must be between {param[0]} and {param[1]} characters'
],
'email' => [
'required' => 'An email address is required',
'valid_email' => 'Enter a valid email address'
],
'age' => [
'required' => 'Please enter your age',
'integer' => 'Age must be a whole number',
'min_numeric' => 'You must be at least {param} years old'
],
'password' => [
'required' => 'Choose a password',
'strong_password' => 'Password needs uppercase, lowercase, number, and special character'
]
]);
$data = [
'username' => 'ab',
'email' => 'notanemail',
'age' => 15,
'password' => 'weak'
];
$validated = $v->run($data);
// Returns false — errors use the custom messages above
$errors = $v->get_readable_errors(true);
// "Please choose a username" (not "The Username field is required")
// "Usernames can only contain letters and numbers"
Global Error Message Override
use Simple\Validation\Validator as Validate;
// Override globally — affects ALL fields using these rules
Validate::set_error_message('required', 'Oops! {field} cannot be empty.');
Validate::set_error_message('valid_email', '{field} is not a valid email address.');
Validate::set_error_message('min_len', '{field} needs at least {param} characters.');
// Set multiple at once
Validate::set_error_messages([
'max_len' => '{field} cannot exceed {param} characters.',
'min_numeric' => '{field} must be at least {param}.',
'max_numeric' => '{field} cannot be more than {param}.'
]);
// Now all validations use these messages
$data = ['name' => '', 'email' => 'bad'];
$rules = ['name' => 'required|min_len,2', 'email' => 'required|valid_email'];
$validated = Validate::is_valid($data, $rules);
$errors = Validate::get_instance()->get_readable_errors(true);
// "Oops! name cannot be empty."
// "email is not a valid email address."
Inline with is_valid() Shorthand
use Simple\Validation\Validator as Validate;
$data = [
'username' => '',
'email' => 'bad-email',
'age' => 16
];
$rules = [
'username' => 'required|alpha_numeric|min_len,3',
'email' => 'required|valid_email',
'age' => 'required|integer|min_numeric,18'
];
$messages = [
'username' => [
'required' => 'Pick a username',
'min_len' => 'Username needs at least {param[0]} characters'
],
'email' => [
'required' => 'Email is required',
'valid_email' => 'Enter a valid email'
],
'age' => [
'required' => 'Enter your age',
'min_numeric' => 'Must be {param} or older'
]
];
$validated = Validate::is_valid($data, $rules, $messages);
if ($validated !== true) {
// $validated = ['username' => ['Pick a username'], 'email' => ...]
foreach ($validated as $field => $errors) {
echo "$field: " . implode(', ', $errors) . "\n";
}
}
Setting Readable Field Names
use Simple\Validation\Validator as Validate;
// Map field keys to human-readable labels
Validate::set_field_name('usr', 'Username');
Validate::set_field_name('pwd', 'Password');
Validate::set_field_name('email_addr', 'Email Address');
// Or set multiple at once
Validate::set_field_names([
'usr' => 'Username',
'pwd' => 'Password',
'email_addr' => 'Email Address',
'dob' => 'Date of Birth'
]);
// Now default error messages use these instead of the raw key
$data = ['usr' => '', 'pwd' => '12'];
$rules = ['usr' => 'required|min_len,3', 'pwd' => 'required|min_len,8'];
$validated = Validate::is_valid($data, $rules);
$errors = Validate::get_instance()->get_readable_errors(true);
// "The Username field is required"
// "The Password field needs to be at least 8 characters"
Complete Example — Registration with Custom Messages
use Simple\Validation\Validator as Validate;
// Set readable field names
Validate::set_field_names([
'first_name' => 'First Name',
'last_name' => 'Last Name',
'email' => 'Email Address',
'age' => 'Age',
'dob' => 'Date of Birth',
'website' => 'Website URL'
]);
$v = new Validate;
$v->validation_rules([
'first_name' => 'required|alpha_space|min_len,2|max_len,50',
'last_name' => 'required|alpha_space|min_len,2|max_len,50',
'email' => 'required|valid_email',
'age' => 'required|integer|min_numeric,13|max_numeric,120',
'dob' => 'required|date|past_date|min_age,13',
'website' => 'valid_url',
'password' => 'required|strong_password',
'terms' => 'required|boolean,strict'
]);
// Per-field custom error messages
$v->set_fields_error_messages([
'first_name' => [
'required' => 'Please enter your first name',
'alpha_space' => 'First name can only contain letters and spaces',
'min_len' => 'First name must be at least {param[0]} characters'
],
'email' => [
'required' => 'An email address is required',
'valid_email' => 'Enter a valid email address'
],
'age' => [
'min_numeric' => 'You must be at least {param} years old',
'max_numeric' => 'Age cannot exceed {param}'
],
'dob' => [
'date' => 'Enter a valid date (YYYY-MM-DD)',
'past_date' => 'Date of birth must be in the past',
'min_age' => 'You must be at least {param} years old'
],
'password' => [
'strong_password' => 'Password must have uppercase, lowercase, a number, and a special character'
],
'terms' => [
'required' => 'You must accept the terms and conditions',
'boolean' => 'Please check the agreement box'
]
]);
$data = [
'first_name' => 'J',
'last_name' => 'Doe',
'email' => 'not-an-email',
'age' => 10,
'dob' => '2020-01-01',
'website' => 'not-a-url',
'password' => 'weak',
'terms' => 'no'
];
$validated = $v->run($data);
if ($validated === false) {
echo $v->get_readable_errors(true);
} else {
print_r($validated);
}
Date & Time Validation
The library provides several validators for dates, times, and age checks. Below are comprehensive examples covering the most common scenarios.
Basic Date Validation
use Simple\Validation\Validator as Validate;
// Validate ISO 8601 date (Y-m-d)
$data = ['published' => '2025-01-15'];
$rules = ['published' => 'date'];
$result = Validate::is_valid($data, $rules);
// true
// Custom format
$data = ['published' => '15/01/2025'];
$rules = ['published' => 'date,d/m/Y'];
$result = Validate::is_valid($data, $rules);
// true
// Invalid date
$data = ['published' => 'not-a-date'];
$result = Validate::is_valid($data, $rules);
// false
// Invalid for format
$data = ['published' => '2025-01-15'];
$rules = ['published' => 'date,d/m/Y'];
$result = Validate::is_valid($data, $rules);
// false — "2025-01-15" is not valid for d/m/Y
Age Verification
// Minimum age (date of birth must be at least N years ago)
$data = ['dob' => '2000-06-15'];
$rules = ['dob' => 'required|date|min_age,18'];
$result = Validate::is_valid($data, $rules);
// true — born 2000 = 25+ years old
$data = ['dob' => '2020-06-15'];
$result = Validate::is_valid($data, $rules);
// false — only ~5 years old
// With custom date format
$data = ['dob' => '15/06/2000'];
$rules = ['dob' => 'required|date,d/m/Y|min_age,18'];
$result = Validate::is_valid($data, $rules);
// true
Future & Past Dates
// Event must be in the future
$data = ['event_date' => '2030-12-25'];
$rules = ['event_date' => 'required|date|future_date'];
$result = Validate::is_valid($data, $rules);
// true
// Past date — e.g. "date of birth" must be in the past
$data = ['dob' => '1990-01-01'];
$rules = ['dob' => 'required|date|past_date'];
$result = Validate::is_valid($data, $rules);
// true
// Today's date is neither future nor past
$data = ['today' => date('Y-m-d')];
$rules = ['today' => 'date|future_date'];
$result = Validate::is_valid($data, $rules);
// false — today is not in the "future"
$rules = ['today' => 'date|past_date'];
$result = Validate::is_valid($data, $rules);
// false — today is not in the "past"
// With custom format
$data = ['appointment' => '01/12/2030'];
$rules = ['appointment' => 'required|date,d/m/Y|future_date'];
$result = Validate::is_valid($data, $rules);
// true
Date Range
// Date must fall between start and end (inclusive)
$data = ['trip' => '2025-07-15'];
$rules = ['trip' => 'required|date|date_range,2025-06-01;2025-09-01'];
$result = Validate::is_valid($data, $rules);
// true — July 15 is within the range
$data = ['trip' => '2025-05-01'];
$result = Validate::is_valid($data, $rules);
// false — May 1 is before the range
// Booking system: check-in must be within the next 30 days
$start = date('Y-m-d');
$end = date('Y-m-d', strtotime('+30 days'));
$data = ['checkin' => date('Y-m-d', strtotime('+14 days'))];
$rules = ['checkin' => "required|date|date_range,$start;$end"];
$result = Validate::is_valid($data, $rules);
// true
$data = ['checkin' => date('Y-m-d', strtotime('+60 days'))];
$result = Validate::is_valid($data, $rules);
// false — 60 days out is beyond the range
Business Day Check
// Date must be Monday-Friday
$data = ['delivery' => '2025-07-14']; // Monday
$rules = ['delivery' => 'required|date|business_day'];
$result = Validate::is_valid($data, $rules);
// true
$data = ['delivery' => '2025-07-12']; // Saturday
$result = Validate::is_valid($data, $rules);
// false
// Combined: future business day
$rules = ['delivery' => 'required|date|future_date|business_day'];
$result = Validate::is_valid($data, $rules);
// false (Saturday is also not a future date if it's past)
Time Validation
// Valid time formats: HH:MM or HH:MM:SS
$data = ['start' => '09:00'];
$rules = ['start' => 'valid_time'];
$result = Validate::is_valid($data, $rules);
// true
$data = ['start' => '14:30:00'];
$result = Validate::is_valid($data, $rules);
// true
$data = ['start' => '25:00'];
$result = Validate::is_valid($data, $rules);
// false — hour 25 is invalid
// Combined with date
$data = [
'appointment_date' => '2025-12-01',
'appointment_time' => '10:30'
];
$rules = [
'appointment_date' => 'required|date|future_date|business_day',
'appointment_time' => 'required|valid_time'
];
$result = Validate::is_valid($data, $rules);
// true if 2025-12-01 is a future business day
Date of Birth — Full Real-World Example
// Registration form (long format)
$v = new Validate;
$v->validation_rules([
'full_name' => 'required|valid_name|max_len,100',
'email' => 'required|valid_email',
'dob' => 'required|date,d/m/Y|past_date|min_age,18',
'member_since' => 'date|past_date'
]);
$v->set_fields_error_messages([
'dob' => [
'date' => 'Enter a valid date in DD/MM/YYYY format',
'past_date' => 'Date of birth must be in the past',
'min_age' => 'You must be at least 18 years old'
]
]);
$data = [
'full_name' => 'Jane Smith',
'email' => '[email protected]',
'dob' => '15/06/1990',
'member_since' => '2023-01-01'
];
$validated = $v->run($data);
if ($validated === false) {
echo $v->get_readable_errors(true);
} else {
print_r($validated);
}
Event Booking — Full Real-World Example
use Simple\Validation\Validator as Validate;
// Static shorthand format
$data = [
'event_name' => 'Summer Conference',
'event_date' => '2026-07-15',
'start_time' => '09:00',
'end_time' => '17:00',
'reg_deadline' => '2026-06-01'
];
$rules = [
'event_name' => 'required|alpha_numeric_space|max_len,200',
'event_date' => 'required|date|future_date|business_day',
'start_time' => 'required|valid_time',
'end_time' => 'required|valid_time',
'reg_deadline' => 'required|date|date_range,2026-01-01;2026-07-14|past_date'
];
$validated = Validate::is_valid($data, $rules);
if ($validated !== true) {
foreach ($validated as $field => $errors) {
echo "$field: " . implode(', ', $errors) . "\n";
}
}