Simple, Modern PHP Validation
Valicomb is a simple, minimal PHP validation library with zero dependencies. A modernized fork of vlucas/valitron for PHP 8.2+ with security-first design, strict type safety, and modern PHP features.
- Modern PHP 8.2+ support with strict types turned on, so everything is fully typed and predictable.
- Security-first approach that helps guard against things like ReDoS, type juggling issues, path traversal, and similar problems.
- Thoroughly tested, with over 430 tests making sure things behave the way they should.
- No external dependencies, other than the standard
ext-mbstringextension. - Clean and straightforward API that's easy to read and chain together.
- Built-in i18n support, offering 33 languages out of the box.
- 54 ready-to-use validation rules covering the most common validation needs.
- Easy to extend, so you can add your own custom validation rules when needed.
- Clean, modern codebase, fully passing PHPStan Level 8 checks.
- PHP 8.2 or higher
ext-mbstringextension
Install via Composer:
composer require frostybee/valicombuse Frostybee\Valicomb\Validator;
// Create validator with data
$v = new Validator([
'username' => 'frostybee',
'email' => 'bee@example.com',
'password' => 'Secret123!'
]);
// Define rules by field
$v->forFields([
'username' => ['required', ['lengthBetween', 3, 20]],
'email' => ['required', 'email'],
'password' => ['required', ['lengthMin', 8]]
]);
if ($v->validate()) {
echo "Validation passed!";
} else {
print_r($v->errors());
}Define validation rules once, then validate multiple datasets with withData():
use Frostybee\Valicomb\Validator;
$baseValidator = new Validator([]);
$baseValidator->rule('required', 'email')->rule('email', 'email');
// Validate different datasets
$v1 = $baseValidator->withData(['email' => 'user1@example.com']);
$v1->validate(); // true
$v2 = $baseValidator->withData(['email' => 'invalid']);
$v2->validate(); // falseThis is useful for form validation, API endpoints, and batch processing where the same rules apply to different data.
For detailed usage examples of each rule, see the documentation
required- Field is requiredalpha- Alphabetic characters onlyalphaNum- Alphabetic and numeric characters onlyascii- ASCII characters onlyslug- URL slug characters (a-z, 0-9, -, _)email- Valid email addressemailDNS- Valid email address with active DNS recordcontains- Field is a string and contains the given stringregex- Field matches given regex patternstartsWith- Field starts with the given stringendsWith- Field ends with the given stringuuid- Field is a valid UUID (supports versions 1-5)passwordStrength- Field meets password strength requirements
integer- Must be integer numbernumeric- Must be numericmin- Minimum valuemax- Maximum valuebetween- Value must be between min and maxpositive- Must be a positive number (greater than zero)decimalPlaces- Must have specified number of decimal places
length- String must be certain lengthlengthBetween- String must be between given lengthslengthMin- String must be greater than given lengthlengthMax- String must be less than given length
url- Valid URLurlActive- Valid URL with active DNS recordurlStrict- Valid URL with strict validationphone- Valid phone number format
array- Must be arrayin- Performs in_array check on given array valuesnotIn- Negation ofinrule (not in array of values)listContains- Performs in_array check on given array values (the other way round thanin)subset- Field is an array or a scalar and all elements are contained in the given arraycontainsUnique- Field is an array and contains unique valuesarrayHasKeys- Field is an array and contains all specified keys
date- Field is a valid datedateFormat- Field is a valid date in the given formatdateBefore- Field is a valid date and is before the given datedateAfter- Field is a valid date and is after the given datepast- Field is a valid date in the pastfuture- Field is a valid date in the future
equals- Field must match another field (email/password confirmation)different- Field must be different than another field
boolean- Must be booleanip- Valid IP addressipv4- Valid IP v4 addressipv6- Valid IP v6 addresscreditCard- Field is a valid credit card numberinstanceOf- Field contains an instance of the given class
optional- Value does not need to be included in data array. If it is however, it must pass validation.nullable- Field can be null; if null, other validation rules are skippedaccepted- Checkbox or Radio must be accepted (yes, on, 1, true)requiredWith- Field is required if any other fields are presentrequiredWithout- Field is required if any other fields are NOT present
NOTE: If you are comparing floating-point numbers with min/max validators, you should install the BCMath extension for greater accuracy and reliability. The extension is not required for Valicomb to work, but Valicomb will use it if available, and it is highly recommended.
Valicomb provides four flexible ways to define validation rules:
Group rules by field - reads naturally as "for this field, apply these rules":
use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->forFields([
'name' => ['required', ['lengthMin', 2]],
'email' => ['required', 'email', ['lengthMax', 254]]
]);use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->rule('required', 'email')
->rule('email', 'email')
->rule('lengthMin', 'email', 5);use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->rules([
'required' => ['name', 'email'],
'email' => 'email',
'lengthBetween' => [
['name', 1, 100],
['bio', 10, 500]
]
]);Chain validation methods directly on fields with full IDE autocomplete support:
use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->field('email')
->required()
->email()
->lengthMax(254);
$v->field('password')
->required()
->lengthMin(8);Add custom messages and labels inline:
$v->field('email')
->label('Email Address')
->required()->message('We need your email')
->email()->message('Please enter a valid email');use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->labels([
'email' => 'Email Address',
'password' => 'Password'
]);use Frostybee\Valicomb\Validator;
$v = new Validator(['username' => 'admin']);
// Closure-based rule
$v->rule(function($field, $value, $params, $fields) {
return $value !== 'admin';
}, 'username')->message('Username cannot be "admin"');
// Register global custom rule
Validator::addRule('strongPassword', function($field, $value, $params) {
return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/', $value);
}, 'Password must be at least 8 characters with uppercase, lowercase, and number');By default, validation continues checking all rules even after encountering failures. You can configure the validator to stop the validation process as soon as the first failure occurs, which can improve performance when validating large datasets.
use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->stopOnFirstFail(true);
$v->rule('required', ['email', 'password']);
$v->rule('email', 'email');Valicomb properly handles form data where all values come as strings:
use Frostybee\Valicomb\Validator;
// $_POST data - everything is strings
$_POST = [
'age' => '25', // String, not int
'price' => '19.99', // String, not float
'active' => '1' // String, not bool
];
$v = new Validator($_POST);
$v->rule('integer', 'age'); // Works with string '25'
$v->rule('numeric', 'price'); // Works with string '19.99'
$v->rule('boolean', 'active'); // Works with string '1'use Frostybee\Valicomb\Validator;
$data = [
'user' => [
'email' => 'test@example.com',
'profile' => [
'age' => 25
]
]
];
$v = new Validator($data);
$v->rule('email', 'user.email');
$v->rule('integer', 'user.profile.age');use Frostybee\Valicomb\Validator;
$data = [
'users' => [
['email' => 'user1@example.com'],
['email' => 'user2@example.com']
]
];
$v = new Validator($data);
$v->rule('email', 'users.*.email'); // Validates all emailsCheck if an array field contains a specific value:
use Frostybee\Valicomb\Validator;
// Check if tags array contains 'php'
$v = new Validator(['tags' => ['php', 'javascript', 'python']]);
$v->rule('listContains', 'tags', 'php'); // true
// Strict type checking
$v = new Validator(['ids' => [1, 2, 3]]);
$v->rule('listContains', 'ids', '1', true); // false (strict: string !== int)
// For associative arrays, checks keys not values
$v = new Validator(['data' => ['name' => 'John', 'email' => 'john@example.com']]);
$v->rule('listContains', 'data', 'name'); // true (checks keys)
$v->rule('listContains', 'data', 'John'); // false (doesn't check values)Regular expression validation includes automatic protection against catastrophic backtracking:
use Frostybee\Valicomb\Validator;
$v = new Validator(['field' => 'aaaaaaaaaaaa!']);
$v->rule('regex', 'field', '/^(a+)+$/'); // Throws RuntimeException on ReDoS patternAll comparisons use strict equality (===) to prevent type juggling attacks:
use Frostybee\Valicomb\Validator;
$v = new Validator([
'field1' => '0e123456',
'field2' => '0e789012'
]);
$v->rule('equals', 'field1', 'field2'); // Returns false (strict comparison)URL validation uses proper prefix checking to prevent bypass attacks:
use Frostybee\Valicomb\Validator;
// FAIL - http:// not at start
$v = new Validator(['url' => 'evil.com?redirect=http://trusted.com']);
$v->rule('url', 'url'); // Returns false
// PASS - proper URL
$v = new Validator(['url' => 'http://trusted.com']);
$v->rule('url', 'url'); // Returns trueLanguage loading validates against directory traversal:
use Frostybee\Valicomb\Validator;
// Blocked - invalid language
new Validator([], [], '../../etc/passwd'); // Throws InvalidArgumentExceptionEmail validation includes:
- RFC 5321 length limits (254 chars total, 64 local, 255 domain)
- Dangerous character rejection
- Proper validation against injection attacks
Fixed regex properly validates all integers, not just single digits:
use Frostybee\Valicomb\Validator;
$v = new Validator(['num' => '1000']);
$v->rule('integer', 'num', true); // Works correctly (strict mode)Valicomb supports 33 languages out of the box:
use Frostybee\Valicomb\Validator;
// Set default language
Validator::lang('es'); // Spanish
// Or per-instance
$v = new Validator($data, [], 'fr'); // FrenchAvailable languages: ar, az, bg, cs, da, de, el, en, es, fa, fi, fr, hu, id, it, ja, ko, lt, lv, nb, nl, nn, no, pl, pt, pt-br, ro, ru, sk, sl, sv, th, tr, uk, vi, zh-cn, zh-tw
use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
// Required only if other field is present
$v->rule('requiredWith', 'billing_address', ['same_as_shipping']);
// Required only if other field is absent
$v->rule('requiredWithout', 'phone', ['email']);use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->rule('optional', 'middle_name');
$v->rule('alpha', 'middle_name'); // Only validated if presentuse Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
// Any valid card
$v->rule('creditCard', 'card_number');
// Specific card type
$v->rule('creditCard', 'card_number', 'visa');
// Multiple allowed types
$v->rule('creditCard', 'card_number', ['visa', 'mastercard']);use Frostybee\Valicomb\Validator;
$v = new Validator(['date' => new DateTime()]);
$v->rule('instanceOf', 'date', DateTime::class);use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->rule('required', 'email');
$v->rule('integer', 'age');
if (!$v->validate()) {
$errors = $v->errors();
// [
// 'email' => ['Email is required', 'Email is not a valid email address'],
// 'age' => ['Age must be an integer']
// ]
}use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->rule('required', 'email')->rule('email', 'email');
$v->validate();
$emailErrors = $v->errors('email');
// ['Email is required', 'Email is not a valid email address']use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->rule('required', 'email')->message('We need your email!');
$v->rule('email', 'email')->message('That doesn\'t look like a valid email');use Frostybee\Valicomb\Validator;
$v = new Validator($_POST);
$v->rule('lengthBetween', 'username', 3, 20)
->message('Username must be between {0} and {1} characters');Originally created by Vance Lucas
Modernized for PHP 8.2+ with security enhancements and strict type safety.
- GitHub Issues: Report bugs or request features
- Stack Overflow: Tag your questions with
valicomborphp-validation
Contributions are welcome! Please ensure:
- Fork the repository
- Create your feature branch (
git checkout -b my-new-feature) - Make your changes
- Run all quality checks (
composer check-all) - Code follows PSR-12 standards (
composer cs-fix) - All tests pass (
composer test) - PHPStan analysis passes (
composer analyse) - Add tests for new features
- Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a Pull Request
# Before committing
composer check-all
# Individual checks
composer test # Run PHPUnit test suite
composer analyse # Run PHPStan static analysis (Level 8)
composer cs-check # Check code style (PSR-12)
# Fix any issues
composer cs-fix
# Verify fixes
composer check-allcomposer benchmark- Run performance benchmarkscomposer validate- Validate composer.json syntaxcomposer audit- Check for security vulnerabilities
To report a security vulnerability, please create a private security advisory on GitHub or email the maintainer directly. Do not create public issues for security vulnerabilities.
Valicomb is open-source software licensed under the BSD 3-Clause License.