Created
May 30, 2018 15:47
-
-
Save fernandosavio/ffa417fa9f0e48879134735e5381a8d5 to your computer and use it in GitHub Desktop.
Validadores de CPF e CNPJ mais legíveis e PHP 7.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Utils | |
{ | |
/** | |
* Tira qualquer caracter que não seja número da string | |
* @param string $str | |
* @return string | |
*/ | |
public static function onlyNumbers(string $str) : string | |
{ | |
return preg_replace('#\D+#', '', $str); | |
} | |
/** | |
* Garante que $cpf contenha apenas números de tenha a quantidade de dígitos correta | |
* @param string $cpf | |
* @return string | |
* @throws \InvalidArgumentException | |
*/ | |
private static function sanitizeCPF(string $cpf) : string | |
{ | |
$cpf = self::onlyNumbers($cpf); | |
if (strlen($cpf) !== 11) | |
throw new \InvalidArgumentException("CPF deve ter 9 números"); | |
return $cpf; | |
} | |
/** | |
* Garante que $cnpj contenha apenas números de tenha a quantidade de dígitos correta | |
* @param string $cnpj | |
* @return string | |
* @throws \InvalidArgumentException | |
*/ | |
private static function sanitizeCNPJ(string $cnpj) : string | |
{ | |
$cnpj = self::onlyNumbers($cnpj); | |
if (strlen($cnpj) !== 14) | |
throw new \InvalidArgumentException("CNPJ deve ter 14 números"); | |
return $cnpj; | |
} | |
/** | |
* Valida os dígitos verificadores com código mais moderno e legível dos que encontrei na internet. | |
* @see http://www.geradorcpf.com/algoritmo_do_cpf.htm | |
* @param string $cpf Uma string com o CPF (com máscara ou apenas números) | |
* @return bool verdadeiro se o CPF é válido | |
*/ | |
public static function validaCPF(string $cpf) : bool | |
{ | |
// prepara a string para trabalhar nela | |
try { | |
$cpf = self::sanitizeCPF($cpf); | |
} catch (\InvalidArgumentException $e) { | |
return false; | |
} | |
// Não pode ser números repetidos. Ex.: 000.000.000-00, 333.333.333-33, etc... | |
if (preg_match('#^(\d)\1{10}$#', $cpf)) { | |
return false; | |
} | |
/* quebra "11122233399" para: | |
$numeros = [1, 1, 1, 2, 2, 2, 3, 3, 3]; | |
$verificadores = [9, 9]; */ | |
list($numeros, $verificadores) = array_chunk(array_map('intval', str_split($cpf)), 9); | |
// Multiplica cada elemento com os números correspondentes e então soma tudo | |
$soma = array_sum(array_map(function (int $num, int $num_aux) { | |
return $num * $num_aux; | |
}, $numeros, range(10, 2))); | |
// Calcula o dígito verificador | |
$digito = $soma % 11; | |
$digito = $digito < 2 ? 0 : 11 - $digito; | |
// Se o primeiro dígito verificador não bateu, o CNPJ é inválido | |
if ($verificadores[0] != $digito) { | |
return false; | |
} | |
// Prepara as variáveis para a próxima iteração do algoritmo | |
$numeros[] = $digito; | |
// Soma o resultado das multiplicações | |
$soma = array_sum(array_map(function (int $num, int $num_aux) { | |
return $num * $num_aux; | |
}, $numeros, range(11, 2))); | |
// Calcula o segundo dígito verificador | |
$digito = $soma % 11; | |
$digito = $digito < 2 ? 0 : 11 - $digito; | |
// Se o segundo dígito confere então o CNPJ é válido | |
return $digito === $verificadores[1]; | |
} | |
/** | |
* Valida os dígitos verificadores com código mais moderno e legível dos que encontrei na internet. | |
* @see http://www.geradorcnpj.com/algoritmo_do_cnpj.htm | |
* @param string $cnpj Uma string com o CPF (com máscara ou apenas números) | |
* @return bool verdadeiro se o CNPJ é valido | |
*/ | |
public static function validaCNPJ(string $cnpj) : bool | |
{ | |
// prepara a string para uso | |
try { | |
$cnpj = self::sanitizeCNPJ($cnpj); | |
} catch (\InvalidArgumentException $e) { | |
return false; | |
} | |
// Não pode ser números repetidos. Ex.: 00.000.000/0000-00, 333.333.333-33, etc... | |
if (preg_match('#^(\d)\1{13}$#', $cnpj)) { | |
return false; | |
} | |
/* quebra "11222333000199" para: | |
$numeros = [1, 1, 2, 2, 2, 3, 3, 3, 0, 0, 0, 1]; | |
$verificadores = [9, 9]; */ | |
list($numeros, $verificadores) = array_chunk(array_map('intval', str_split($cnpj)), 12); | |
// Valores que serão multiplicados pelos números | |
$aux = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]; | |
// Multiplica cada elemento de $aux com os números correspondentes e então soma tudo | |
$soma = array_sum(array_map(function (int $num, int $num_aux) { | |
return $num * $num_aux; | |
}, $numeros, $aux)); | |
// Calcula o dígito verificador | |
$digito = $soma % 11; | |
$digito = $digito < 2 ? 0 : 11 - $digito; | |
// Se o primeiro dígito verificador não bateu, o CNPJ é inválido | |
if ($verificadores[0] != $digito) { | |
return false; | |
} | |
// Prepara as variáveis para a próxima iteração do algoritmo | |
array_unshift($aux, 6); | |
$numeros[] = $digito; | |
// Soma o resultado das multiplicações | |
$soma = array_sum(array_map(function (int $num, int $num_aux) { | |
return $num * $num_aux; | |
}, $numeros, $aux)); | |
// Calcula o segundo dígito verificador | |
$digito = $soma % 11; | |
$digito = $digito < 2 ? 0 : 11 - $digito; | |
// Se o segundo dígito confere então o CNPJ é válido | |
return $digito === $verificadores[1]; | |
} | |
/** | |
* Formata CPF para padrão "###.###.###-##" | |
* @param string $cpf | |
* @return string | |
*/ | |
public static function formatCPF(string $cpf) : string | |
{ | |
$cpf = self::sanitizeCPF($cpf); | |
$matches = []; | |
preg_match('~^(\d{3})(\d{3})(\d{3})(\d{2})$~', $cpf, $matches); | |
list( , $part1, $part2, $part3, $verificador) = $matches; | |
return "$part1.$part2.$part3-$verificador"; | |
} | |
/** | |
* Formata CNPJ para padrão "##.###.###/####-##" | |
* @param string $cnpj | |
* @return string | |
*/ | |
public static function formatCNPJ(string $cnpj) : string | |
{ | |
// garante que a string contém apenas números | |
$cnpj = self::onlyNumbers($cnpj); | |
// valida a string | |
if (strlen($cnpj) !== 14) { | |
throw new \InvalidArgumentException("CNPJ deve ter 14 números"); | |
} | |
$matches = []; | |
preg_match('~^(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})$~', $cnpj, $matches); | |
list( , $part1, $part2, $part3, $part4, $verificador) = $matches; | |
return "$part1.$part2.$part3/$part4-$verificador"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment