From ec26ee553a8529ba245b327e672de0e34ff475bf Mon Sep 17 00:00:00 2001 From: Marcelo Rocha Date: Tue, 30 Jun 2026 18:02:31 -0300 Subject: [PATCH 1/6] Starting in July 2026, the CNPJ may contain alphanumeric characters. --- tests/TestCase/Validation/BrValidationTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/TestCase/Validation/BrValidationTest.php b/tests/TestCase/Validation/BrValidationTest.php index 2eec0dd..193d52f 100644 --- a/tests/TestCase/Validation/BrValidationTest.php +++ b/tests/TestCase/Validation/BrValidationTest.php @@ -125,6 +125,9 @@ public function testSsn() $this->assertTrue(BrValidation::personId('04.295.166/0001-33')); $this->assertTrue(BrValidation::personId('33.530.486/0001-29')); + //Testing alphanumeric CNPJ + $this->assertTrue(BrValidation::cnpj('XOXDNB0K000156')); + // Testing ssn $this->assertFalse(BrValidation::personId('04295165000133')); $this->assertFalse(BrValidation::personId('33530485000129')); From 1a98a37d34fcf2220761c343e106d119a737fa18 Mon Sep 17 00:00:00 2001 From: Marcelo Rocha Date: Tue, 30 Jun 2026 18:32:13 -0300 Subject: [PATCH 2/6] Starting in July 2026, the CNPJ may contain alphanumeric characters. --- src/Validation/BrValidation.php | 16 ++++++++-------- tests/TestCase/Validation/BrValidationTest.php | 7 +++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Validation/BrValidation.php b/src/Validation/BrValidation.php index de83870..87ad4e9 100644 --- a/src/Validation/BrValidation.php +++ b/src/Validation/BrValidation.php @@ -118,22 +118,22 @@ public static function cnpj(string $check): bool // sometimes the user submits a masked CNPJ if (preg_match('/^\d\d.\d\d\d.\d\d\d\/\d\d\d\d\-\d\d/', $check)) { $check = str_replace(['-', '.', '/'], '', $check); - } elseif (!ctype_digit($check)) { + } elseif (!ctype_alnum($check)) { return false; } - + $charVal = fn(int $key) => ord($check[$key]) - 48; if (strlen($check) !== 14) { return false; } - $firstSum = ((int)$check[0] * 5) + ((int)$check[1] * 4) + ((int)$check[2] * 3) + ((int)$check[3] * 2) + - ((int)$check[4] * 9) + ((int)$check[5] * 8) + ((int)$check[6] * 7) + ((int)$check[7] * 6) + - ((int)$check[8] * 5) + ((int)$check[9] * 4) + ((int)$check[10] * 3) + ((int)$check[11] * 2); + $firstSum = ($charVal(0) * 5) + ($charVal(1) * 4) + ($charVal(2) * 3) + ($charVal(3) * 2) + + ($charVal(4) * 9) + ($charVal(5) * 8) + ($charVal(6) * 7) + ($charVal(7) * 6) + + ($charVal(8) * 5) + ($charVal(9) * 4) + ($charVal(10) * 3) + ($charVal(11) * 2); $firstVerificationDigit = $firstSum % 11 < 2 ? 0 : 11 - ($firstSum % 11); - $secondSum = ((int)$check[0] * 6) + ((int)$check[1] * 5) + ((int)$check[2] * 4) + ((int)$check[3] * 3) + - ((int)$check[4] * 2) + ((int)$check[5] * 9) + ((int)$check[6] * 8) + ((int)$check[7] * 7) + - ((int)$check[8] * 6) + ((int)$check[9] * 5) + ((int)$check[10] * 4) + ((int)$check[11] * 3) + + $secondSum = ($charVal(0) * 6) + ($charVal(1) * 5) + ($charVal(2) * 4) + ($charVal(3) * 3) + + ($charVal(4) * 2) + ($charVal(5) * 9) + ($charVal(6) * 8) + ($charVal(7) * 7) + + ($charVal(8) * 6) + ($charVal(9) * 5) + ($charVal(10) * 4) + ($charVal(11) * 3) + ((int)$check[12] * 2); $secondVerificationDigit = $secondSum % 11 < 2 ? 0 : 11 - ($secondSum % 11); diff --git a/tests/TestCase/Validation/BrValidationTest.php b/tests/TestCase/Validation/BrValidationTest.php index 193d52f..5c120d7 100644 --- a/tests/TestCase/Validation/BrValidationTest.php +++ b/tests/TestCase/Validation/BrValidationTest.php @@ -126,7 +126,14 @@ public function testSsn() $this->assertTrue(BrValidation::personId('33.530.486/0001-29')); //Testing alphanumeric CNPJ + $this->assertFalse(BrValidation::cnpj('ABC123Z4000110')); + $this->assertFalse(BrValidation::cnpj('9AB5B5FF0001AB'));//Last two chars must be numeric + $this->assertTrue(BrValidation::cnpj('XOXDNB0K000156')); + $this->assertTrue(BrValidation::cnpj('F9Z3AJUJ000108')); + $this->assertTrue(BrValidation::cnpj('f9z3AjUj000108'));//lowercase must work + $this->assertTrue(BrValidation::cnpj('NGZ9C1T4000145')); + $this->assertTrue(BrValidation::cnpj('12.ABC.345/01DE-35')); // Testing ssn $this->assertFalse(BrValidation::personId('04295165000133')); From d0ad58df9a6713a8e01d07b83ac4428dec140698 Mon Sep 17 00:00:00 2001 From: Marcelo Rocha Date: Tue, 30 Jun 2026 18:33:01 -0300 Subject: [PATCH 3/6] Starting in July 2026, the CNPJ may contain alphanumeric characters. --- src/Validation/BrValidation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Validation/BrValidation.php b/src/Validation/BrValidation.php index 87ad4e9..4b4588c 100644 --- a/src/Validation/BrValidation.php +++ b/src/Validation/BrValidation.php @@ -114,7 +114,7 @@ public static function cpf(string $check): bool */ public static function cnpj(string $check): bool { - $check = trim($check); + $check = strtoupper(trim($check)); // sometimes the user submits a masked CNPJ if (preg_match('/^\d\d.\d\d\d.\d\d\d\/\d\d\d\d\-\d\d/', $check)) { $check = str_replace(['-', '.', '/'], '', $check); From 5af02b063939d709e3b09f3b4363b2c384793356 Mon Sep 17 00:00:00 2001 From: Marcelo Rocha Date: Tue, 30 Jun 2026 18:37:58 -0300 Subject: [PATCH 4/6] Starting in July 2026, the CNPJ may contain alphanumeric characters. --- src/Validation/BrValidation.php | 2 +- tests/TestCase/Validation/BrValidationTest.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Validation/BrValidation.php b/src/Validation/BrValidation.php index 4b4588c..59ee530 100644 --- a/src/Validation/BrValidation.php +++ b/src/Validation/BrValidation.php @@ -116,7 +116,7 @@ public static function cnpj(string $check): bool { $check = strtoupper(trim($check)); // sometimes the user submits a masked CNPJ - if (preg_match('/^\d\d.\d\d\d.\d\d\d\/\d\d\d\d\-\d\d/', $check)) { + if (preg_match('/^([A-Z0-9]{2}).([A-Z0-9]{3}).([A-Z0-9]{3})\/([A-Z0-9]{4})\-\d\d/', $check)) { $check = str_replace(['-', '.', '/'], '', $check); } elseif (!ctype_alnum($check)) { return false; diff --git a/tests/TestCase/Validation/BrValidationTest.php b/tests/TestCase/Validation/BrValidationTest.php index 5c120d7..e2ab8aa 100644 --- a/tests/TestCase/Validation/BrValidationTest.php +++ b/tests/TestCase/Validation/BrValidationTest.php @@ -128,6 +128,8 @@ public function testSsn() //Testing alphanumeric CNPJ $this->assertFalse(BrValidation::cnpj('ABC123Z4000110')); $this->assertFalse(BrValidation::cnpj('9AB5B5FF0001AB'));//Last two chars must be numeric + $this->assertFalse(BrValidation::cnpj('12.@BC.345/01#E-35'));//bad chars @# + $this->assertFalse(BrValidation::cnpj('XOX&@!B0K000156'));//Bad chars &@! $this->assertTrue(BrValidation::cnpj('XOXDNB0K000156')); $this->assertTrue(BrValidation::cnpj('F9Z3AJUJ000108')); From add8397a75a025fa0656054301d3bd4d34fb58b1 Mon Sep 17 00:00:00 2001 From: Marcelo Rocha Date: Tue, 30 Jun 2026 18:49:26 -0300 Subject: [PATCH 5/6] Starting in July 2026, the CNPJ may contain alphanumeric characters. --- tests/TestCase/Validation/BrValidationTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/TestCase/Validation/BrValidationTest.php b/tests/TestCase/Validation/BrValidationTest.php index e2ab8aa..9d06d5f 100644 --- a/tests/TestCase/Validation/BrValidationTest.php +++ b/tests/TestCase/Validation/BrValidationTest.php @@ -127,6 +127,7 @@ public function testSsn() //Testing alphanumeric CNPJ $this->assertFalse(BrValidation::cnpj('ABC123Z4000110')); + $this->assertFalse(BrValidation::cnpj('9AB5B5FF0001AB')); $this->assertFalse(BrValidation::cnpj('9AB5B5FF0001AB'));//Last two chars must be numeric $this->assertFalse(BrValidation::cnpj('12.@BC.345/01#E-35'));//bad chars @# $this->assertFalse(BrValidation::cnpj('XOX&@!B0K000156'));//Bad chars &@! @@ -146,10 +147,13 @@ public function testSsn() $this->assertFalse(BrValidation::personId('33.530.485/0001-29')); $this->assertFalse(BrValidation::personId('04.295.166/0001-01')); $this->assertFalse(BrValidation::personId('33.530.486/0001-30')); + $this->assertFalse(BrValidation::personId('ABC123Z4000110')); $this->assertTrue(BrValidation::personId('04295166000133')); $this->assertTrue(BrValidation::personId('33530486000129')); $this->assertTrue(BrValidation::personId('04.295.166/0001-33')); $this->assertTrue(BrValidation::personId('33.530.486/0001-29')); + $this->assertTrue(BrValidation::personId('NGZ9C1T4000145')); + $this->assertTrue(BrValidation::personId('12.ABC.345/01DE-35')); // Testing invalid input $this->assertFalse(BrValidation::personId('3712093712890371289073901287390812')); From 5298672feb893a58fdcaf29ae98bb12c5a4953d3 Mon Sep 17 00:00:00 2001 From: Marcelo Rocha Date: Tue, 30 Jun 2026 19:57:27 -0300 Subject: [PATCH 6/6] Using mb_* functions --- src/Validation/BrValidation.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Validation/BrValidation.php b/src/Validation/BrValidation.php index 59ee530..0564139 100644 --- a/src/Validation/BrValidation.php +++ b/src/Validation/BrValidation.php @@ -114,7 +114,7 @@ public static function cpf(string $check): bool */ public static function cnpj(string $check): bool { - $check = strtoupper(trim($check)); + $check = mb_strtoupper(trim($check)); // sometimes the user submits a masked CNPJ if (preg_match('/^([A-Z0-9]{2}).([A-Z0-9]{3}).([A-Z0-9]{3})\/([A-Z0-9]{4})\-\d\d/', $check)) { $check = str_replace(['-', '.', '/'], '', $check); @@ -122,7 +122,7 @@ public static function cnpj(string $check): bool return false; } $charVal = fn(int $key) => ord($check[$key]) - 48; - if (strlen($check) !== 14) { + if (mb_strlen($check) !== 14) { return false; } $firstSum = ($charVal(0) * 5) + ($charVal(1) * 4) + ($charVal(2) * 3) + ($charVal(3) * 2) +