Search by

phatnt93 / phalcon-validation

phatnt93

High-performance, expressive PHP data validation and sanitization library for Phalcon Framework v5, inspired by GUMP. Features 80+ validators, 17 filters, nested wildcard arrays, file upload validation, and Phalcon MVC Model ORM integration.

Package info

github.com/phatnt93/phalcon-validation

pkg:composer/phatnt93/phalcon-validation

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2.0 2026-10-15 14:01 UTC

This package is auto-updated.

Last update: 2026-10-15 15:09:03 UTC


README

English | TiαΊΏng Việt

Latest Version PHP Version Phalcon Support Build Status License: MIT

A fast, flexible, expressive, and human-friendly PHP Data Validation and Sanitization library for Phalcon Framework v5, inspired by the minimalist syntax of Wixel/GUMP and integrated with Phalcon\Filter\Validation.

Table of Contents

  1. Why Use This Library?
  2. Architecture and Two Execution Paths
  3. System Requirements
  4. Installation
  5. Detailed Usage Guide
  6. Nested Arrays and Wildcards
  7. Field Aliases and Multi-Language Localization
  8. Database ORM Validation (Unique and Exists)
  9. File Upload Validation and Normalization
  10. 17 Built-in Data Filters (Sanitizers)
  11. 80+ Built-in Validators
  12. Custom Validators and Custom Filters
  13. Automated Testing
  14. Using with AI Coding Agents
  15. Publishing to Packagist

1. Why Use This Library?

In the official Phalcon 5 documentation (docs.phalcon.io/5.22/filter-validation), setting up validation is quite verbose and requires manual instantiation and attachment of separate validator classes for each field:

πŸ”΄ Phalcon 5 Native (Verbose):

use Phalcon\Filter\Validation;
use Phalcon\Filter\Validation\Validator\PresenceOf;
use Phalcon\Filter\Validation\Validator\Email;
use Phalcon\Filter\Validation\Validator\StringLength;
use Phalcon\Filter\Validation\Validator\Alnum;

$validation = new Validation();
$validation->add('username', new PresenceOf(['message' => 'Username is required']));
$validation->add('username', new Alnum(['message' => 'Username must be alphanumeric']));
$validation->add('username', new StringLength(['min' => 3, 'max' => 30]));

$validation->add('email', new PresenceOf(['message' => 'Email is required']));
$validation->add('email', new Email(['message' => 'Email is invalid']));

// Sanitization requires a separate Filter service:
$filter = (new \Phalcon\Filter\FilterFactory())->newInstance();
$data['username'] = $filter->sanitize($_POST['username'], 'trim');
$data['email']    = $filter->sanitize($_POST['email'], 'email');

$messages = $validation->validate($data);

🟒 With phalcon-validation (Clean & Expressive):

use PhalconValidation\PhalconValidation;

$cleanData = PhalconValidation::run($_POST, [
    'username' => 'required|alpha_numeric|min_len,3|max_len,30',
    'email'    => 'required|valid_email',
], [
    'username' => 'trim|lower_case',
    'email'    => 'trim|lower_case|sanitize_email',
]);

if ($cleanData === false) {
    // Validation failed
} else {
    // $cleanData is sanitized and guaranteed valid!
}

2. Architecture and Two Execution Paths

The library provides two clean, distinct execution paths depending on your application needs:

                                [Rule Definitions & Input Data]
                                               β”‚
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β”‚                                                           β”‚
                 β–Ό                                                           β–Ό
     [Path 1: Standard Engine]                                   [Path 2: Native Bridge]
   Validator::run(), Facade run()                           PhalconValidationAdapter::build()
        and DI $this->validator                                              β”‚
                 β”‚                                                           β–Ό
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”                                     Returns Phalcon\Filter\Validation
         β–Ό               β–Ό                                                   β”‚
  4 C-Native Filters   81 PHP Rules                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  (trim, lower, upper, (Arr, Str, Wildcards,                       β–Ό                   β–Ό
   sanitize_email)     Fail-fast, i18n en/vi)              14 Native C Rules   68 Extended Rules
                                                          (PresenceOf, Email, (Bridged via Phalcon
                                                           StringLength,...)   Callback Validator)

Path 1: Standard Engine (Validator::run(), PhalconValidation::run(), $this->validator)

