brunoconte3/dev-utils

A complete PHP utility library for validating, formatting, comparing data, and more.

Maintainers

Package info

github.com/brunoconte3/dev-utils

pkg:composer/brunoconte3/dev-utils

Statistics

Installs: 26 327

Dependents: 0

Suggesters: 0

Stars: 35

Open Issues: 0

2.15.2 2026-05-24 20:00 UTC

README

dev-utils Pure PHP Data Validation & Formatting Library

Latest Version PHP Version License

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.

✨ Key Features

  • 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 Navigation

Quick Start

<?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());
}

Installation

Install using Composer:

composer require brunoconte3/dev-utils

Or add to your composer.json:

{
    "require": {
        "brunoconte3/dev-utils": "2.15.1"
    }
}

Requirements:

  • PHP >= 8.3
  • Composer

Why use dev-utils?

  • 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

🎯 Common Use Cases

Validate registration forms

Validate email, CPF/CNPJ, phone and other data in a single validator.

Process file uploads

Control file size, MIME type, image dimensions and filename.

Format data for display

Format currencies, dates, strings and perform type conversions.

Validate API data

Ensure received data meets your business criteria.

Manipulate complex arrays

Search, sort, filter and transform arrays with ready-to-use methods.

Data Validation Example

Sample Data

$data = [
   'name'  => 'Bruno Conte',
   'email' => 'bruno@example.com',
   'newPassword' => '123456',
];

Validation Rules

$rules = [
   'name'  => 'required|alpha|min:7|max:100',
   'email' => 'required|email|max:80',
   'newPassword' => 'required|email|max:50',
];

Validate the Data

<?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());
}

Validating File(s) Upload

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.

HTML Form

<!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 Validation

<?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());
    }
}
?>

Validation types (validators)

Complete list of available validators in the library. Use them in your validation rules to ensure data meets your business criteria.

Text Validators

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

Brazilian Data Validators

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

Date and Time Validators

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

Type Validators

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)

Constraint Validators

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

Network and Identifier Validators

Validator Description
email Email validation
ip Valid IP address
mac Valid MAC address
rgbColor Valid RGB color

Numeric Comparison Validators

Validator Description
numMax Maximum value (minimum = 0)
numMin Minimum value (minimum = 0)

File Upload Validators

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

Defining custom message

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.',
    ]);

Formatting Examples

<?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,
];

Formatting Upload File(s)

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',
	],
]

Comparisons Examples

<?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);

Validations in the form of Methods

<?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

Generation Utilities

UUID v7 - Generate and Validate

<?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

Password Generation

<?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

Manipulate Arrays

<?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

Utilities

<?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 URL

Check the minimum coverage of CI/CD unit tests using PHPUnit

file: .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/

Will perform pull request, please execute unit tests, and phpstan level 10

./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

💬 Support and Documentation

Need Help?

Contributing

Contributions are welcome! Please:

  1. Fork the project
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Make sure:

  • All tests pass: phpunit
  • Code follows standards: phpstan analyse -c phpstan.neon --level 10
  • PSR-12 compliance: phpcs

📊 Code Quality

  • 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

🔗 Useful Links

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

📝 Changelog

See CHANGELOG.md for complete version history and changes.

🌟 If you like this project

If this project was useful to you:

  • ⭐ Leave a star on GitHub
  • 🍴 Fork and share
  • 💬 Give feedback and suggestions

License

The validator is an open-source application licensed under the MIT License.