Skip to content

Commit 4feb662

Browse files
committed
feat: Add Support for Alphanumeric CNPJ
Due to the continuous increase in the number of companies and the imminent exhaustion of available CNPJs (Brazilian taxpayer identification numbers), the Brazilian Federal Revenue Service is instituting the alphanumeric CNPJ. The initiative aims to facilitate the identification of all companies and improve the business environment, contributing to the economic and social development of Brazil. The alphanumeric CNPJ will be assigned, starting in July 2026, exclusively to new registrations. Changes: - Add support for alphanumeric CNPJ validation - Format code according to PHPCS standards - Simplify CNPJ conversion to uppercase character array - Add documentation about CNPJ structure
1 parent d8e31db commit 4feb662

4 files changed

Lines changed: 30 additions & 9 deletions

File tree

docs/validators.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ In this page you will find a list of validators by their category.
241241
[Charset]: validators/Charset.md "Validates if a string is in a specific charset."
242242
[Circuit]: validators/Circuit.md "Validates the input against a series of validators until the first fails."
243243
[Cnh]: validators/Cnh.md "Validates a Brazilian driver's license."
244-
[Cnpj]: validators/Cnpj.md "Validates if the input is a Brazilian National Registry of Legal Entities (CNPJ) number."
244+
[Cnpj]: validators/Cnpj.md "Validates the structure and mathematical integrity of Brazilian CNPJ identifiers."
245245
[Consonant]: validators/Consonant.md "Validates if the input contains only consonants."
246246
[Contains]: validators/Contains.md "Validates if the input contains some value."
247247
[ContainsAny]: validators/ContainsAny.md "Validates if the input contains at least one of defined values"

docs/validators/Cnpj.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ SPDX-License-Identifier: MIT
77

88
- `Cnpj()`
99

10-
Validates if the input is a Brazilian National Registry of Legal Entities (CNPJ) number.
10+
Validates the structure and mathematical integrity of Brazilian [CNPJ](https://pt.wikipedia.org/wiki/Cadastro_Nacional_da_Pessoa_Jur%C3%ADdica) identifiers.
1111
Ignores non-digit chars, so use `->digit()` if needed.
1212

1313
```php
1414
v::cnpj()->assert('00394460005887');
1515
// Validation passes successfully
16+
17+
v::cnpj()->assert('12ABC34501DE35');
18+
// Validation passes successfully
1619
```
1720

1821
## Templates

src/Validators/Cnpj.php

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
use function array_sum;
2525
use function count;
2626
use function is_scalar;
27+
use function ord;
2728
use function preg_replace;
2829
use function str_split;
30+
use function strtoupper;
2931

3032
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]
3133
#[Template(
@@ -34,6 +36,8 @@
3436
)]
3537
final class Cnpj extends Simple
3638
{
39+
private const int BASE_ASCII = 48;
40+
3741
public function isValid(mixed $input): bool
3842
{
3943
if (!is_scalar($input)) {
@@ -42,7 +46,8 @@ public function isValid(mixed $input): bool
4246

4347
// Code ported from jsfromhell.com
4448
$bases = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
45-
$digits = $this->getDigits((string) $input);
49+
$chars = $this->getChars((string) $input);
50+
$digits = $this->transformToAscii($chars);
4651

4752
if (array_sum($digits) < 1) {
4853
return false;
@@ -71,14 +76,22 @@ public function isValid(mixed $input): bool
7176
return $digits[13] == $check;
7277
}
7378

74-
/** @return int[] */
75-
private function getDigits(string $input): array
79+
/** @return string[] */
80+
private function getChars(string $input): array
81+
{
82+
return str_split((string) preg_replace('/[\W_]/', '', strtoupper($input)));
83+
}
84+
85+
/**
86+
* @param array<string> $input
87+
*
88+
* @return int[]
89+
*/
90+
private function transformToAscii(array $input): array
7691
{
7792
return array_map(
78-
'intval',
79-
str_split(
80-
(string) preg_replace('/\D/', '', $input),
81-
),
93+
static fn(string $character) => ord($character) - self::BASE_ASCII,
94+
$input,
8295
);
8396
}
8497
}

tests/unit/Validators/CnpjTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,14 @@ public static function providerForValidInput(): iterable
3939
[$validator, '24.760.428/0001-09'],
4040
[$validator, '27.355.204/0001-00'],
4141
[$validator, '36.310.327/0001-07'],
42+
[$validator, '12.ABC.345/01DE-35'],
43+
[$validator, '12.ABC.345/01DE_35'],
4244
[$validator, '38175021000110'],
4345
[$validator, '37550610000179'],
4446
[$validator, '12774546000189'],
4547
[$validator, '77456211000168'],
4648
[$validator, '02023077000102'],
49+
[$validator, '12ABC34501DE35'],
4750
];
4851
}
4952

@@ -75,6 +78,8 @@ public static function providerForInvalidInput(): iterable
7578
[$validator, '992999999999929384'],
7679
[$validator, '99-010-0.'],
7780
[$validator, null],
81+
[$validator, '12ABC34501DE00'],
82+
[$validator, '12ABC34501DEFG'],
7883
];
7984
}
8085
}

0 commit comments

Comments
 (0)