An enhanced library to validate TIN numbers for individuals with advanced features including input masks, TIN type identification, and comprehensive Docker support. This is a fork of the original loophp/tin library with significant enhancements.
New Features in v2.0.0:
- 🎯 Input Mask Support - Get format masks for TIN input fields
- 📝 Placeholder Generation - Generate example values for input fields
- 🔧 Input Formatting - Format user input according to TIN mask
- 🏷️ TIN Type Identification - Identify specific TIN types (DNI, NIE, CIF, etc.)
- 📊 TIN Types API - Get available TIN types for each country
- 🐳 Docker Support - Complete development environment with PHP 8.3
- 📚 Enhanced Documentation - Comprehensive examples and usage guides
Supported countries:
- Austria (AT)
- Belgium (BE)
- Bulgaria (BG)
- Croatia (HR)
- Cyprus (CY)
- Czech Republic (CZ)
- Denmark (DK)
- Estonia (EE)
- Finland (FI)
- France (FR)
- Germany (DE)
- Greece (GR) - only size
- Hungary (HU)
- Ireland (IE)
- Italy (IT)
- Latvia (LV) - no check digit
- Lithuania (LT)
- Luxembourg (LU)
- Malta (MT) - no check digit
- Netherlands (NL)
- Poland (PL)
- Portugal (PT)
- Romania (RO) - no check digit
- Slovakia (SK)
- Slovenia (SI)
- Spain (ES)
- Sweden (SE)
- United Kingdom (UK) - only structure
If your country is not there, feel free to open an issue with your country code, and a link to the specification. Ideally, you can provide a pull request with the algorithm and the tests.
- PHP >= 8.1
composer require vldmir/tinTo simply check the validity of a TIN number:
<?php
require __DIR__ . '/vendor/autoload.php';
use loophp\Tin\TIN;
$bool = TIN::fromSlug('be71102512345')->isValid();If you want to get the reason why a number is invalid, you can use:
<?php
require __DIR__ . '/vendor/autoload.php';
use loophp\Tin\TIN;
use loophp\Tin\Exception\TINException;
try {
TIN::fromSlug('be71102512345')->check();
} catch (TINException $e) {
echo "Validation Error: " . $e->getMessage();
}The library provides comprehensive input mask and formatting capabilities:
<?php
use loophp\Tin\TIN;
// Get the input mask for a country
$tin = TIN::fromSlug('be71102512345');
$mask = $tin->getInputMask(); // Returns: "99.99.99-999.99"
// Get a placeholder example
$placeholder = $tin->getPlaceholder(); // Returns: "85.07.30-033.61"
// Format raw input according to the country's mask
$formatted = $tin->formatInput('71102512345'); // Returns: "71.10.25-123.45"
// Get mask information without creating a TIN instance
$maskInfo = TIN::getMaskForCountry('BE');
// Returns: [
// 'mask' => '99.99.99-999.99',
// 'placeholder' => '85.07.30-033.61',
// 'country' => 'BE'
// ]Different countries may have multiple types of TINs. The library can identify and categorize them:
<?php
use loophp\Tin\TIN;
// Get all TIN types for a country
$types = TIN::getTinTypesForCountry('ES');
// Returns:
// [
// 1 => ['code' => 'DNI', 'name' => 'Documento Nacional de Identidad', 'description' => 'Spanish Natural Persons ID'],
// 2 => ['code' => 'NIE', 'name' => 'Número de Identidad de Extranjero', 'description' => 'Foreigners Identification Number'],
// 3 => ['code' => 'CIF', 'name' => 'Código de Identificación Fiscal', 'description' => 'Tax Identification Code for Legal Entities']
// ]
// Identify the type of a specific TIN
$tin = TIN::fromSlug('es12345678Z');
$type = $tin->identifyTinType();
// Returns: ['code' => 'DNI', 'name' => 'Documento Nacional de Identidad', 'description' => 'Spanish Natural Persons ID']
// Get TIN types for the current TIN's country
$allTypes = $tin->getTinTypes();<?php
require __DIR__ . '/vendor/autoload.php';
use loophp\Tin\TIN;
use loophp\Tin\Exception\TINException;
// Test different countries
$testCases = [
['country' => 'BE', 'tin' => '71102512345', 'description' => 'Belgian TIN'],
['country' => 'ES', 'tin' => '12345678Z', 'description' => 'Spanish DNI'],
['country' => 'DE', 'tin' => '12345678901', 'description' => 'German TIN'],
['country' => 'UK', 'tin' => 'AB123456C', 'description' => 'UK TIN'],
];
foreach ($testCases as $test) {
echo "Testing {$test['description']} ({$test['country']}): {$test['tin']}\n";
try {
$tin = TIN::fromSlug($test['country'] . $test['tin']);
// Basic validation
$isValid = $tin->isValid();
echo "Valid: " . ($isValid ? 'YES' : 'NO') . "\n";
// Get input mask and placeholder
$mask = $tin->getInputMask();
$placeholder = $tin->getPlaceholder();
echo "Input Mask: $mask\n";
echo "Placeholder: $placeholder\n";
// Format input
$formatted = $tin->formatInput($test['tin']);
echo "Formatted: $formatted\n";
// Identify TIN type
$tinType = $tin->identifyTinType();
if ($tinType) {
echo "TIN Type: {$tinType['code']} - {$tinType['name']}\n";
echo "Description: {$tinType['description']}\n";
}
echo "Validation: PASSED\n";
} catch (TINException $e) {
echo "Validation Error: " . $e->getMessage() . "\n";
}
echo "\n";
}| Country | Mask | Placeholder | TIN Types |
|---|---|---|---|
| Belgium (BE) | 99.99.99-999.99 |
85.07.30-033.61 |
TIN |
| Spain (ES) | 99999999A |
12345678Z |
DNI, NIE, CIF |
| Germany (DE) | 999 999 999 99 |
123 456 789 01 |
IdNr, StNr |
| United Kingdom (UK) | AA999999A |
AB123456C |
UTR, NINO |
| France (FR) | 9 99 99 99 999 999 |
1 23 45 67 890 123 |
TIN |
| Italy (IT) | AAAAAANNANNANAAA |
RSSMRA85T10A562S |
TIN |
Mask Format:
9- Digit (0-9)A- Uppercase lettera- Lowercase letter- Other characters (
.,-, space) - Separators
The library includes a complete Docker setup for easy development and testing:
# Start containers and install dependencies
make up
# Run tests
make phpspec
# Run the test script
make tin-test
# Open shell in container
make shellmake up # Start containers and install dependencies
make down # Stop containers
make shell # Open bash shell in PHP container
make composer # Run composer commands
make test # Run all tests (PHPSpec + GrumPHP)
make phpspec # Run PHPSpec tests
make grumphp # Run GrumPHP checks
make phpstan # Run PHPStan analysis
make psalm # Run Psalm analysis
make infection # Run mutation testing
make tin-test # Run the TIN test script# Start containers
docker-compose up -d
# Install dependencies
docker-compose run --rm tin-composer composer install
# Run tests
docker exec tin-php vendor/bin/phpspec run -vvv --stop-on-failure
# Run the TIN test script
docker exec tin-php php test-tin.php
# Open shell
docker exec -it tin-php bashFor detailed Docker documentation, see DOCKER.md.
If you want to use a stricter method (without normalizing the TIN number, that
is, using the raw TIN number), use the strict parameter in the check or
isValid functions as shown below. By default, it is set to false.
TIN::fromSlug('be7110.2512345')->check(); // Not strict
TIN::fromSlug('be7110.2512345')->check(strict: false); // Not strict
TIN::fromSlug('be7110.2512345')->check(true); // Strict
TIN::fromSlug('be7110.2512345')->check(strict: true); // StrictEvery time changes are introduced into the library, Github run the tests and the benchmarks.
The library has tests written with PHPSpec. Feel free
to check them out in the spec directory. Run composer phpspec to trigger the
tests.
Before each commit some inspections are executed with
GrumPHP, run ./vendor/bin/grumphp run to
check manually.
PHPInfection is used to ensure that
your code is properly tested, run composer infection to test your code.
# Using Composer
composer phpspec
# Using Docker
make phpspec
# With code coverage
docker exec tin-php vendor/bin/phpspec run -vvv --stop-on-failureEuropean Commission TIN serviceTIN Algorithms - Public - Functional SpecificationTaxpayer Identification Number
- Volodymyr Romantsov - Enhanced version with input masks and Docker support
- Thomas Portelange - Original library
- Pol Dellaiera - Original library
We warmly welcome your contributions by submitting pull requests. Our team is highly responsive and will gladly guide you through the entire process, from the initial submission to the final resolution.
- Fork the repository
- Clone your fork
- Set up the Docker environment:
make up - Make your changes
- Run tests:
make phpspec - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.