Ferramentas gratuitas para desenvolvedores. Nenhum dado real de pessoas é consultado ou armazenado.Como funciona o algoritmo do CPF →
PHP

Validar, gerar e formatar CNPJ em PHP

Funções em PHP 8 para validar, gerar e formatar CNPJ numérico e alfanumérico, testes com PHPUnit 10 e DataProvider e chamada à API com cURL.

Roberto GuerraPublicado em 05 de outubro de 2026Editar no GitHub

Boa parte dos validadores de CNPJ em PHP que circulam por aí começa com preg_replace('/\D/', '', $cnpj). Com o CNPJ alfanumérico, essa linha passa a apagar letras legítimas e transforma um CNPJ válido em lixo. As funções desta página usam PHP 8 com strict_types, só dependem do PCRE embutido e tratam os dois formatos com o mesmo cálculo: cada caractere vale ord($c) - 48, o que dá 0 a 9 para dígitos e 17 a 42 para letras de A a Z. O impacto em banco, máscaras e integrações está no guia CNPJ alfanumérico: o que muda no seu sistema.

Validar CNPJ em PHP (numérico e alfanumérico)

src/cnpj.php
<?php

declare(strict_types=1);

namespace Cnpj;

const PESOS_1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
const PESOS_2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];

function calcularDigito(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;
}

function validarCnpj(string $valor): bool
{
  $cnpj = preg_replace('#[./\-\s]#', '', strtoupper($valor));
  if (preg_match('/^[A-Z0-9]{12}[0-9]{2}$/D', $cnpj) !== 1) {
      return false;
  }
  if (preg_match('/^(.)\1{11}/', $cnpj) === 1) {
      return false;
  }
  $base = substr($cnpj, 0, 12);
  $dv1 = calcularDigito($base, PESOS_1);
  $dv2 = calcularDigito($base . $dv1, PESOS_2);
  return substr($cnpj, 12) === $dv1 . $dv2;
}

O que cada parte resolve:

  • strtoupper antes da limpeza faz 12.abc.345/01de-35 ser tratado como 12.ABC.345/01DE-35.
  • Só pontos, barra, hífen e espaços são removidos. Outros símbolos ficam na string e a regex seguinte recusa a entrada.
  • [A-Z0-9]{12}[0-9]{2} com o modificador D aceita letras na raiz e na ordem, exige dígitos nos verificadores e impede que $ aceite uma quebra de linha no fim.
  • /^(.)\1{11}/ recusa bases repetidas como 00.000.000/0000-00, que fecham a conta, mas não são CNPJs válidos.
  • A comparação é entre strings. $dv1 . $dv2 vira "81", e substr($cnpj, 12) também, então === funciona sem conversão implícita.

Conferindo com 11.222.333/0001-81: a primeira soma é 102, o resto é 3 e o dígito é 8; a segunda soma é 120, o resto é 10 e o dígito é 1. Com 12.ABC.345/01DE-35, as somas são 459 e 424, os restos 8 e 6, e os dígitos 3 e 5. Em Laravel, embrulhe validarCnpj em uma ValidationRule para reaproveitá-la nos Form Requests.

Gerar CNPJ válido em PHP

src/cnpj.php
function gerarCnpj(bool $alfanumerico = false, bool $formatado = false): string
{
  $alfabeto = $alfanumerico ? '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' : '0123456789';
  $max = strlen($alfabeto) - 1;
  do {
      $base = '';
      for ($i = 0; $i < 12; $i++) {
          $base .= $alfabeto[random_int(0, $max)];
      }
  } while (preg_match('/^(.)\1{11}$/', $base) === 1);
  $dv1 = calcularDigito($base, PESOS_1);
  $dv2 = calcularDigito($base . $dv1, PESOS_2);
  $cnpj = $base . $dv1 . $dv2;
  return $formatado ? formatarCnpj($cnpj) : $cnpj;
}

random_int usa o gerador criptográfico do sistema. O CNPJ gerado passa na validação, mas pode coincidir com um CNPJ real por acaso; use-o em seeders e factories de teste. Para fixar a matriz, troque a ordem sorteada por 0001, como explica o guia da estrutura do CNPJ. Para volume em SQL ou CSV sem código, use o gerador de CNPJ em lote.

