Validar CNPJ alfanumérico no Laravel com Rule customizada
Crie uma Rule customizada no Laravel 10/11 que valida o novo CNPJ alfanumérico com o algoritmo oficial (ASCII−48, pesos e módulo 11) e use-a no FormRequest.
Validar CNPJ alfanumérico no Laravel ficou simples: você cria uma Rule customizada que aplica o algoritmo oficial (ASCII−48, pesos e módulo 11) e a usa como ['cnpj' => ['required', new CnpjAlfanumerico]] no seu FormRequest ou validator. Este tutorial mostra a classe completa, o uso e a mensagem de erro em português, prontos para Laravel 10 e 11.
O que muda no CNPJ alfanumérico
A partir de julho de 2026 (Instrução Normativa RFB nº 2.229/2024), o CNPJ passa a aceitar letras maiúsculas A–Z nas 12 primeiras posições (raiz + ordem), mantendo as 14 posições e a máscara XX.XXX.XXX/XXXX-DD. Os dois dígitos verificadores continuam numéricos, e os CNPJs numéricos atuais seguem válidos — seu sistema precisa aceitar os dois formatos. Veja o panorama completo no nosso guia de implementação do CNPJ alfanumérico.
Validando CNPJ alfanumérico em Laravel
Desde o Laravel 10 a forma recomendada de criar regras é implementar a interface Illuminate\Contracts\Validation\ValidationRule, que tem um único método validate() e recebe um Closure $fail para reportar o erro. Gere o esqueleto com php artisan make:rule CnpjAlfanumerico e cole a lógica golden abaixo. Toda a aritmética (normalização, pesos e módulo 11) fica encapsulada na própria Rule.
<?php
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
class CnpjAlfanumerico implements ValidationRule
{
private const PESO1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
private const PESO2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
public function validate(string $attribute, mixed $value, Closure $fail): void
{
if (! is_string($value) || ! $this->valido($value)) {
$fail('O :attribute informado não é um CNPJ válido.');
}
}
private function valido(string $cnpj): bool
{
$c = $this->normalizar($cnpj);
// 12 posições alfanuméricas (A-Z, 0-9) + 2 dígitos verificadores
if (! preg_match('/^[A-Z0-9]{12}[0-9]{2}$/', $c)) {
return false;
}
if (preg_match('/^0{12}/', $c)) { // base zerada
return false;
}
return $this->calcularDv(substr($c, 0, 12)) === substr($c, 12);
}
private function normalizar(string $s): string
{
return preg_replace('/[^A-Z0-9]/', '', strtoupper($s));
}
private function digito(string $base, array $pesos): int
{
$soma = 0;
for ($i = 0; $i < strlen($base); $i++) {
$soma += (ord($base[$i]) - 48) * $pesos[$i];
}
$resto = $soma % 11;
return $resto < 2 ? 0 : 11 - $resto;
}
private function calcularDv(string $base12): string
{
$d1 = $this->digito($base12, self::PESO1);
$d2 = $this->digito($base12 . $d1, self::PESO2);
return $d1 . $d2;
}
}Observe que normalizar() remove a máscara e força maiúsculas, então a Rule aceita tanto 12.ABC.345/01DE-35 quanto 12abc34501de35. A mesma lógica isolada em funções aparece no nosso tutorial de como validar CNPJ alfanumérico em PHP puro, caso você queira reaproveitá-la fora do Laravel.
Calculando os dígitos verificadores
O coração da Rule são os métodos digito() e calcularDv(). Para cada DV, somamos (ord($char) - 48) * peso posição a posição, tiramos o resto da divisão por 11 e aplicamos a regra resto < 2 ? 0 : 11 - resto. O 1º DV usa os 12 caracteres da base com os pesos PESO1; o 2º DV usa a base já com o 1º DV anexado (13 caracteres) e os pesos PESO2. Como os DV resultantes são sempre dígitos 0–9, a comparação final é uma simples igualdade de strings.
Usando a Rule no FormRequest e no validator
Com a classe pronta, é só referenciá-la como uma instância no array de regras. No FormRequest:
<?php
namespace App\Http\Requests;
use App\Rules\CnpjAlfanumerico;
use Illuminate\Foundation\Http\FormRequest;
class StoreEmpresaRequest extends FormRequest
{
public function rules(): array
{
return [
'cnpj' => ['required', 'string', new CnpjAlfanumerico],
];
}
public function messages(): array
{
return [
'cnpj.required' => 'Informe o CNPJ da empresa.',
];
}
}Ou diretamente no Validator::make() de um controller:
<?php
use App\Rules\CnpjAlfanumerico;
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'cnpj' => ['required', new CnpjAlfanumerico],
]);
if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
}Como testar
- Crie a Rule com
php artisan make:rule CnpjAlfanumericoe cole a lógica golden. - Adicione
new CnpjAlfanumericoàs regras do seu FormRequest ou validator. - Escreva um teste Pest/PHPUnit cobrindo casos válidos, inválidos e o CNPJ numérico clássico.
- Gere massa de teste com o nosso gerador de CNPJ alfanumérico e confira cada número no validador de CNPJ alfanumérico.
Use estes vetores verificados nas suas asserções:
| CNPJ | Tipo | Resultado |
|---|---|---|
12.ABC.345/01DE-35 | Alfanumérico (filial) | Válido |
XP.TO1.234/0001-20 | Alfanumérico (matriz) | Válido |
9F.8E7.D6C/0001-36 | Alfanumérico (matriz) | Válido |
A1.B2C.3D4/E5F6-68 | Alfanumérico (filial) | Válido |
11.222.333/0001-81 | Numérico clássico | Válido |
12.ABC.345/01DE-34 | DV incorreto | Inválido |
Perguntas frequentes
Devo usar ValidationRule ou a antiga interface Rule?
Use Illuminate\Contracts\Validation\ValidationRule com o método validate(). Ela é a forma recomendada no Laravel 10 e 11 e substitui a antiga Illuminate\Contracts\Validation\Rule (com passes() e message()), que está obsoleta. Se você ainda está num projeto Laravel 9, a interface antiga funciona com a mesma lógica de cálculo.
A Rule aceita CNPJ numérico antigo também?
Sim. O algoritmo é o mesmo módulo 11 para os dois formatos — os números são apenas um caso particular em que todos os caracteres têm valor 0–9. Por isso 11.222.333/0001-81 passa na mesma Rule que valida 12.ABC.345/01DE-35, sem condicionais extras.
Como customizar a mensagem de erro em português?
A própria Rule chama $fail('O :attribute informado não é um CNPJ válido.'), e o Laravel substitui :attribute pelo nome do campo. Você pode traduzir o atributo em lang/pt-br/validation.php (chave attributes) para exibir "CNPJ" em vez de "cnpj". Para a mensagem de campo obrigatório, use o método messages() do FormRequest com a chave cnpj.required.
Onde encontro a versão em outras linguagens?
O mesmo algoritmo (ASCII−48 + módulo 11) está pronto em outras stacks, além da versão em PHP puro citada acima. Veja também como validar CNPJ alfanumérico em Python, validar CNPJ alfanumérico em JavaScript, validar CNPJ alfanumérico em Java e validar CNPJ alfanumérico em C#/.NET.
Fontes: Receita Federal (IN RFB 2.229/2024) e nota técnica do Serpro sobre o CNPJ alfanumérico.
Ofertas em destaque
Ver todas →
Amazon
-58%
Smartwatch Samsung Galaxy Fit3 Display 1.6" Grafite
Amazon
Smart TV LCD LED 32" AOC 32S5155/78G - Wi-Fi, HD, Quad Core, Dolby Áudio, 60 Hz
Amazon
-28%
Filtro de Linha CLAMPER iCLAMPER Energia 5, 5 Tomadas, Proteção Contra Surtos Elétricos, 10A, Bivolt, Cabo 1m, Transparente
Amazon
-14%