dev-utils Pure PHP Data Validation & Formatting Library
Complete pure PHP library for data validation, string formatting, array manipulation, and general utilities. Fully tested with PHPUnit and validated with PHPStan level 10 and SonarQube and PHPCS.
- Robust data validation - Email, CPF, CNPJ, dates, time, phone, file uploads and more
- String formatting - Type conversion, currency, date and text formatting
- Array manipulation - Search, filter, sort and transform arrays
- File upload validation - File type, MIME type, image dimensions, size
- General utilities - UUID, comparisons, arrays and string operations
- 100% tested - PHPUnit + PHPStan level 10 + SonarQube + PHPCS
- Code Quality - Validated with industry-standard tools
- Quick Start
- Installation
- Common Use Cases
- Data Validation
- File Upload Validation
- Validation Types
- Custom Messages
- String Formatting
- Data Comparison
- Validation Methods
- Generation Utilities
- Array Manipulation
- General Utilities
<?php
require 'vendor/autoload.php';
use DevUtils\Validator;
$data = ['email' => 'user@example.com'];
$rules = ['email' => 'required|email'];
$validator = new Validator();
$validator->set($data, $rules);
if (!$validator->getErros()) {
echo '✓ Validation successful!';
} else {
var_dump($validator->getErros());
}Install using Composer:
composer require brunoconte3/dev-utilsOr add to your composer.json:
{
"require": {
"brunoconte3/dev-utils": "2.15.1"
}
}Requirements:
- PHP >= 8.3
- Composer
- ✓ Pure PHP - Zero external dependencies
- ✓ Fully tested - PHPUnit + PHPStan Level 10 + SonarQube
- ✓ Code Quality - Validated with PHPCS standards
- ✓ Professional Code - Production-ready quality
- ✓ Complete Documentation - Examples for each validator
- ✓ Active Maintenance - Regular updates
Validate email, CPF/CNPJ, phone and other data in a single validator.
Control file size, MIME type, image dimensions and filename.
Format currencies, dates, strings and perform type conversions.
Ensure received data meets your business criteria.
Search, sort, filter and transform arrays with ready-to-use methods.
$data = [
'name' => 'Bruno Conte',
'email' => 'bruno@example.com',
'newPassword' => '123456',
];$rules = [
'name' => 'required|alpha|min:7|max:100',
'email' => 'required|email|max:80',
'newPassword' => 'required|email|max:50',
];<?php
require 'vendor/autoload.php';
use DevUtils\Validator;
$validator = new Validator();
$validator->set($data, $rules);
if (!$validator->getErros()) {
echo '✓ Validation successful!';
} else {
var_dump($validator->getErros());
}Validate file uploads with validators: fileName, maxFile, maxUploadSize, mimeType, minFile, minUploadSize, minHeight, minWidth, maxHeight, maxWidth and requiredFile.
Control minimum/maximum file size (bytes), number of files, allowed extensions, image dimensions, filename and field requirements.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Upload de Arquivos</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data">
<!-- Upload a single file -->
<input type="file" name="fileUploadSingle" />
<!-- Upload single or multiple files -->
<input type="file" name="fileUploadMultiple[]" multiple="multiple" />
<button type="submit">Submit</button>
</form>
</body>
</html><?php
/**
* Notes:
* - maxFile, minFile, minHeight, minWidth, maxUploadSize, maxHeight, maxWidth, minUploadSize: Must be integers
* - mimeType: Pass an array with allowed extensions, separated by ';'
*/
if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST') {
$fileUploadSingle = $_FILES['fileUploadSingle'];
$fileUploadMultiple = $_FILES['fileUploadMultiple'];
$datas = [
'fileUploadSingle' => $fileUploadSingle,
'fileUploadMultiple' => $fileUploadMultiple,
];
$rules = [
'fileUploadSingle' => 'requiredFile|fileName|mimeType:jpeg;png;jpg;txt;docx;xlsx;pdf|minUploadSize:10|maxUploadSize:100|minWidth:200|maxWidth:200',
'fileUploadMultiple' => 'fileName|mimeType:jpeg|minFile:1|maxFile:3|minUploadSize:10|minWidth:200|maxWidth:200|maxUploadSize:100',
];
$validator = new DevUtils\Validator();
DevUtils\Format::convertTypes($datas, $rules);
$validator->set($datas, $rules);
if (!$validator->getErros()) {
echo '✓ Files validated successfully!';
} else {
echo '<pre>';
print_r($validator->getErros());
}
}
?>Complete list of available validators in the library. Use them in your validation rules to ensure data meets your business criteria.
| Validator | Description |
|---|---|
| alpha | Only alphabetic characters |
| alphaNoSpecial | Regular text without accents |
| alphaNum | Alphanumeric characters |
| alphaNumNoSpecial | Letters without accents + numbers |
| lower | All lowercase characters |
| notSpace | Check if contains spaces |
| regex | Custom regular expression validation |
| upper | All uppercase characters |
| Validator | Description |
|---|---|
| companyIdentification | Validates CNPJ with or without mask |
| ddd | Validates DDD by state or general (e.g. ddd:pr) |
| identifier | Validates CPF with or without mask |
| identifierOrCompany | Validates CPF or CNPJ |
| phone | Phone with DDD (10 or 11 digits) |
| plate | Vehicle license plate |
| Validator | Description |
|---|---|
| dateAmerican | American date format (MM/DD/YYYY) |
| dateBrazil | Brazilian date format (DD/MM/YYYY) |
| dateIso8601 | ISO 8601 date (2025-11-20T10:30:00Z) |
| dateNotFuture | Validates date is not in the future |
| dateUTCWithoutTimezone | UTC date without Z (2025-11-20T10:30:00) |
| hour | Validates hour format |
| noWeekend | Checks if date is not a weekend |
| numMonth | Validates month (1-12) |
| timestamp | Validates Unix timestamp |
| Validator | Description |
|---|---|
| array | Check if it is an array |
| bool | Boolean values (true/false, 1/0, yes/no) |
| float | Decimal/floating value |
| int | Integer type (attempts parse) |
| integer | Integer with strict type check |
| json | Valid JSON |
| numeric | Only numeric values (accepts leading zeros) |
| Validator | Description |
|---|---|
| equals | Field must equal another field |
| max | Maximum size |
| maxWords | Maximum number of words |
| min | Minimum size |
| minWords | Minimum number of words |
| optional | Validates only if not empty |
| required | Required field |
| Validator | Description |
|---|---|
| Email validation | |
| ip | Valid IP address |
| mac | Valid MAC address |
| rgbColor | Valid RGB color |
| Validator | Description |
|---|---|
| numMax | Maximum value (minimum = 0) |
| numMin | Minimum value (minimum = 0) |
| Validator | Description |
|---|---|
| fileName | Validates and formats filename |
| maxFile | Maximum number of files |
| maxHeight | Maximum image height (pixels) |
| maxUploadSize | Maximum file size (bytes) |
| maxWidth | Maximum image width (pixels) |
| minFile | Minimum number of files |
| minHeight | Minimum image height (pixels) |
| minUploadSize | Minimum file size (bytes) |
| minWidth | Minimum image width (pixels) |
| mimeType | Defines allowed extensions (separated by ;) |
| requiredFile | Required file field |
After defining some of our rules to the data you can also add a custom message using the ',' delimiter in some specific rule or using the default message.
Example:
<?php
$validator->set($datas, [
'name' => 'required, The name field cannot be empty',
'email' => 'email, The email field is incorrect|max:50',
'password' => 'min:8, nat least 8 characters|max:12, no máximo 12 caracteres.',
]);<?php
require 'vendor/autoload.php';
use DevUtils\Format;
Format::companyIdentification('A1B2C3D45E6F59'); //CNPJ ==> A1.B2C.3D4/5E6F-59
Format::convertTimestampBrazilToAmerican('15/04/2021 19:50:25'); //Convert Timestamp Brazil to American format
Format::currency('113', 'R$ '); //Default currency BR ==> 123.00 - the 2nd parameter chooses the Currency label
Format::currencyUsd('1123.45'); //Default currency USD ==> 1,123.45 - the 2nd parameter chooses the Currency label
Format::dateAmerican('12-05-2020'); //return date ==> 2020-05-12
Format::dateBrazil('2020-05-12'); //return date ==> 12/05/2020
Format::identifier('73381209000'); //CPF ==> 733.812.090-00
Format::identifierOrCompany('30720870089'); //CPF/CNPJ Brazil ==> 307.208.700-89
Format::falseToNull(false); //Return ==> null
Format::lower('CArrO'); //lowercase text ==> carro - the 2nd parameter chooses the charset, UTF-8 default
//[Apply any type of Mask, accepts space, points and others]
Format::mask('#### #### #### ####', '1234567890123456'); //Mask ==> 1234 5678 9012 3456
Format::maskStringHidden('065.775.009.96', 3, 4, '*'); //Mask of string ==> 065.***.009.96
Format::onlyNumbers('548Abc87@'); //Returns only numbers ==> 54887;
Format::onlyLettersNumbers('548Abc87@'); //Returns only letters and numbers ==> 548Abc87;
Format::pointOnlyValue('1.350,45'); //Currency for recording on the BD ==> 1350.45
Format::removeAccent('Açafrão'); //Remove accents and character 'ç' ==> Acafrao
//Removes all special characters ==> "Acafrao com Espaco", 2nd parameter chooses whether to allow space, default true
Format::removeSpecialCharacters('Açafrão com Espaco %$#@!', true);
Format::returnPhoneOrAreaCode('44999998888', false); //Returns only the phone number ==> 999998888
Format::returnPhoneOrAreaCode('44999998888', true); //Returns only the phone's area code ==> 44
Format::reverse('Abacaxi'); //Returns inverted string ==> ixacabA
Format::telephone('44999998888'); //Return phone format brazil ==> (44) 99999-8888
Format::ucwordsCharset('aÇafrÃo maCaRRão'); //Return first capital letter ==> Açafrão Macarrão
Format::upper('Moto'); //lowercase text ==> MOTO - the 2nd parameter chooses the charset, UTF-8 default
Format::zipCode('87030585'); //CEP format brazil ==> 87030-585
Format::writeDateExtensive('06/11/2020'); //Date by Long Brazilian format ==> sexta-feira, 06 de novembro de 2020
Format::writeCurrencyExtensive(1.97); //Coin by Extensive Brazilian format ==> um real e noventa e sete centavos
Format::convertStringToBinary('amor'); //String to binary ==> 1100001 1101101 1101111 1110010
Format::slugfy('Polenta frita e Parmesão'); //Returns a slug from a string ==> polenta-frita-e-parmesao
$data = [
'treatingIntType' => '12',
'handlingFloatType' => '9.63',
'treatingBooleanType' => 'true',
'handlingNumericType' => '11',
];
$rules = [
'treatingIntType' => 'convert|int',
'handlingFloatType' => 'convert|float',
'treatingBooleanType' => 'convert|bool',
'handlingNumericType' => 'convert|numeric',
];
Format::convertTypes($data, $rules); //Convert the value to its correct type ['bool', 'float', 'int', 'numeric',]
/*** Return
[
'treatingIntType' => int 12
'handlingFloatType' => float 9.63
'treatingBooleanType' => boolean true
'handlingNumericType' => float 11
]
***/
$array = [
0 => '1',
1 => '123',
'a' => '222',
'b' => 333,
'c' => '',
];
$newArray = Format::emptyToNull($array); //Convert empty to null, - the 2nd parameter is optional, passing the desired exception
/*** Return
[
0 => 1,
1 => 123,
'a' => 222,
'b' => 333,
'c' => null,
];
**/
//$value = Format::arrayToInt($array); ==> Option for other than by Reference
Format::arrayToIntReference($array); //Formats array values in integer ==>
[
0 => 1,
1 => 123,
'a' => 222,
'b' => 333,
'c' => 0,
];Example: Uploading a single file
<?php
$fileUploadSingle = [
'name' => 'JPG - Upload Validation v.1.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/tmp/phpODnLGo',
'error' => 0,
'size' => 8488,
];
Format::restructFileArray($fileUploadSingle); // Call of the method responsible for normalizing the array
[
0 => [
'name' => 'jpg___upload_validation_v_1.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/tmp/phpBmqX1i',
'error' => 0,
'size' => 8488,
'name_upload' => '22-01-2021_13_1830117018768373446425980271611322393600ad419619ec_jpg___upload_validation_v_1.jpg',
]
]Example: Uploading multiple files
<?php
$fileUploadMultiple = [
'name' => [
'0' => 'JPG - Upload Validation v.1.jpg',
'1' => 'PDF - Upload Validation v.1.pdf',
'2' => 'PNG - Upload Validation v.1.png',
],
'type' => [
'0' => 'image/jpeg',
'1' => 'application/pdf',
'2' => 'image/png',
],
'tmp_name' => [
'0' => '/tmp/phpODnLGo',
'1' => '/tmp/phpfmb0tL',
'2' => '/tmp/phpnoejk8',
],
'error' => [
'0' => 0,
'1' => 0,
'2' => 0,
],
'size' => [
'0' => 8488,
'1' => 818465,
'2' => 1581312,
],
];
Format::restructFileArray($fileUploadMultiple); // Call of the method responsible for normalizing the array
[
0 => [
'name' => 'jpg___upload_validation_v_1.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/tmp/phpBmqX1i',
'error' => 0,
'size' => 8488,
'name_upload' => '22-01-2021_13_1830117018768373446425980271611322393600ad419619ec_jpg___upload_validation_v_1.jpg',
],
1 => [
'name' => 'pdf___upload_validation_v_1.pdf',
'type' => 'application/pdf',
'tmp_name' => '/tmp/phpYo0w7c',
'error' => 0,
'size' => 818465,
'name_upload' => '22-01-2021_13_170624609160164419213582611971611322393600ad41961a5a_pdf___upload_validation_v_1.pdf',
],
2 => [
'name' => 'png___upload_validation_v_1.png',
'type' => 'image/png',
'tmp_name' => '/tmp/phpme7Yf7',
'error' => 0,
'size' => 1581312,
'name_upload' => '22-01-2021_13_8675237129330338531328755051611322393600ad41961ac8_png___upload_validation_v_1.png',
],
]<?php
require 'vendor/autoload.php';
use DevUtils\Compare;
//Returns +30 (+30 days difference)
Compare::daysDifferenceBetweenData('31/05/2020', '30/06/2020'); //Accepts American date too
//Compares if start date is less than end date => Returns [bool]
Compare::startDateLessThanEnd('30/07/2020', '30/06/2020'); //Accepts American date too
//Difference between hours ==> 01:36:28 [Hours displays negative and positive difference]
Compare::differenceBetweenHours('10:41:55', '12:18:23');
//Compares if the start time is less than the end time (3rd parameter, accept custom message)
Compare::startHourLessThanEnd('12:05:01', '10:20:01');
//Compares the date to the current date, and returns the person's age
Compare::calculateAgeInYears('20/05/1989');
//Compares fields for equality, returns boolean
//optional third parameter, false to not compare caseSensitive, default true
Compare::checkDataEquality('AçaFrão', 'Açafrão');
//Compares if desired content exists in String, returns boolean
Compare::contains('AçaFrão', 'çaF');
//Compares the corresponding URL with the second parameter, starts with the string entered in the first parameter. Returns boolean.
Compare::beginUrlWith('/teste', '/teste/variavel');
//Compares the corresponding URL with the second parameter, ends with the string entered in the first parameter. Returns boolean.
Compare::finishUrlWith('/teste', 'sistema/teste');
//Compares if the corresponding string with the first parameter is equal to the substring obtained from the second parameter. Extracting to compare 7 characters from the second parameter starting at position 0. Returns boolean.
Compare::compareStringFrom('sistema', 'sistema/teste', 0, 7);<?php
require 'vendor/autoload.php';
use DevUtils\ValidateCnpj;
ValidateCnpj::validateCnpj('A1.B2C.3D4/5E6F-59'); //Returns boolean, example true [Can pass without mask]
use DevUtils\validateCpf;
ValidateCpf::validateCpf('257.877.760-89'); //Returns boolean, example true [Can pass without mask]
use DevUtils\ValidateDate;
//Examples return true
ValidateDate::validateDateBrazil('29/04/2021'); //Return boolean [Format dd/mm/yyyy]
ValidateDate::validateDateAmerican('2021-04-29'); //Return boolean [Format yyyy-mm-dd]
ValidateDate::validateTimeStamp('2021-04-29 11:17:12'); //Return boolean [Format yyyy-mm-dd hh:mm:ss]
ValidateDate::validateDateIso8601('2025-11-20T10:30:00Z'); //Return boolean [Format ISO 8601: 2025-11-20T10:30:00Z]
ValidateDate::validateDateUTCWithoutTimezone('2025-11-20T10:30:00'); //Return boolean [Format UTC without Z: 2025-11-20T10:30:00]
use DevUtils\ValidateHour;
ValidateHour::validateHour('08:50'); //Return boolean [Format YY:YY]
use DevUtils\ValidatePhone;
ValidatePhone::validate('44999999999'); //Return boolean [[You can wear a mask]
use DevUtils\ValidateString;
ValidateString::minWords('Bruno Conte', 2) //Return boolean
ValidateString::maxWords('Bruno Conte', 2) //Return boolean<?php
require 'vendor/autoload.php';
use DevUtils\Uuid;
// Generate UUID v7 (timestamp-based, sortable, unique)
$uuid = Uuid::generate(); // ==> 01890f87-4f0b-7f6b-8b1d-9f4f9d7c3b5a
// Validate any UUID version (v1 to v8)
Uuid::isValid('550e8400-e29b-41d4-a716-446655440000'); // ==> true
// Validate specific version
Uuid::isValid('01890f87-4f0b-7f6b-8b1d-9f4f9d7c3b5a', 7); // ==> true<?php
use DevUtils\Utility;
/*
Generate secure passwords
int $size ==> Number of characters (Required)
bool $uppercase ==> Include uppercase letters (default: true)
bool $lowercase ==> Include lowercase letters (default: true)
bool $numbers ==> Include numbers (default: true)
bool $symbols ==> Include symbols (default: true)
*/
Utility::generatePassword(10); // ==> aB3$xY9!zK
Utility::generatePassword(16, true, true, true, false); // Without symbols<?php
require 'vendor/autoload.php';
use DevUtils\Arrays;
$array = ['primeiro' => 15, 'segundo' => 25];
var_dump(Arrays::searchKey($array, 'primeiro')); // Search for key in array, and Return position ==> returns 0
var_dump(Arrays::searchKey($array, 'segundo')); // Search for key in array, and Return position ==> returns 1
var_dump(Arrays::searchKey($array, 'nao-existe')); // Search for key in array, and Return position ==> returns null
$array = ['primeiro' => 10, 'segundo' => 20];
Arrays::renameKey($array, 'primeiro', 'novoNome');
var_dump($array); //Rename array key ==> ['novoNome' => 10, 'segundo' => 20];
$array = [
'frutas' => ['fruta_1' => 'Maçã', 'fruta_2' => 'Pêra', 'fruta_3' => 'fruta', 'fruta_4' => 'Uva'],
'verduras' => ['verdura_1' => 'Rúcula', 'verdura_2' => 'Acelga', 'verdura_3' => 'Alface'],
'legume' => 'Tomate'
];
// Checks in the array, if there is any index with the desired value
var_dump(Arrays::checkExistIndexByValue($array, 'Tomate'));
// Performs the search in the array, through the key and Return an array with all indexes located
var_dump(Arrays::findValueByKey($array, 'verduras'));
// Performs the search in the array, through a value and returns an array with all items located
var_dump(Arrays::findIndexByValue($array, 'Tomate'));
$xml = new SimpleXMLElement('<root/>');
Arrays::convertArrayToXml($array, $xml); // Convert array to Xml
var_dump($xml->asXML());
$array = [
'frutas' => ['fruta_1' => 'Maçã', 'fruta_2' => 'Pêra', 'fruta_3' => 'fruta', 'fruta_4' => 'Uva'],
'verduras' => '{"verdura_1": "Rúcula", "verdura_2": "Acelga", "verdura_3": "Alface"}'
];
// Checks the array, if it has any index with JSON and turns it into an array
Arrays::convertJsonIndexToArray($array);
var_dump($array);
$array = [
'pessoa' => [
'pedidos' => ['pedido1', 'pedido2'],
'categorias' => [
'subcategorias' => [
'subcategoria1' => 'valor teste'
]
]
]
];
// Checks if a specific index exists in a multilevel array
var_dump(Arrays::checkExistIndexArrayRecursive($array, 'subcategoria1')); // Return true<?php
require 'vendor/autoload.php';
use DevUtils\Utility;
Utility::captureClientIp(); // Return user IP, capture per layer available, eg 201.200.25.40
/*
* @return string -> Full URL string
* @param string $host -> system domain
* @param string $absolutePath -> absolute path
* @param string $https -> 'on' to generate https url, null or other value, generate http url
*/
Utility::buildUrl('localhost', '/sua-url/complemento', 'on'); // Return to URLfile: .gitlab-ci.yml
Add Lines:
script:
- composer install
- ./vendor/bin/phpunit --coverage-xml coverage #Here generates the coverage file
- php ./src/CI.php coverage/index.xml 80 #Change the value 80 to your value
file: .gitignore
Add Line: /coverage/./vendor/bin/phpunit --coverage-xml coverage
./vendor/bin/phpstan analyse -c phpstan.neon --level 10
If you don't know how to run phpstan, I execute and adjust whatever is necessary
- 📖 Check the complete documentation
- 🐛 Found a bug? Open an issue
- 💡 Have a suggestion? Submit a feature request
Contributions are welcome! Please:
- Fork the project
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Make sure:
- All tests pass:
phpunit - Code follows standards:
phpstan analyse -c phpstan.neon --level 10 - PSR-12 compliance:
phpcs
- ✅ PHPUnit - Full test coverage
- ✅ PHPStan Level 10 - Advanced static analysis
- ✅ SonarQube - Code quality and security analysis
- ✅ PHPCS - PHP Code Sniffer for coding standards
- ✅ Zero dependencies - Pure PHP
GitHub https://github.com/brunoconte3/dev-utils
Packagist https://packagist.org/packages/brunoconte3/dev-utils
Issues https://github.com/brunoconte3/dev-utils/issues
Wiki https://github.com/brunoconte3/dev-utils/wiki
See CHANGELOG.md for complete version history and changes.
If this project was useful to you:
- ⭐ Leave a star on GitHub
- 🍴 Fork and share
- 💬 Give feedback and suggestions
The validator is an open-source application licensed under the MIT License.