This is the default path when calling run(), validate(), or using the DI service:

  • Validation Engine: Executes through RuleEngine across 81 PHP Rule classes. This path handles advanced capabilities that Phalcon's C-core does not natively provide:
    • Multidimensional dot-notation resolution (customer.profile.email).
    • Wildcard array expansion (items.*.price, order_items.*.qty).
    • Fail-fast validation per field.
    • Automatic optional field handling (non-presence rules are skipped when fields are left blank).
    • Human-friendly field aliases and dual-language error messaging (en, vi).
  • Automatic C-Extension Sanitizer Integration: In FilterEngine, 4 filters that match Phalcon's native behavior (trim, lower_case, upper_case, sanitize_email) automatically delegate to Phalcon\Filter\Filter native C-sanitizers for maximum throughput.
  • Database ORM: Automatically queries Phalcon MVC Models ($modelClass::count(...)) for unique and exists rules.

Path 2: Phalcon Native Bridge (PhalconValidationAdapter::build())

This path is only activated when explicitly invoked via PhalconValidationAdapter::build($rules). It converts your rules into a native Phalcon\Filter\Validation C-extension instance:

  • Same verdict as Path 1: for the same rules and data, PhalconValidationAdapter::build($rules)->validate($data) passes or fails exactly like Validator::is_valid($data, $rules). A parity test runs every natively mapped rule against empty, Unicode, signed, float, date, boolean and array input.
  • 14 rules run on native C-Validators: required (PresenceOf), valid_email (Email), valid_url (Url), valid_ip/valid_ipv4/valid_ipv6 (Ip), min_len/max_len/exact_len/between_len (StringLength), alpha (Alpha), equalsfield (Confirmation), date,<format> (Date), required_file (File).
    • Non-presence validators get allowEmpty for '', null and [], so optional fields are skipped as in Path 1 ('0', 0 and false are still validated).
    • required, alpha, the length rules and equalsfield are wrapped in a Callback type guard that rejects array/object input and otherwise delegates to the C-validator.
  • 68 rules bridged via Phalcon\Filter\Validation\Validator\Callback: Advanced rules such as strong_password, uuid, jwt_token, iban, even, odd, prime, word_count, valid_name,... are wrapped in Phalcon's native Callback validator. No rule is ever dropped silently.
    • This includes rules whose native Phalcon validator behaves differently: alpha_numeric and integer (native Alnum/Digit are ASCII-only and unsigned), numeric (native Numericality accepts 8.8.8.8, rejects 1e3), date without a format (ISO 8601 in PHP, Y-m-d natively), regex (native Regex requires a full-string match), and between_numeric, contains, doesnt_contain_list (native validators accept booleans).
  • Localized messages: every validator, native or bridged, gets its message from the global Translator, with field aliases, {param:n} placeholders and the current locale.
  • Known difference: Path 1 stops at the first failing rule per field (fail-fast), while Phalcon runs every validator of a field, so a field can return more than one message.
  • Explicit Error Handling: Throws RuleNotFoundException if an unknown rule name is supplied.

3. System Requirements

  • PHP Compatibility Targets: PHP >= 8.1 (compatible with PHP 8.1, 8.2, 8.3, and 8.4).
  • Actively Tested Environment: PHP 8.3.6 (CLI NTS x64) with Phalcon Extension 5.8.0 (the full PHPUnit suite passes; CI also runs PHP 8.1–8.4 with a 90% line coverage gate).
  • Phalcon Framework Target: ext-phalcon: ^5.0 (optional for stand-alone mode, recommended for native C acceleration and DI integration). Phalcon v6 is not supported yet.
  • Required PHP Extensions: mbstring (multibyte UTF-8 string handling).

4. Installation

Install via Composer:

composer require phatnt93/phalcon-validation

5. Detailed Usage Guide

Method 1: Static One-Liner Shorthand

Best suited for API Controllers or Micro Applications:

use PhalconValidation\PhalconValidation;

$data = [
    'username' => '  john_doe  ',
    'email'    => 'JOHN@EXAMPLE.COM',
    'age'      => '25',
];

$rules = [
    'username' => 'required|alpha_dash|min_len,3|max_len,20',
    'email'    => 'required|valid_email',
    'age'      => 'numeric|between_numeric,18;65',
];

$filters = [
    'username' => 'trim|lower_case',
    'email'    => 'trim|lower_case|sanitize_email',
];

