| Recommend this page to a friend! |
| Info | Example | Screenshots | Reputation | Support forum | Blog | Links |
| Last Updated | Ratings | Unique User Downloads | Download Rankings | |||||
| 2026-08-03 (11 days ago) | Not yet rated by the users | Total: Not yet counted | Not yet ranked | |||||
| Version | License | PHP version | Categories | |||
| contextual-validator 1.0 | MIT/X Consortium ... | 7.4 | Validation, PHP 7 |
| Description | Author | ||||||||||||||
This package can validate multiple form fields that are related. |
| ||||||||||||||
Copy src/ContextualValidator.php into your project and require it - no Composer, no dependencies.
require 'ContextualValidator.php';
use ContextValidate\ContextualValidator;
Create a validator with your submitted data (typically $_POST), then chain the rules you need:
$validator = new ContextualValidator($_POST);
$validator
->postalCodeMatchesCountry('zip', 'country')
->dateRange('start_date', 'end_date')
->ageMatchesBirthdate('age', 'birthdate')
->phoneMatchesCountry('phone', 'country')
->fieldsMatch('password', 'password_confirmation')
->numericRange('min_price', 'max_price');
if ($validator->fails()) {
foreach ($validator->errors() as $field => $messages) {
foreach ($messages as $message) {
echo "$field: $message\n";
}
}
}
postalCodeMatchesCountry($postalField, $countryField)
Checks the postal code format against the ISO country code
(25+ countries built in: US, CA, GB, FR, DE, ES, IT, NL, BE, CH,
AT, PT, AU, JP, BR, IN, CN, MX, SE, NO, DK, FI, PL, IE...).
dateRange($startField, $endField, $allowEqual = true)
Checks that the start date is not after the end date. Pass
false as the third argument to reject equal dates too.
ageMatchesBirthdate($ageField, $birthdateField, $toleranceYears = 0, $referenceDate = null)
Checks that a declared age is consistent with a birthdate.
Use $toleranceYears to allow a small margin.
phoneMatchesCountry($phoneField, $countryField)
Checks that a phone number's digit count is plausible for the
given country. This is a lightweight sanity check, not full
phone number validation.
fieldsMatch($fieldA, $fieldB, $message = null)
Checks that two fields hold identical values - typical use:
password / password confirmation.
numericRange($minField, $maxField)
Checks that a "min" field is not greater than a "max" field.
custom($field, $callable)
Add your own cross-field rule. The callable receives the full
data array and must return true, or a string error message:
$validator->custom('discount', function (array $data) {
return $data['discount'] <= $data['price']
? true
: 'Discount cannot exceed price.';
});
To add or override a postal code pattern for a country not in the built-in list:
ContextualValidator::addPostalCodePattern('XX', '/^\d{5}$/');
$validator->passes(); // bool
$validator->fails(); // bool
$validator->errors(); // array<string, string[]> keyed by field
$validator->allMessages(); // string[] flattened, in rule order
php tests/run-tests.php
27 assertions, no external test framework required.
<?php |
Most PHP validation libraries check one field at a time: is this a valid email, is this string non-empty, is this number in range. That catches typos, but it misses an entire class of bugs where each field is individually valid, yet the form as a whole is inconsistent.
This class validates relationships between fields instead of fields in isolation.
All of these pass every ordinary field-by-field validator, yet every one of them is wrong:
Copy src/ContextualValidator.php into your project, or require it
directly. No dependencies.
require 'src/ContextualValidator.php';
use ContextValidate\ContextualValidator;
$validator = new ContextualValidator($_POST);
$validator
->postalCodeMatchesCountry('zip', 'country')
->dateRange('start_date', 'end_date')
->ageMatchesBirthdate('age', 'birthdate')
->phoneMatchesCountry('phone', 'country')
->fieldsMatch('password', 'password_confirmation')
->numericRange('min_price', 'max_price');
if ($validator->fails()) {
foreach ($validator->errors() as $field => $messages) {
echo "$field: " . implode(', ', $messages) . "\n";
}
}
See examples/example.php for a full runnable demo with a form that
fails every single rule at once.
| Method | Checks |
|---|---|
| postalCodeMatchesCountry($postalField, $countryField) | Postal code format matches the ISO country code (25+ countries built in) |
| dateRange($startField, $endField, $allowEqual = true) | Start date is not after end date |
| ageMatchesBirthdate($ageField, $birthdateField, $toleranceYears = 0, $referenceDate = null) | Declared age matches computed age from birthdate |
| phoneMatchesCountry($phoneField, $countryField) | Phone number digit count is plausible for the given country |
| fieldsMatch($fieldA, $fieldB, $message = null) | Two fields hold identical values (e.g. password confirmation) |
| numericRange($minField, $maxField) | A "min" field is not greater than a "max" field |
| custom($field, $callable) | Any custom cross-field rule; return true or an error string |
Every rule skips silently (does not add an error) when a required field is empty or when the country isn't in the built-in list - it's not this class's job to require fields or judge unknown countries; pair it with your usual field-level validator for that.
ContextualValidator::addPostalCodePattern('XX', '/^\d{5}$/');
php tests/run-tests.php
MIT ? see LICENSE.
| Screenshots (1) | ||
| / | src |
| File | Role | Description |
|---|---|---|
| |
Class | Main class: validates relationships between form fields (postal code/country, date ranges, age/birthdate, phone/country, field matching, numeric ranges). |
| / | examples |
| File | Role | Description |
|---|---|---|
| |
Example | Full working example: a form that fails all 5 rules at once, demonstrating every cross-field check together. |
| / | tests |
| File | Role | Description |
|---|---|---|
| |
Example | Dependency-free automated test suite (27 assertions) covering every rule. |
| The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page. |
| Version Control | Unique User Downloads | |||||||
| 0% |
|
| Applications that use this package |
If you know an application of this package, send a message to the author to add a link here.