Validar CPF em PHP: algoritmo, biblioteca e API com fallback
Três formas de validar CPF em PHP: do algoritmo cru do DV à biblioteca pronta, terminando com API para checagem anti-fraude. Código pronto pra copiar.
Validar CPF em PHP parece trivial até você descobrir que 70% dos snippets espalhados pela internet têm bug — não rejeitam sequências como 111.111.111-11 ou falham em CPFs com zeros à esquerda. Este guia mostra três formas correta, do simples ao paranoico.
O algoritmo do dígito verificador
CPF tem 11 dígitos. Os dois últimos são os DVs calculados a partir dos nove primeiros. A regra é fixa há décadas:
- Multiplica os nove primeiros dígitos por 10, 9, 8, 7, 6, 5, 4, 3, 2 respectivamente.
- Soma os resultados.
- Multiplica a soma por 10 e divide por 11. O resto é o primeiro DV (se for 10, vira 0).
- Repete o processo incluindo o primeiro DV, multiplicando por 11, 10, 9... 2.
Implementação 1: função pura sem dependência
<?php
function validarCpf(string $cpf): bool
{
// Tira pontuação
$cpf = preg_replace('/\D/', '', $cpf);
// Tem que ter 11 dígitos
if (strlen($cpf) !== 11) {
return false;
}
// Rejeita sequências repetidas (111.111.111-11, 222.222.222-22...)
if (preg_match('/^(\d)\1{10}$/', $cpf)) {
return false;
}
// Calcula primeiro DV
$soma = 0;
for ($i = 0; $i < 9; $i++) {
$soma += (int) $cpf[$i] * (10 - $i);
}
$dv1 = ($soma * 10) % 11;
if ($dv1 === 10) {
$dv1 = 0;
}
if ($dv1 !== (int) $cpf[9]) {
return false;
}
// Calcula segundo DV
$soma = 0;
for ($i = 0; $i < 10; $i++) {
$soma += (int) $cpf[$i] * (11 - $i);
}
$dv2 = ($soma * 10) % 11;
if ($dv2 === 10) {
$dv2 = 0;
}
return $dv2 === (int) $cpf[10];
}
// Uso
var_dump(validarCpf('123.456.789-09')); // true ou false
var_dump(validarCpf('111.111.111-11')); // false (sequência)
var_dump(validarCpf('11144477735')); // true (CPF didático válido)
Essa função cobre 99% dos casos. Aceita CPF com pontos, hífens ou só números. Rejeita sequências repetidas (que tecnicamente passam no DV mas claramente são falsas).
Implementação 2: biblioteca pronta (Laravel)
Se você está no Laravel, a forma idiomática é usar uma rule de validação. A community lib mais popular é laravel-validation-rules/cpf-cnpj:
composer require laravel-validation-rules/cpf-cnpj
use LaravelValidationRules\Rules\Cpf;
$request->validate([
'cpf' => ['required', new Cpf()],
]);
Vantagem: integra direto com FormRequest, mensagens de erro traduzidas, sem você precisar manter o algoritmo. Use para forms internos.
Implementação 3: API anti-fraude
Validação local resolve a parte matemática mas não detecta CPFs falsos com DV correto. Para checkouts críticos vale uma checagem complementar via API que cruza com bases reais:
use Falcon\DataHub\Client;
$client = new Client('SEU_TOKEN');
$result = $client->cpf('12345678909');
if (!$result->valid) {
return 'CPF inválido';
}
if ($result->suspicious) {
return 'CPF suspeito (sequência ou padrão atípico)';
}
// Premium: cruzamento com QSA de CNPJ, XML de NFe etc.
if ($result->found_in && count($result->found_in) > 0) {
echo "CPF aparece em: ";
foreach ($result->found_in as $context) {
echo "{$context->type} ";
}
}
Aqui o ganho não é validação do DV — isso já fez localmente em microsegundos. O ganho é o cruzamento. Saber que o CPF aparece como sócio em algum CNPJ ou como destinatário em NFes legítimas é forte sinal anti-fraude.
Qual abordagem escolher
| Cenário | Abordagem |
|---|---|
| Form interno de cadastro | Função pura ou rule do Laravel |
| Validação em tempo real no front | Algoritmo no client (JS) + função no backend |
| Checkout de e-commerce | Rule do Laravel + API anti-fraude para risco alto |
| Verificação de sócio em B2B | API com enriquecimento (qsa, xml) |
A maioria dos sistemas começa com 1 ou 2 e adiciona 3 quando começa a tomar fraude. Não precisa over-engineering desde o dia zero.
Cuidado comum: zero à esquerda
PHP tem uma armadilha clássica: se você fizer (int) '01234567890', vira 1234567890 e perde um dígito. Por isso o código acima trata o CPF como string até o último momento, e só converte cada dígito individualmente para int dentro do loop. Cuidado com intval($cpf) antes da validação — vai te morder.
Conclusão
Para 90% dos usos, a função pura resolve. Lib do Laravel é açúcar para FormRequest. API anti-fraude entra quando o custo de aceitar um CPF falso é maior que o custo da chamada externa. Comece simples e suba o nível conforme o problema aparecer.
Gostou do artigo?
Comece a usar a API do Falcon Data Hub agora. Plano grátis, sem cartão.
Criar conta grátis