// Execute filtering and validation in one call:
$clean = PhalconValidation::run($data, $rules, $filters);

if ($clean === false) {
    echo "Invalid input!";
} else {
    // $clean contains sanitized and verified data:
    // ['username' => 'john_doe', 'email' => 'john@example.com', 'age' => '25']
    echo "Welcome, " . $clean['username'];
}

Quick Boolean Check:

$isValid = PhalconValidation::isValid($_POST, [
    'title' => 'required|min_len,5',
    'slug'  => 'required|url_slug',
]);

if ($isValid === true) {
    echo "Valid input!";
} else {
    // $isValid is an array of error messages:
    print_r($isValid);
}

Method 2: Instance Fluent API (GUMP Style)

Supports standard GUMP configuration methods:

use PhalconValidation\Validator;

$validator = new Validator('en'); // Default is 'en', or 'vi' for Vietnamese

// 1. Declare validation rules
$validator->validation_rules([
    'username' => 'required|alpha_numeric|min_len,3|max_len,30',
    'password' => 'required|strong_password',
    'confirm'  => 'required|equalsfield,password',
]);

// 2. Declare sanitization filters
$validator->filter_rules([
    'username' => 'trim|lower_case',
]);

// 3. Run (supports optional $check_fields to disallow undeclared input keys)
$clean = $validator->run($_POST, $check_fields = true);

if ($clean === false) {
    // Key-value error array: ['username' => 'The Username field is required.']
    $errorsArray = $validator->get_errors_array();

    // Or formatted HTML list:
    echo $validator->get_readable_errors(true);
} else {
    // Save to database...
}

Method 3: Phalcon Controller Integration via DI Container

Register the service provider once in your Phalcon application bootstrap:

use Phalcon\Di\FactoryDefault;
use PhalconValidation\Adapters\Phalcon\ValidationServiceProvider;

$di = new FactoryDefault();
// Registers the 'validator' service:
$di->register(new ValidationServiceProvider());

Use directly inside any Controller:

namespace App\Controllers;

use Phalcon\Mvc\Controller;

class AuthController extends Controller
{
    public function registerAction()
    {
        // Resolve validator service from DI container:
        $validator = $this->validator; // or $this->di->getShared('validator')

        $data = $validator->run($this->request->getPost(), [
            'username' => 'required|alpha_numeric|min_len,3|unique,App\Models\Users,username',
            'email'    => 'required|valid_email|unique,App\Models\Users,email',
            'password' => 'required|strong_password',
        ], [
            'username' => 'trim|lower_case',
            'email'    => 'trim|lower_case|sanitize_email',
        ]);

        if ($data === false) {
            $this->flash->error($validator->get_readable_errors(true));
            return $this->response->redirect('/register');
        }

        // Create new user with verified clean data:
        $user = new \App\Models\Users();
        $user->assign($data);
        $user->save();
    }
}

Method 4: Building a Native Phalcon Validation Object

If you need a pure Phalcon\Filter\Validation instance for model validation or legacy Phalcon workflows:

use PhalconValidation\Adapters\Phalcon\PhalconValidationAdapter;

$rules = [
    'email'    => 'required|valid_email|min_len,5',
    'password' => 'required|strong_password', // Automatically bridged via native Callback validator
];

// Returns a native Phalcon\Filter\Validation instance:
$nativeValidation = PhalconValidationAdapter::build($rules);

// Execute via Phalcon's native C-engine:
$messages = $nativeValidation->validate($_POST);

if (count($messages) > 0) {
    foreach ($messages as $message) {
        echo $message->getMessage() . '<br>';
    }
}

Method 5: Rich Result Object (validateData() / PhalconValidation::check())

When you need the sanitized data and the errors at the same time, use validateData() on an instance (PhalconValidation::create($lang) returns a new Validator) or the static PhalconValidation::check(). Both return a ValidationResult:

use PhalconValidation\PhalconValidation;

$result = PhalconValidation::check(
    ['email' => ' A@B.COM ', 'age' => 'x'],
    ['email' => 'required|valid_email', 'age' => 'integer'],
    ['email' => 'trim|lower_case'],
);
// Same as: PhalconValidation::create('en')->validateData($data, $rules, $filters);

