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.

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