Formatar e limpar CNPJ em PHP

src/cnpj.php
function limparCnpj(string $valor): string
{
  return preg_replace('/[^A-Z0-9]/', '', strtoupper($valor));
}

function formatarCnpj(string $valor): string
{
  $c = limparCnpj($valor);
  if (strlen($c) !== 14) {
      throw new \InvalidArgumentException('CNPJ precisa de 14 caracteres');
  }
  return sprintf('%s.%s.%s/%s-%s', substr($c, 0, 2), substr($c, 2, 3), substr($c, 5, 3), substr($c, 8, 4), substr($c, 12, 2));
}

formatarCnpj('12abc34501de35') devolve "12.ABC.345/01DE-35", e aplicar a função de novo no resultado não muda nada. Grave sempre a versão limpa, em uma coluna CHAR(14): uma coluna numérica não comporta letras e ainda perde o zero à esquerda. Para validar o formato com máscara em uma única expressão, veja o guia de regex de CNPJ.

Testes

No PHPUnit 10, o provedor de dados usa o atributo #[DataProvider] e precisa ser public static. Como as funções estão no namespace Cnpj, o teste as importa com use function e carrega o arquivo com require_once, caso ele ainda não esteja no autoload do Composer.

tests/CnpjTest.php
<?php

declare(strict_types=1);

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

use function Cnpj\formatarCnpj;
use function Cnpj\gerarCnpj;
use function Cnpj\validarCnpj;

require_once __DIR__ . '/../src/cnpj.php';

final class CnpjTest extends TestCase
{
  public static function casos(): array
  {
      return [
          'numérico válido' => ['11.222.333/0001-81', true],
          'alfanumérico válido' => ['12.ABC.345/01DE-35', true],
          'dígito errado' => ['11.222.333/0001-82', false],
          'repetido' => ['00.000.000/0000-00', false],
      ];
  }

  #[DataProvider('casos')]
  public function testValidarCnpj(string $cnpj, bool $esperado): void
  {
      $this->assertSame($esperado, validarCnpj($cnpj));
  }

  public function testGeradosSaoValidos(): void
  {
      for ($i = 0; $i < 1000; $i++) {
          $this->assertTrue(validarCnpj(gerarCnpj()));
          $this->assertTrue(validarCnpj(gerarCnpj(alfanumerico: true)));
      }
  }

  public function testFormatarEhIdempotente(): void
  {
      $this->assertSame('12.ABC.345/01DE-35', formatarCnpj(formatarCnpj('12abc34501de35')));
  }
}

As chaves do array viram o nome de cada caso na saída do PHPUnit. Outros números para a tabela estão nos exemplos de CNPJ alfanumérico para teste.

Usar a API em vez de reimplementar

A API do cpf.dev.br valida e gera CNPJs por HTTP, sem chave, com limite de 60 requisições por minuto por IP. Envie o CNPJ sem máscara ou passe-o por rawurlencode, que troca a barra por %2F. curl_exec devolve false em erro de rede, e esse caso precisa ser tratado antes do json_decode.

api.php
<?php

function getJson(string $url): array
{
  $ch = curl_init($url);
  curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]);
  $corpo = curl_exec($ch);
  if ($corpo === false) {
      throw new RuntimeException('Falha na requisição: ' . curl_error($ch));
  }
  return json_decode($corpo, true, flags: JSON_THROW_ON_ERROR);
}

$dados = getJson('https://www.cpf.dev.br/api/v1/cnpj/validar/' . rawurlencode('12.ABC.345/01DE-35'));
// ['valido' => true, 'cnpj' => '12ABC34501DE35', 'formatado' => '12.ABC.345/01DE-35',
//  'formato' => 'alfanumerico', 'raiz' => '12ABC345', 'ordem' => '01DE', 'matriz' => false]

$query = http_build_query(['quantidade' => 5, 'formato' => 'alfanumerico', 'formatado' => 'true']);
$cnpjs = getJson('https://www.cpf.dev.br/api/v1/cnpj/gerar?' . $query)['cnpjs'];

Em formulários, a função local continua sendo a melhor escolha: não depende de rede nem conta no limite. Para testar um número à mão, use o validador de CNPJ.

Leia também