$result->isValid();         // false
$result->getData();         // filtered data, returned even when validation fails
$result['email'];           // 'a@b.com' (ValidationResult implements ArrayAccess)
$result->getErrorsArray();  // ['age' => 'The Age field must be an integer.']
$result->getErrors();       // [['field' => 'age', 'rule' => 'integer', 'message' => '...', 'params' => []]]
$result->getReadableErrors(); // list of messages (pass true for HTML)

6. Nested Arrays and Wildcards

Easily validate nested JSON payloads or array collections:

$data = [
    'customer' => [
        'name' => 'Alice',
        'email' => 'alice@example.com',
    ],
    'items' => [
        ['product_id' => 101, 'qty' => 2, 'price' => 50],
        ['product_id' => 102, 'qty' => 1, 'price' => 120],
    ],
];

$rules = [
    'customer.name'       => 'required|min_len,2',
    'customer.email'      => 'required|valid_email',
    'items.*.product_id'  => 'required|integer',
    'items.*.qty'         => 'required|integer|min_numeric,1',
    'items.*.price'       => 'required|numeric|min_numeric,0',
];

$filters = [
    'customer.name'  => 'trim',
    'customer.email' => 'trim|lower_case',
];

$clean = PhalconValidation::run($data, $rules, $filters);

Array and Object Values

Rules that expect a string or number fail (they never throw or raise warnings) when the field holds an array or object, for example min_len,3 with tags[]=x. Validate list items with wildcards (tags.*) instead. An empty array counts as an empty value, so non-presence rules skip it and required fails.

7. Field Aliases and Multi-Language Localization

7.1. Built-in Languages

The library includes complete language dictionaries for:

  • en: English (default and fallback)
  • vi: Vietnamese
$validator = new Validator();       // 'en' by default
$validator = new Validator('vi');   // Vietnamese
$validator->setLocale('vi_VN');     // regional codes fall back to the base language ('vi')

Locale codes are case-insensitive and accept - or _ (EN, en-us, vi_VN). Malformed codes (for example ../en) throw PhalconValidation\Exceptions\InvalidLocaleException. A well-formed locale without a dictionary falls back to en, and any message missing from the current locale also falls back to en.

Adding your own language

$validator = new Validator('fr');
$validator->addTranslations('fr', [
    'required'    => 'Le champ {field} est obligatoire.',
    'valid_email' => 'Le champ {field} doit Γͺtre une adresse e-mail valide.',
]);

Keep the placeholders ({field}, {param}, {param:0}...) identical to the English template.

7.2. Setting Field Aliases

Replace technical keys (items.1.price) with natural labels:

$validator->setFieldNames([
    'customer.email' => 'Customer Email Address',
    'items.*.price'  => 'Product Price',
    'items.*.qty'    => 'Order Quantity',
]);

Error output: The Product Price field must be a number greater than or equal to 0.

7.3. Custom Error Messages

$validator->set_fields_error_messages([
    'customer.email' => [
        'required'    => 'Please provide your email address.',
        'valid_email' => 'The provided email is not valid.',
    ],
]);

7.4. Global Aliases and Messages (GUMP Static Setters)

The GUMP-style static setters configure every Validator instance, Validator::is_valid() and PhalconValidationAdapter::build(). Instance settings (setFieldNames(), set_fields_error_messages()) take precedence.

Validator::set_field_name('age', 'Your age');
Validator::set_field_names(['email' => 'Email address']);
Validator::set_error_message('integer', '{field} must be a whole number.');
Validator::set_error_messages(['required' => '{field} cannot be empty.']);

Validator::is_valid(['age' => 'x'], ['age' => 'integer']);
// ['Your age must be a whole number.']

8. Database ORM Validation (Unique and Exists)

Integrated directly with Phalcon MVC Models:

  • unique,ModelClass,column,[ignoreIdCol],[ignoreIdVal]: Verifies that value does not exist in database table.
  • exists,ModelClass,column: Verifies that foreign key or record exists in database table.

Example:

$rules = [
    // Verify that username is unique in Users table:
    'username' => 'required|unique,App\Models\Users,username',

    // When updating user with ID 15, ignore row with id=15:
    'email'    => 'required|valid_email|unique,App\Models\Users,email,id,15',

    // Verify category_id exists in Categories table:
    'category_id' => 'required|exists,App\Models\Categories,id',
];

