CNPJ alfanumérico com PHP

Disclaimer: Eu não sou uma entidade divina. O que eu falo não é uma verdade absoluta. Não tenha medo de questionar até o mundo, pois ele pode estar errado, não você. #devsforliberty

Hoje o CNPJ (Cadastro Nacional da Pessoa Jurídica) é um número único que identifica uma pessoa jurídica e outros tipos de arranjo jurídico sem personalidade, ou seja, basicamente é um número identificador de uma empresa.

Fonte: Wikipédia

Hoje ele é composto por 14 dígitos ou 18 dígitos se você considerar os pontos, hífen e barra, o famoso 12.345.6789/0001-23, porém, iremos ver que isto irá mudar.

Nota Técnica conjunta COCAD, SUARA e RFB

Recentemente, surgiu uma nova nota técnica com mudanças no número do CNPJ, permitindo além dos números, letras, visando a expansão de combinações, dos atuais 99,9 milhões para quase um trilhão, isto é virtualmente infinito!

Caso queira acessar a nota técnica na integra, basta acessar o endereço http://sadd.receita.fazenda.gov.br/sadd-internet/pages/validadocumento.xhtml e usar o código AP16.0524.06247.2039 para baixar o PDF.

E aqui eu deixo minha pequena e ácida crítica a Receita Federal baseado no dia de hoje, 26/09/2024. É sério mesmo que uma plataforma importante de validação de documento não está com proteção SSL no HTTP Receita? É sério mesmo que vai fazer esse tipo de noobagem nesta altura do campeonato? Foda viu…

CNPJ alfanumérico

Certo, agora iremos ter mudanças no número do CNPJ, como a imagem abaixo.

Felizmente, a fórmula de cálculo do módulo 11, usado para validar o CNPJ não mudou, pois ele vai considerar os valores representados pelas letras, conforme a memória de cálculo, que é claro, iremos ignorar, mas fica bonito no post.

$$DV1 = \begin{cases} 0, & \text{se } \left( \sum_{i=0}^{11} (n_i \times j) \right) \% 11 < 2 \\ 11 - \left( \sum_{i=0}^{11} (n_i \times j) \right) \% 11 \end{cases}$$

$$DV2 = \begin{cases} 0, & \text{se } \left( \sum_{i=0}^{12} (n_i \times j) \right) \% 11 < 2 \\ 11 - \left( \sum_{i=0}^{12} (n_i \times j) \right) \% 11 \end{cases}$$

Porque a memória de cálculo não muda? Porque basicamente o valor de cada letra será o seu valor correspondente na tabela ASCII subtraindo 48. Então a lógica será como abaixo.


A = 65 - 48 = 17
B = 66 - 48 = 18
C = 67 - 48 = 19
D = 68 - 48 = 20
E = 69 - 48 = 21
...
E assim sucessivamente

Vale lembrar que está sendo considerado somente as letras maiúsculas neste cálculo, pois o valor das letras minúsculas são diferentes, então é preciso tomar cuidado com isto.

Tá, como fica isto no PHP?

Bom, como eu estava atoa na calada da noite, decidi refatorar meu Value Object do CNPJ para suportar esse novo cálculo.

Caso você queria ver todas as alterações na íntegra, basta conferir o meu commit 7fd37a3.

Primeiro eu mudei as funções de regex que validavam o valor string que eu recebia para deixar em conformidade com basicamente ser uma string numérica com 11 caracteres e que não tivesse números todos repetidos, como 11111111111111 por exemplo. Agora esta regex também aceita letras maiúsculas e minúsculas.

$number = preg_replace('/[^A-Za-z0-9]/', '', $number);

if (14 != strlen($number)) {
    return false;
}

if (false !== filter_var($number, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/([A-Za-z0-9])\1{13}/']])) {
    return false;
}

Depois disto, eu faço a conversão do meu valor string alfanumérico para um array de 14 elementos números inteiros que serão usados na memória de cálculo para validar o CNPJ.

private const ALPHA_ASCII_SUBTRACT = 48;

/* code */

$numbers = self::convert($number);

/* code */

private static function convert(string $number): array
{
    $numbers = [];
    foreach (str_split($number) as $char) {
        $numbers[] = ctype_alpha($char) ? ord(strtoupper($char)) - self::ALPHA_ASCII_SUBTRACT : (int) $char;
    }

    return $numbers;
}

Note que embora eu esteja aceitando letras maiúsculas ou minúsculas, eu faço a conversão para letras maiúsculas, evitando o erro para o cálculo.

Como a memória de cálculo não mudou, eu basicamente troquei a string numérica pelo array de números para fazer o cálculo.

A implementação completa da classe pode ser conferida em Cnpj.php. Pode usar minha classe a vontade para brincar ou para produção, pois ele usa uma linda licença MIT.

Quando isto irá ocorrer?

Felizmente, a Receita Federal ainda tem um pouco de bom senso, então está previsto a implementação interna deles em 2025 e o início da produção do novo padrão no início de 2026. Parece muito tempo, mas é bom estar preparado antecipadamente para o seu sistema não quebrar.

Então é isto, até a próxima!