Diferentemente do RG um CPF (ou CNPJ) é um identificador único. Um CPF identifica uma pessoa única no Brasil. É uma boa prática associar contas de usuário com seu CPF. Seguro para o usuário, pois diminui o risco de alguém se passar por ele, e seguro para quem presta algum serviço, pois pode identificar um usuário infrator.
Lógico que essa não deveria nem de longe ser a única medida de segurança e identificação de um usuário, mas já é um começo.
Quando você coloca o CPF como campo obrigatório em um formulário de cadastro no seu sistema torna-se difícil testar esse formulário porque você precisa validar o CPF para ver se é correto, mas também precisa de CPF's válidos e únicos para usar nos seus testes. O que fazer?
Pensando nisso coloquei esse gerador de CPF e CNPJ que você pode ver na barra lateral do blog, e fiz esse programinha em lazarus para gerar e/ou validar CPF's e CNPJ's. Você pode copiar esse algoritmo para validar documentos nos seus cadastros.
Funcionamento do CPF:
O CPF é formado por 11 dígitos (excetuando-se as pontuações e separadores), 9 do número do documento e 2 de verificação.
O 10° dígito é baseado em um algoritmo feito com os 9 dígitos precedentes, e o 11° é calculado usando-se os 9 primeiros mais o 10° recém calculado. Ou seja, se seu CPF é 74241980503 (ainda não chegamos nesse número espero) isso quer dizer que fazendo o referido algoritmo com 742419805 você encontrará o 0 e fazendo com 7424198050 você encontrará o 3.
O algoritmo consiste em 3 passos:
1) multiplicar, da esquerda para a direita, cada dígito por um valor n que começará com 10 e decrescerá (n-1 com n nunca sendo < 2) a cada casa para a direita, acumulando-se (somando-se) cada resultado. Por exemplo, o CPF que mencionamos iniciaríamos o calculo assim:
(
7 x 10)+(
4 x 9)+(
2 x 8)+(
4 x 7)+(
1 x 6)+(
9 x 5)+(
8 x 4)+(
0 x 3)+(
5 x 2) que seria 70+36+16+28+6+45+32+0+10=243
2) Obter o resto da divisão dessa soma por 11, ou seja 243 mod 11 = 1
3) Subtrair o resultado de 11, ou seja, 11 - 1. Se o resultado for maior que 9 colocamos 0. Então 11-1 = 10, portanto 0. Há alguns que verificam se o módulo por 11 é menor que 2, se for o resultado do dígito é 0, senão será 11 subtraindo-se o módulo. Tanto faz a ordem dos fatores, dá no mesmo.
O 11° dígito obtem-se da mesma maneira, porém começando-se a multiplicação por 11, então se até agora temos 742419805
0X devemos fazer:
(7 x 11) + (4 x 10) + (2 x 9) + (4 x 8) + (1 x 7 ) + (9 x 6) + (8 x 5) + (0 x 4) + (5 x 3 ) + (0 x 2) = 283
283 mod 11 = 8
11-8 = 3, por isso o último dígito é 3.
Criamos a seguinte função para calcular o DV do CPF, supondo-se que os 9 primeiros dígitos são dados:
function TfrmDocumentos.CalculaDVCPF(cpf: string): string;
var
digitos: array [1..11] of integer;
begin
digitos[1] := StrToInt(cpf[1]);
digitos[2] := StrToInt(cpf[2]);
digitos[3] := StrToInt(cpf[3]);
digitos[4] := StrToInt(cpf[4]);
digitos[5] := StrToInt(cpf[5]);
digitos[6] := StrToInt(cpf[6]);
digitos[7] := StrToInt(cpf[7]);
digitos[8] := StrToInt(cpf[8]);
digitos[9] := StrToInt(cpf[9]);
digitos[10] := 11 -
(((digitos[1] * 10)+
(digitos[2] * 9)+
(digitos[3] * 8)+
(digitos[4] * 7)+
(digitos[5] * 6)+
(digitos[6] * 5)+
(digitos[7] * 4)+
(digitos[8] * 3)+
(digitos[9] * 2)) mod 11);
if digitos[10] > 9 then
digitos[10] := 0;
digitos[11] := 11 -
(((digitos[1] * 11)+
(digitos[2] * 10)+
(digitos[3] * 9)+
(digitos[4] * 8)+
(digitos[5] * 7)+
(digitos[6] * 6)+
(digitos[7] * 5)+
(digitos[8] * 4)+
(digitos[9] * 3)+
(digitos[10] * 2)) mod 11);
if digitos[11] > 9 then
digitos[11] := 0;
Result := IntToStr(digitos[10])+IntToStr(digitos[11]);
end;
Para gerar números randômicos de 9 dígitos, para serem passadas para a função acima, usamos:
function TfrmDocumentos.GeraCPF: string;
var
iNum: integer;
begin
Randomize;
iNum:=random(999999999);
Result := ZeroEsquerda(IntToStr(iNum), 9);
end;
A função ZeroEsquerda serve para completar uma string numérica com zeros a esquerda até a quantidade de dígitos definidas no segundo parâmetro e é definida como a seguir:
function TfrmDocumentos.ZeroEsquerda(num: string; tamanho: integer): string;
var i: integer;
tamAtual: integer;
begin
Result := num;
tamAtual:= tamanho - Length(num);
for i := 1 to tamAtual do
Result := '0'+Result;
end;
As funções abaixo são usadas para limpar um CPF ou CNPJ se ele possui caracteres de pontuação, ou para colocar os caracteres de pontuação nas posições corretas de acordo com o tipo de documento.
//elimina caracteres não numéricos da string
function TfrmDocumentos.Limpa(documento: string): string;
var
i: integer;
begin
for i := 1 to Length(documento) do
if documento[i] in ['0'..'9'] then
Result := Result+documento[i];
end;
//insere as pontuações nas posições corretas
function TfrmDocumentos.Mascara(documento: string): string;
var
i: integer;
temp: string;
begin
temp := Limpa(documento);
if Length(temp) = 11 then
begin
Insert('.', temp, 4);
Insert('.', temp, 8);
Insert('-', temp, 12);
end
else
begin
Insert('.', temp, 3);
Insert('.', temp, 7);
Insert('/', temp, 11);
Insert('-', temp, 16);
end;
Result := temp;
end;
Para gerar um CPF utilizamos:
procedure TfrmDocumentos.btGeraCPFClick(Sender: TObject);
var
sCPF: string; //9 primeiros digitos
begin
sCPF:=GeraCPF;
//edit com o cpf completo
txtGCPF.Text := sCPF+CalculaDVCPF(sCPF)
end;
Para verificar se um CPF é válido obtemos os 9 primeiros dígitos, separamos dos dois posteriores e calculamos os DV's para esses 9 dígitos. Se eles forem iguais aos dois últimos dígitos que extraímos então o CPF é válido.
procedure TfrmDocumentos.btValidaCPFClick(Sender: TObject);
var
temp, sCpf, sDv: string;
begin
temp := Limpa(txtVCPF.Text);
sCpf:=Copy(temp, 1, 9);
sDv := Copy(temp, 10, 2);
if (Length(temp) = 11) and (CalculaDVCPF(sCpf) = sDv) then
begin
lbMsg.Caption := 'Cpf Válido';
lbMsg.Font.Color:=clGreen;
end
else
begin
lbMsg.Caption := 'Cpf Inválido';
lbMsg.Font.Color:=clRed;
end;
end;
A mesma lógica se aplica com o CNPJ. A única diferença é que o CNPJ se divide em três blocos:
O número (8 primeiros dígitos) o número da filial ou famoso "mil ao contrário/mil contra" que são os 4 posteriores e os dois últimos são o DV.
Para calcular o dígito 13 multiplicamos os 12 primeiros por 5,4,3,2,9,8,7,5,6,4,3,2 e depois somamos as parcelas, retiramos o resto da divisão por 11, subtraimos este resultado de 11 e tudo que for maior que 9 passa a ser 0, não for maior que 9 permanece.
Para calcular o 14° dígito multiplicamos os 13 primeiros, incluindo aí o primeiro DV, por 6,5,4,3,2,9,8,7,6,5,4,3,2 e repetimos o processo.
Esse é o algoritmo em lazarus:
function TfrmDocumentos.CalculaDVCNPJ(cnpj: string): string;
var
digitos: array [1..14] of integer;
begin
digitos[1] := StrToInt(cnpj[1]);
digitos[2] := StrToInt(cnpj[2]);
digitos[3] := StrToInt(cnpj[3]);
digitos[4] := StrToInt(cnpj[4]);
digitos[5] := StrToInt(cnpj[5]);
digitos[6] := StrToInt(cnpj[6]);
digitos[7] := StrToInt(cnpj[7]);
digitos[8] := StrToInt(cnpj[8]);
digitos[9] := StrToInt(cnpj[9]);
digitos[10] := StrToInt(cnpj[10]);
digitos[11] := StrToInt(cnpj[11]);
digitos[12] := StrToInt(cnpj[12]);
digitos[13] := 11 - ((
(digitos[1] * 5)+
(digitos[2] * 4)+
(digitos[3] * 3)+
(digitos[4] * 2)+
(digitos[5] * 9)+
(digitos[6] * 8)+
(digitos[7] * 7)+
(digitos[8] * 6)+
(digitos[9] * 5)+
(digitos[10] * 4)+
(digitos[11] * 3)+
(digitos[12] * 2)
) mod 11);
if digitos[13] > 9 then
digitos[13] := 0;
digitos[14] := 11 - ((
(digitos[1] * 6)+
(digitos[2] * 5)+
(digitos[3] * 4)+
(digitos[4] * 3)+
(digitos[5] * 2)+
(digitos[6] * 9)+
(digitos[7] * 8)+
(digitos[8] * 7)+
(digitos[9] * 6)+
(digitos[10] * 5)+
(digitos[11] * 4)+
(digitos[12] * 3)+
(digitos[13] * 2)
) mod 11);
if digitos[14] > 9 then
digitos[14] := 0;
Result := IntToStr(digitos[13])+IntToStr(digitos[14]);
end;
Respectivamente estes são os códigos para gerar, criar e validar CNPJ:
function TfrmDocumentos.GeraCNPJ: string;
var
iNum: Int64;
begin
Randomize;
iNum:=random(999999999999);
Result := ZeroEsquerda(IntToStr(iNum), 12);
end;
procedure TfrmDocumentos.btGeraCNPJClick(Sender: TObject);
var
sCNPJ: string;
begin
sCNPJ:=GeraCNPJ;
if cbMascara.Checked then
txtGCNPJ.Text := Mascara(sCNPJ+CalculaDVCNPJ(sCNPJ))
else
txtGCNPJ.Text := sCNPJ+CalculaDVCNPJ(sCNPJ);
end;
procedure TfrmDocumentos.btValidaCNPJClick(Sender: TObject);
var
temp, sCNPJ, sDv: string;
begin
temp := Limpa(txtVCNPJ.Text);
sCNPJ:=Copy(temp, 1, 12);
sDv := Copy(temp, 13, 2);
if (Length(temp) = 14) and (CalculaDVCNPJ(sCNPJ) = sDv) then
begin
lbMsg.Caption := 'CNPJ Válido';
lbMsg.Font.Color:=clGreen;
end
else
begin
lbMsg.Caption := 'CNPJ Inválido';
lbMsg.Font.Color:=clRed;
end;
end;
Como essas regras e fórmulas são rígidas, bem como os tamanhos e posições dos documentos, optei por usar um vetor de tamanho fixo e armazenar cada valor em sua posição em vez de usar um loop for. Assim eu economizo algumas variáveis temporárias de somatório e módulo, efetuo as somas e divisões uma única vez e a transformação de str para int apenas uma vez, e as transformações de int para str apenas nos dois últimos dígitos, os DV.
Espero ter esclarecido como funciona essa validação.
Você pode baixar o programa aqui.
Comentários
Postar um comentário