If the model class is missing or misspelled, both rules throw PhalconValidation\Exceptions\InvalidRuleConfigurationException instead of reporting the field as invalid, so configuration mistakes surface during development. Empty optional fields are still skipped before this check.

9. File Upload Validation and Normalization

Phalcon-Validation provides out-of-the-box support for single and multi-file uploads, combining the safety of Phalcon v5 with concise GUMP-like syntax:

9.1. Five Specialized File Upload Validators

  • required_file: Ensures a file was uploaded successfully (UPLOAD_ERR_OK, file size > 0, non-empty filename).
  • extension,ext1;ext2: Validates file extension against allowed list (pdf;docx;png;jpg).
  • mimetype,type1;type2: Inspects real binary content on disk via finfo_file (prevents malicious file disguise, alias: mime_type).
  • max_file_size,limit: Limits maximum file size (supports human units like 2mb, 500kb, 1048576).
  • min_file_size,limit: Enforces minimum file size (e.g. 10kb, 1024).

9.2. Normalization Filter (normalize_files)

PHP native $_FILES organizes multi-file inputs awkwardly (e.g. $_FILES['photos']['name'][0]). The normalize_files filter (alias: normalize_file) automatically transforms single/multi-file uploads or Phalcon FileInterface objects into a clean, sequential list of file arrays:

$data = [
    'title'  => '  My Vacation Photos  ',
    'avatar' => $_FILES['avatar'], // Single native file
    'photos' => $_FILES['photos'], // Multiple native files (<input name="photos[]" multiple>)
];

$rules = [
    'title'  => 'required|min_len,3',
    'avatar' => 'required_file|extension,png;jpg|mimetype,image/png;image/jpeg|max_file_size,2mb',
    'photos' => 'required_file|extension,png;jpg|mimetype,image/png;image/jpeg|max_file_size,5mb',
];

$filters = [
    'title'  => 'trim',
    'photos' => 'normalize_files', // Transforms $_FILES['photos'] into clean array list
];

$result = PhalconValidation::run($data, $rules, $filters);

9.3. Polymorphic Input Support

Every file validator automatically detects and validates:

  1. Single File: ['name' => 'photo.png', 'tmp_name' => '/tmp/xyz', 'size' => 1024, 'error' => 0]
  2. PHP Native Multi-File: Raw $_FILES arrays with multi-key arrays.
  3. Normalized Array List: Sequential file arrays after normalize_files (or wildcard rules: 'photos.*' => 'extension,png;jpg').
  4. Phalcon File Object: Instances of Phalcon\Http\Request\File.
  5. Path String: Direct file path string on server disk.

10. 17 Built-in Data Filters (Sanitizers)

Filter Description Example
trim Strip whitespace from start/end (Phalcon native C). ' abc ' -> 'abc'
sanitize_string Strip <script> tags and clean dangerous HTML (XSS prevention). '<script>bad</script><b>Hi</b>' -> 'Hi'
sanitize_email Remove illegal email characters (Phalcon native C). 'john @ex .com' -> 'john@ex.com'
sanitize_numbers Keep only digits 0-9, + and -. '+84-90-123' -> '+84-90-123'
sanitize_floats Keep only digits, +, -, and decimal point .. 'Price: $12.50' -> '12.50'
boolean Convert ['1', 1, 'true', true, 'yes', 'on'] to true, else false. 'on' -> true, 'no' -> false
basic_tags Keep safe HTML tags (<b>, <i>, <p>), strip scripts. '<p><b>OK</b><script></script></p>' -> '<p><b>OK</b></p>'
whole_number Cast to integer via intval() (preserves negatives). '42.8' -> 42, '-15.5' -> -15
ms_word_characters Normalize MS Word quotes and dashes to web-safe characters. β€œHello” -> "Hello", β€˜It’ -> 'It'
lower_case Convert to lowercase UTF-8 (Phalcon native C). 'HELLO' -> 'hello'
upper_case Convert to uppercase UTF-8 (Phalcon native C). 'hello' -> 'HELLO'
slug Convert to URL slug (supports Vietnamese accents). 'TiΓͺu Đề BΓ i ViαΊΏt' -> 'tieu-de-bai-viet'
urlencode URL-encode string characters. 'a b!' -> 'a+b%21'
htmlencode Convert HTML characters to HTML entities. '<b>"Hi"</b>' -> '&lt;b&gt;&quot;Hi&quot;&lt;/b&gt;'
rmpunctuation Strip all punctuation characters from string. 'Hello, World!' -> 'Hello World'
noise_words Strip stop-words/noise words from text. 'the quick brown fox' -> 'quick brown fox'
normalize_files Normalize native PHP $_FILES (multi/single) into clean array list (alias: normalize_file). $_FILES['photos'] -> [['name' => 'a.jpg', ...], ...]

