Grupos exclusivos de desconto no WhatsApp — Faca parte agora! Participar

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 com Rule customizada

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
<?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
<?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
<?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

Passo a passo
  • Crie a Rule com php artisan make:rule CnpjAlfanumerico e 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:

CNPJTipoResultado
12.ABC.345/01DE-35Alfanumérico (filial)Válido
XP.TO1.234/0001-20Alfanumérico (matriz)Válido
9F.8E7.D6C/0001-36Alfanumérico (matriz)Válido
A1.B2C.3D4/E5F6-68Alfanumérico (filial)Válido
11.222.333/0001-81Numérico clássicoVálido
12.ABC.345/01DE-34DV incorretoInvá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.

Assistente PP
Assistente PP
Online agora
Powered by Primeira Solução