Skip to content

Commit 570ba48

Browse files
valdeirpsrhenriquemoody
authored andcommitted
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 16148e9 commit 570ba48

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
@@ -238,7 +238,7 @@ In this page you will find a list of validators by their category.
238238
[Charset]: validators/Charset.md "Validates if a string is in a specific charset."
239239
[Circuit]: validators/Circuit.md "Validates the input against a series of validators until the first fails."
240240
[Cnh]: validators/Cnh.md "Validates a Brazilian driver's license."
241-
[Cnpj]: validators/Cnpj.md "Validates if the input is a Brazilian National Registry of Legal Entities (CNPJ) number."
241+
[Cnpj]: validators/Cnpj.md "Validates the structure and mathematical integrity of Brazilian CNPJ identifiers."
242242
[Consonant]: validators/Consonant.md "Validates if the input contains only consonants."
243243
[Contains]: validators/Contains.md "Validates if the input contains some value."
244244
[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
@@ -11,12 +11,15 @@ SPDX-FileContributor: William Espindola <oi@williamespindola.com.br>
1111

1212
- `Cnpj()`
1313

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

1717
```php
1818
v::cnpj()->assert('00394460005887');
1919
// Validation passes successfully
20+
21+
v::cnpj()->assert('12ABC34501DE35');
22+
// Validation passes successfully
2023
```
2124

2225
## 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
@@ -34,11 +34,14 @@ public static function providerForValidInput(): iterable
3434
[$validator, '24.760.428/0001-09'],
3535
[$validator, '27.355.204/0001-00'],
3636
[$validator, '36.310.327/0001-07'],
37+
[$validator, '12.ABC.345/01DE-35'],
38+
[$validator, '12.ABC.345/01DE_35'],
3739
[$validator, '38175021000110'],
3840
[$validator, '37550610000179'],
3941
[$validator, '12774546000189'],
4042
[$validator, '77456211000168'],
4143
[$validator, '02023077000102'],
44+
[$validator, '12ABC34501DE35'],
4245
];
4346
}
4447

@@ -70,6 +73,8 @@ public static function providerForInvalidInput(): iterable
7073
[$validator, '992999999999929384'],
7174
[$validator, '99-010-0.'],
7275
[$validator, null],
76+
[$validator, '12ABC34501DE00'],
77+
[$validator, '12ABC34501DEFG'],
7378
];
7479
}
7580
}

0 commit comments

Comments
 (0)