11. 80+ Built-in Validators

11.1. Presence

  • required: Field must be present and not empty (not null, "", []).
  • required_file: File must be uploaded without errors (UPLOAD_ERR_OK). Intelligently adapts to single files, native PHP $_FILES multiple arrays, normalized file lists, and Phalcon File objects.

11.2. Strings & Length

  • min_len,n: Minimum string length.
  • max_len,n: Maximum string length.
  • exact_len,n: Exact string length.
  • between_len,min;max: String length within inclusive range.
  • word_count,min,v1,max,v2: Word count within specified range.

11.3. Characters & Naming Conventions

  • alpha: Alphabetic characters only.
  • alpha_numeric: Alphanumeric characters only.
  • alpha_dash: Letters, hyphens -, and underscores _.
  • alpha_numeric_dash: Letters, digits, hyphens -, and underscores _.
  • alpha_numeric_space: Letters, digits, and spaces.
  • alpha_space: Letters and spaces.
  • camel_case: Validates camelCase format.
  • snake_case: Validates snake_case format.
  • url_slug: Validates URL slug format.

11.4. Numeric & Mathematics

  • numeric: Valid number or numeric string.
  • integer: Valid integer.
  • float: Valid float number.
  • boolean,[strict]: Boolean value (yes/no, 1/0, true/false; strict requires boolean type).
  • min_numeric,n: Number >= n.
  • max_numeric,n: Number <= n.
  • between_numeric,min;max: Number between min and max (inclusive).
  • even: Number must be even.
  • odd: Number must be odd.
  • prime: Number must be prime.
  • starts,prefix: Starts with specified prefix.

11.5. Field Comparison & Regex

  • equalsfield,target_field: Equals another field's value (e.g. password confirmation).
  • regex,pattern: Matches regular expression pattern.

11.6. Network & Web

  • valid_email: Valid email address format.
  • valid_url: Valid URL format.
  • url_exists,[allow_private]: http/https URL that answers a HEAD request with a 2xx/3xx status (redirects are not followed, 5 s timeout). To prevent SSRF, hosts resolving to private or reserved addresses (10.0.0.0/8, 127.0.0.1, 169.254.169.254, ...) are rejected unless allow_private is given. The rule sends a network request for every value, so prefer valid_url unless reachability really matters.
  • valid_ip: Valid IP address (IPv4 or IPv6).
  • valid_ipv4: Valid IPv4 address.
  • valid_ipv6: Valid IPv6 address.
  • mac_address: Valid network MAC address.
  • domain_name: Valid domain name without scheme.
  • port_number: Port number between 1 and 65535.
  • social_handle: Social media username handle (@username).
  • valid_name: Human name format.

11.7. Date & Time

  • date,[format]: Valid calendar date. Without a format only ISO 8601 values are accepted (Y-m-d, Y-m-d H:i[:s], Y-m-d\TH:i[:s], optional +07:00/Z offset); relative strings such as now or tomorrow are rejected. With a format (e.g. date,d/m/Y) the value must match it exactly.
  • date_range,start;end;[format]: Date between start and end (inclusive). The value and both bounds use the format, e.g. date_range,01/01/2024;31/12/2024;d/m/Y.
  • future_date,[format]: Date in the future.
  • past_date,[format]: Date in the past.
  • business_day,[format]: Date is a weekday (Monday to Friday).
  • valid_time: Time format (HH:MM:SS or HH:MM).
  • min_age,years,[format]: Age from birthdate >= minimum years (e.g. min_age,18,d/m/Y). Birth dates in the future fail.

Note: like date, these rules accept only ISO 8601 values when no format is given, and the exact format otherwise. Relative or free-form strings (tomorrow, next monday, 15 March 1990) and overflowing dates (2024-02-30) are rejected. A date without a time means midnight, so past_date accepts today's date.

11.8. Locations & Geo

  • latitude: Latitude coordinate (-90 to 90).
  • longitude: Longitude coordinate (-180 to 180).
  • coordinates: Coordinates in lat,lng format.
  • street_address: Street address structure.

