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

Validar, gerar e formatar CPF em PHP

Funções em PHP 8 para validar, gerar e formatar CPF com módulo 11, testes com PHPUnit 10 e DataProvider e chamada à API com cURL.

Roberto GuerraPublicado em 05 de outubro de 2026Editar no GitHub

Validar CPF em PHP aparece em quase todo cadastro brasileiro, de formulários em Laravel a integrações com WordPress. As funções desta página usam PHP 8 com strict_types, não dependem de extensão além do PCRE, que vem embutido, e ficam em um namespace próprio para não colidir com outros helpers do projeto. A lógica é a mesma das ferramentas do site, explicada passo a passo no guia do algoritmo do módulo 11.

Validar CPF em PHP

src/cpf.php
<?php

declare(strict_types=1);

namespace Cpf;

function calcularDigito(string $digitos, int $pesoInicial): int
{
  $soma = 0;
  for ($i = 0; $i < strlen($digitos); $i++) {
      $soma += (int) $digitos[$i] * ($pesoInicial - $i);
  }
  $resto = $soma % 11;
  return $resto < 2 ? 0 : 11 - $resto;
}

function validarCpf(string $valor): bool
{
  $cpf = preg_replace('/[.\-\s]/', '', $valor);
  if (preg_match('/^[0-9]{11}$/D', $cpf) !== 1) {
      return false;
  }
  if (preg_match('/^(\d)\1{10}$/', $cpf) === 1) {
      return false;
  }
  $dv1 = calcularDigito(substr($cpf, 0, 9), 10);
  $dv2 = calcularDigito(substr($cpf, 0, 10), 11);
  return $cpf[9] === (string) $dv1 && $cpf[10] === (string) $dv2;
}

O que cada parte resolve:

  • preg_replace('/[.\-\s]/', '', $valor) remove pontos, hífen e espaços. Letras e outros símbolos continuam na string e fazem a checagem seguinte falhar.
  • O modificador D impede que $ aceite uma quebra de linha no fim. A limpeza já remove \n, mas o padrão fica correto mesmo que ela mude.
  • /^(\d)\1{10}$/ recusa sequências como 111.111.111-11, que fecham a conta do módulo 11, mas não são consideradas válidas.
  • A comparação usa strings. $cpf[9] é o caractere "2", e (string) $dv1 também, então === funciona sem conversões implícitas.

Conferindo com 529.982.247-25: a primeira soma é 295, o resto é 9, e o dígito é 2; a segunda soma é 347, o resto é 6, e o dígito é 5. As duas comparações dão true. Com 529.982.247-26, a segunda compara "6" com "5" e a função devolve false.

Em Laravel, embrulhe validarCpf em uma regra de validação (ValidationRule) para reaproveitá-la em todos os Form Requests.

Gerar CPF válido em PHP

random_int usa o gerador criptográfico do sistema operacional, disponível desde o PHP 7.

src/cpf.php
function gerarCpf(bool $formatado = false): string
{
  do {
      $base = '';
      for ($i = 0; $i < 9; $i++) {
          $base .= (string) random_int(0, 9);
      }
  } while (preg_match('/^(\d)\1{8}$/', $base) === 1);
  $dv1 = calcularDigito($base, 10);
  $dv2 = calcularDigito($base . $dv1, 11);
  $cpf = $base . $dv1 . $dv2;
  return $formatado ? formatarCpf($cpf) : $cpf;
}

O CPF gerado passa na validação, mas pode coincidir com um CPF real por acaso. Use-o em seeders e factories de teste, não em produção. Para um volume maior já pronto em SQL ou CSV, o gerador de CPF em lote resolve sem código.

Formatar e limpar CPF em PHP

src/cpf.php
function limparCpf(string $valor): string
{
  return preg_replace('/\D/', '', $valor);
}

function formatarCpf(string $valor): string
{
  $d = limparCpf($valor);
  if (strlen($d) !== 11) {
      throw new \InvalidArgumentException('CPF precisa de 11 dígitos');
  }
  return vsprintf('%s.%s.%s-%s', str_split($d, 3));
}

str_split('52998224725', 3) devolve ['529', '982', '247', '25'], exatamente os quatro blocos da máscara, e vsprintf monta "529.982.247-25". Grave no banco sempre a versão limpa, em uma coluna CHAR(11); o guia sobre validar CPF no banco de dados explica por que uma coluna numérica perde o zero à esquerda.

Testes

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

tests/CpfTest.php
<?php

declare(strict_types=1);

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

use function Cpf\validarCpf;

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

final class CpfTest extends TestCase
{
  public static function casos(): array
  {
      return [
          'válido' => ['529.982.247-25', true],
          'repetido' => ['111.111.111-11', false],
          'dígito errado' => ['529.982.247-26', false],
      ];
  }

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

As chaves do array viram o nome de cada caso na saída do PHPUnit, o que facilita achar a linha que quebrou. Outros casos de borda estão no guia de erros comuns ao validar CPF.

Usar a API em vez de reimplementar

A API do cpf.dev.br valida e gera CPFs por HTTP, sem chave, com limite de 60 requisições por minuto por IP. Para uma consulta simples, file_get_contents basta; com cURL você controla o tempo limite.

api.php
<?php

$json = file_get_contents('https://www.cpf.dev.br/api/v1/cpf/validar/529.982.247-25');
$dados = json_decode($json, true, flags: JSON_THROW_ON_ERROR);
// ['valido' => true, 'cpf' => '52998224725', 'formatado' => '529.982.247-25', 'uf' => ['ES', 'RJ']]

$query = http_build_query(['quantidade' => 5, 'uf' => 'SP', 'formatado' => 'true']);
$ch = curl_init('https://www.cpf.dev.br/api/v1/cpf/gerar?' . $query);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]);
$cpfs = json_decode(curl_exec($ch), true, flags: JSON_THROW_ON_ERROR)['cpfs'];

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 CPF.

Leia também