Fast, modern PHP request validation and sanitization. Schema-based rules, fail-fast execution, intelligent batching, and 103 built-in validation rules.
$validator = Validator::make([
'email' => 'required|email|max:255',
'age' => 'required|integer|min:18',
])->setSanitizers([
'email' => ['trim', 'lowercase'],
])->setCasts([
'age' => 'integer',
]);
$result = $validator->validate($data);
if ($result->passes()) {
$clean = $result->typed();
// β
All good!
}- π 103 Built-in Rules - Basic types, conditional rules, files, database checks, and more
- π§Ή 50+ Sanitizers - Manual sanitization or built-in sanitize+validate pipeline
- β‘ Intelligent Batching - Expensive DB checks are batched automatically
- π― Fail-Fast + Full Collection Modes - Per-field fail-fast with configurable behavior
- π Nested + Wildcard Validation - Dot notation with wildcard expansion
- π§Ύ Custom Messages + Placeholders -
:field,:rule,:min, and more - π Locale Packs - Per-rule localized message templates with fallback
- π§ Failure Metadata - Structured failures (
field,rule,message,value) - π¦ Schema Fragments + Composition - Reuse validation contracts across endpoints
- π Conditional Closures -
sometimes()andwhen()for dynamic rule activation - π§± Schema Export - JSON Schema, OpenAPI shape, and introspection metadata
- π§° Typed Output + DTO Mapping - Cast map +
toDTO()support - π€ Uploaded File Object Support - Array-style uploads and PSR-7 style objects
- π οΈ PHP 8.4+ - Built with modern PHP features
composer require infocyph/reqshieldRequirements: PHP 8.4+ and ext-hash with xxh3 support
use Infocyph\ReqShield\Validator;
$validator = Validator::make([
'email' => [
'rules' => 'required|email|max:255',
'sanitize' => ['trim', 'lowercase'],
'alias' => 'Email Address',
],
'password' => 'required|string|min:8|confirmed',
'age' => 'required|integer|min:18',
])->setCasts([
'age' => 'integer',
])->setCustomMessages([
'email.required' => ':field is required.',
'*.min' => ':field must be at least :min.',
]);
$result = $validator->validate($data);
if ($result->passes()) {
$validated = $result->typed();
// Process your data...
} else {
$errors = $result->errors();
$failures = $result->failures();
// Handle validation errors...
}Manual sanitization:
use Infocyph\ReqShield\Sanitizer;
$clean = [
'email' => Sanitizer::email($input['email']), // 'john@example.com'
'username' => Sanitizer::alphaDash($input['username']), // 'john_doe'
'age' => Sanitizer::integer($input['age']), // 25
'bio' => Sanitizer::string($input['bio']), // Strips HTML tags
];
$result = $validator->validate($clean);Or built-in sanitize+validate pipeline:
$validator = Validator::make([
'email' => 'required|email',
'contacts.*.email' => 'required|email',
])->setSanitizers([
'email' => ['trim', 'lowercase'],
'contacts.*.email' => ['trim', 'lowercase'],
]);Or use the helper:
$clean = sanitize(' TEST@ex.com ', 'email'); // 'TEST@ex.com'
$clean = sanitize('<b>TEXT</b>', ['string', 'lowercase']); // 'text'ReqShield includes 103 validation rules covering several common scenarios:
- Basic Types
- Formats
- Strings
- Numbers
- Dates
- Conditionals
- Database
- Files
- Arrays
- Comparison
- Patterns
- Additional
π View Complete Rule Reference
ReqShield includes 50+ sanitizers covering several common scenarios:
- Basic Types
- Case Conversions
- Text Processing
- Special Formats
- Alphanumeric Filters
- Security & HTML
- Encoding
- Array Operations
π View Complete Sanitizer Reference
Validate deeply nested arrays using dot notation:
$validator = Validator::make([
'user.email' => 'required|email',
'user.name' => 'required|min:3',
'user.profile.age' => 'required|integer|min:18',
'user.profile.bio' => 'string|max:500',
])->enableNestedValidation();
$data = [
'user' => [
'email' => 'john@example.com',
'name' => 'John Doe',
'profile' => [
'age' => 25,
'bio' => 'Software developer',
],
],
];
$result = $validator->validate($data);Use enableNestedValidation(false) to flatten only required paths for large nested payloads.
Make error messages user-friendly:
$validator->setFieldAliases([
'user_email' => 'Email Address',
'contacts.*.email' => 'Contact Email',
]);$validator
->setCustomMessages([
'email.required' => ':field is required.',
'*.min' => ':field must be at least :min.',
'contacts.*.email.email' => 'Each :field must be valid.',
])
->addLocalePack('es', [
'required' => 'El campo :field es obligatorio.',
'*' => 'El campo :field no es valido.',
])
->setLocale('es');use Infocyph\ReqShield\Exceptions\ValidationException;
$validator = Validator::make($rules)->throwOnFailure();
try {
$result = $validator->validate($data);
$validated = $result->validated();
} catch (ValidationException $e) {
echo $e->getMessage(); // "Validation failed"
print_r($e->getErrors()); // All errors
echo $e->getErrorCount(); // Number of failed fields
echo $e->getFirstFieldError('email'); // First error for specific field
echo $e->getCode(); // 422
}$result = $validator->validate($data);
if ($result->fails()) {
return [
'errors' => $result->errors(),
'failures' => $result->failures(), // field, rule, message, value
];
}$validator
->sometimes('vat', 'required', fn(array $data) => ($data['type'] ?? null) === 'business')
->when(
fn(array $data) => ($data['country'] ?? null) === 'US',
fn() => ['state' => 'required|string'],
);Validator::defineFragment('address', [
'line1' => 'required|string|max:120',
'zip' => 'required|digits:5',
]);
$validator = Validator::make([
'name' => 'required|string',
])->useFragment('address', 'billing');$validator = Validator::make([
'age' => 'required|integer',
'active' => 'required|boolean',
])->setCasts([
'age' => 'integer',
'active' => 'boolean',
])->setDtoClass(App\DTO\UserInput::class);
$result = $validator->validate($data);
$typed = $result->typed();
$dto = $result->toDTO();Use callbacks for quick custom validation:
use Infocyph\ReqShield\Rules\Callback;
$validator = Validator::make([
'code' => [
'required',
new Callback(
callback: fn($value, $field, $data) => $value % 2 === 0,
message: 'The code must be an even number'
),
],
]);Create reusable rule classes:
use Infocyph\ReqShield\Contracts\Rule;
class StrongPassword implements Rule
{
public function passes(mixed $value, string $field, array $data): bool
{
return strlen($value) >= 12
&& preg_match('/[A-Z]/', $value)
&& preg_match('/[a-z]/', $value)
&& preg_match('/[0-9]/', $value)
&& preg_match('/[^A-Za-z0-9]/', $value);
}
public function message(string $field): string
{
return "The {$field} must be at least 12 characters with uppercase, lowercase, number, and special character.";
}
public function cost(): int { return 20; }
public function isBatchable(): bool { return false; }
}
// Usage
$validator = Validator::make([
'password' => ['required', new StrongPassword()],
]);Validate against your database:
use Infocyph\ReqShield\Validator;
use Infocyph\ReqShield\Contracts\DatabaseProvider;
// Implement your database provider
class MyDatabaseProvider implements DatabaseProvider
{
// Implement required methods...
}
$db = new MyDatabaseProvider();
$validator = Validator::make([
'email' => 'required|email|unique:users,email',
'category_id' => 'required|exists:categories,id',
], $db);Benefits:
- π Automatic batching - Multiple checks become one query
- π― Update support -
unique:users,email,5ignores ID 5 - π§Ύ Soft-delete aware unique -
unique:users,email,,id,false,deleted_at
$jsonSchema = $validator->exportSchema('json_schema');
$openApiShape = $validator->exportSchema('openapi');
$introspection = $validator->exportSchema('introspection');For maximum performance, stop all validation on first error:
$validator = Validator::make($rules)
->setStopOnFirstError(true);
// Stops immediately when any field fails
$result = $validator->validate($data);ReqShield is built for speed:
Rules automatically execute in order of complexity:
- Cheap (< 50): Type checks, empty checks
- Medium (50-99): String operations, regex
- Expensive (100+): Database queries, API calls
Database rules are automatically batched:
// 3 separate rules...
'user_id' => 'exists:users,id',
'email' => 'unique:users,email',
'category_id' => 'exists:categories,id',
// ...become just 2 queries (50x faster!)
// - One batch for exists checks
// - One batch for unique checksStops validating a field on first rule failure:
'email' => 'required|email|max:255'
// If empty β fails on 'required', skips 'email' and 'max:255'Nested validation only activates if you use dot notation. No performance cost for simple flat arrays.
ReqShield is open-sourced software licensed under the MIT license.
If you find ReqShield helpful, please consider giving it a βοΈ on GitHub!
Made with β€οΈ for the PHP community
Documentation β’ Report Bug β’ Request Feature