11.9. ISO Standards

  • country_code: ISO 3166-1 alpha-2 or alpha-3 country code.
  • currency_code: ISO 4217 currency code (USD, EUR, VND,...).
  • language_code: ISO 639 language code (en, vi, fr,...).
  • timezone: Valid timezone identifier (Asia/Ho_Chi_Minh, UTC,...).

11.10. Security & Finance

  • valid_cc: Credit card number (Luhn algorithm).
  • iban: International Bank Account Number.
  • uuid: UUID string format.
  • guidv4: GUID version 4 format.
  • jwt_token: JWT token format.
  • hash,algo: Cryptographic hash format (md5, sha1, sha256,...).
  • base64: Base64 encoded string.
  • strong_password: Strong password (upper, lower, digit, symbol, len >= 8).
  • no_sql_injection: Detects SQL injection vectors.
  • no_xss: Detects XSS script injection vectors.
  • phone_number: Phone number format.

11.11. Color

  • hex_color: Hex color code (#FFFFFF, #FFF, FFFFFF).
  • rgb_color: RGB / RGBA color with channels bounded between 0 and 255.

11.12. Content, Arrays & JSON

  • contains,v1;v2: Value is in allowed list (displays allowed list in error).
  • contains_list,v1;v2: Value is in allowed list (hides allowed list in error).
  • doesnt_contain_list,v1;v2: Value is not in disallowed list.
  • valid_json_string: Valid JSON string.
  • valid_array_size_equal,n: Array has exactly n elements.
  • valid_array_size_greater,n: Array has at least n elements.
  • valid_array_size_lesser,n: Array has at most n elements.

11.13. File Uploads

  • extension,ext1;ext2: Allowed file extensions (pdf;docx;png). Intelligently validates single files, native PHP $_FILES multiple arrays, normalized file lists, filename strings, and Phalcon File objects.
  • mimetype,type1;type2: Allowed MIME types (image/png;image/jpeg;application/pdf). Inspects real binary content via finfo (or Phalcon\Http\Request\File::getRealType()). The client-provided type is never trusted: a file that is not available on disk fails (alias: mime_type).
  • max_file_size,limit: Maximum allowed file size (supports units like 2mb, 500kb, 1048576).
  • min_file_size,limit: Minimum allowed file size (supports units like 10kb, 1024).

12. Custom Validators and Custom Filters

Registering Custom Validators

use PhalconValidation\Validator;

Validator::add_validator('is_divisible_by', function ($field, $value, $params, $data) {
    $divisor = (int)($params[0] ?? 1);
    return is_numeric($value) && ((int)$value % $divisor === 0);
}, 'The {field} field must be divisible by {param:0}.');

// Use in rules:
$rules = ['score' => 'required|is_divisible_by,5'];

Registering Custom Filters

use PhalconValidation\Validator;

Validator::add_filter('prefix', function ($value, $params) {
    $prefix = $params[0] ?? 'PREFIX_';
    return $prefix . $value;
});

// Use in filters:
$filters = ['code' => 'prefix,ORDER_'];

13. Automated Testing

The library is covered by an automated PHPUnit test suite (unit + integration). Integration tests are skipped automatically when ext-phalcon is not loaded.

# Run test suite
composer test

# Static analysis and code style
composer analyse
composer cs:check

# Or directly through PHPUnit CLI
php vendor/bin/phpunit

14. Using with AI Coding Agents

This package ships llms.txt and llms-full.txt for AI assistants. Add this snippet to your project's AGENTS.md (or Cursor/Copilot rules):

- Use `phatnt93/phalcon-validation` for request/form validation and sanitization.
- API summary: vendor/phatnt93/phalcon-validation/llms.txt
- Full rule and filter reference: vendor/phatnt93/phalcon-validation/llms-full.txt

15. Publishing to Packagist

To distribute this library for composer installation:

  1. Push this repository to GitHub: https://github.com/phatnt93/phalcon-validation.
  2. Tag a release version: git tag vX.Y.Z && git push origin vX.Y.Z.
  3. Submit the repository URL to Packagist.org.
  4. Users can now install it anywhere: composer require phatnt93/phalcon-validation.

License

This software is open-sourced under the MIT License. Author: Phat Nguyen (phatnt93@gmail.com).