

Olá galera, dando continuidade à série de validação de dados. Agora vou falar como criar a validação de CPF usando um gatilho(trigger) e uma função(function) em MySQL. Para esse post eu usei o script de validação de CPF deste artigo aqui escrito pelo Cristiano Martins Alves, no artigo do Cristiano ele mostra uma função para validação em SQL Server, eu apenas adaptei o código dele para que rode em MySQL, as mudanças foram poucas, quase todas foram em função da diferença de sintaxe(ponto e virgula e loops), da função CONVERT para CAST e da função LEN para LENGTH. Depois das alterações o código ficou da seguinte maneira.
-- -------------------------------------------------------------------------------- -- Routine DDL -- -------------------------------------------------------------------------------- DELIMITER $$ CREATE DEFINER=`root`@`localhost` FUNCTION `validarCpf`(CPF CHAR(11)) RETURNS double BEGIN DECLARE INDICE INT; DECLARE SOMA INT; DECLARE DIG1 INT; DECLARE DIG2 INT; DECLARE CPF_TEMP VARCHAR(11); DECLARE DIGITOS_IGUAIS CHAR(1); DECLARE RESULTADO CHAR(1); SET RESULTADO = FALSE; /* Verificando se os dígitos são iguais A Principio CPF com todos o números iguais são Inválidos apesar de validar o Calculo do digito verificado EX: O CPF 00000000000 é inválido, mas pelo calculo Validaria */ SET CPF_TEMP = SUBSTRING(CPF,1,1); SET INDICE = 1; SET DIGITOS_IGUAIS = 'S'; WHILE (INDICE <= 11) DO IF (SUBSTRING(CPF,INDICE,1) <> CPF_TEMP) Then SET DIGITOS_IGUAIS = 'N'; END IF; SET INDICE = INDICE + 1; END WHILE; /*Caso os dígitos não sejam todos iguais Começo o calculo do dígitos*/ IF (DIGITOS_IGUAIS = 'N') THEN /*Cálculo do 1º dígito*/ SET SOMA = 0; SET INDICE = 1; WHILE (INDICE <= 9) DO SET Soma = Soma + CAST(SUBSTRING(CPF,INDICE,1) AS UNSIGNED) * (11 - INDICE); SET INDICE = INDICE + 1; END WHILE; SET DIG1 = 11 - (SOMA % 11); IF (DIG1 > 9) THEN SET DIG1 = 0; END IF; -- Cálculo do 2º dígito } SET SOMA = 0; SET INDICE = 1; WHILE (INDICE <= 10) DO SET Soma = Soma + CAST(SUBSTRING(CPF,INDICE,1) AS UNSIGNED) * (12 - INDICE); SET INDICE = INDICE + 1; END WHILE; SET DIG2 = 11 - (SOMA % 11); IF DIG2 > 9 THEN SET DIG2 = 0; END IF; -- Validando IF (DIG1 = SUBSTRING(CPF,LENGTH(CPF)-1,1)) AND (DIG2 = SUBSTRING(CPF,LENGTH(CPF),1)) THEN SET RESULTADO = TRUE; ELSE SET RESULTADO = FALSE; END IF; END IF; RETURN RESULTADO; END
Executando esse código naquela nossa base de testes (download e leitura da parte 01) a função validaCpf() vai ser criada no seu banco de dados, para executar a função basta executar um SELECT normal chamando a função validaCpf(), como no exemplo abaixo.
SELECT validarCpf('02452345798') FROM dual
Nesse caso irá retornar 0(zero) que corresponde a false/falso, caso você coloque um cpf válido no teste ele irá retornar 1(um) que corresponde a true/verdadeiro. Sendo assim agora basta colocarmos na nossa trigger essa chamada para a validação.
-- Trigger DDL Statements
DELIMITER $$
USE `testes_roberson`$$CREATE DEFINER=`root`@`localhost` TRIGGER trgValidacaoEmail BEFORE INSERT ON clientes
FOR EACH ROW BEGIN
-- Declaro variável para identificar se está válido ou não
DECLARE email DOUBLE DEFAULT FALSE;
DECLARE cpf DOUBLE DEFAULT FALSE;
-- Verificar se e-mail é válido
IF (NOT EXISTS (SELECT NULL FROM Clientes WHERE NEW.Email REGEXP '^[a-zA-Z0-9]{1}([\._a-zA-Z0-9-]+)(\.[_a-zA-Z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+){1,3}$')) THEN
-- Caso seja inválido atribuo true para a variável email
SET email = TRUE;
END IF;
IF ((SELECT validarCpf(NEW.Cpf) FROM dual) = 0 ) THEN
-- Caso seja inválido atribuo true para a variável cpf
SET cpf = TRUE;
END IF;
-- Verifico se as duas variaveis (email e cpf) estão como true, e mostro o erro
IF (email && cpf) THEN
SELECT 0 FROM `Não foi possível inserir os dados! E-mail e CPF inválidos`INTO @error;
END IF;
-- Verifico se a variável email está como true, e mostro o erro
IF (email) THEN
SELECT 0 FROM `Não foi possível inserir os dados! E-mail inválido`INTO @error;
END IF;
-- Verifico se a variável cpf está como true, e mostro o erro
IF (cpf) THEN
SELECT 0 FROM `Não foi possível inserir os dados! CPF inválido`INTO @error;
END IF;
END$$
Criando essa trigger ou alterando a existente do exemplo anterior, a trigger será disparada todas as vezes que algum dado for ser inserido no banco e verificará tanto e-mail quanto CPF. Eu gostaria de ter feito esse exemplo de uma maneira um pouco diferente, queria armazenar em uma variável a string com o erro a cada verificação, e ao final concatenar elas e exibir o erro, porem não consegui que o CONCAT funciona-se dentro da clausula FROM. Caso alguem consiga algo do tipo, por favor me envie que eu atualizo aqui no script, e eu também vou continuar tentando fazer essa alteração.
O exemplo php da parte 01 continua funcionando da mesma maneira, para testarmos basta mudar no insert para um cpf inválido. Quando o E-mail e/ou CPF forem inválidos o erro será mostrado.
Espero ter contribuido com algo, sugestões, criticas ou elogios são muito bem aceitos. Espero que aproveitem e sucesso a todos.
Veja também:
Validando dados inseridos no banco MySql – Parte 01
Posts relacionados:






More Options ...
Categorias
Nuvem de Tags
Blog RSS
Comentários RSS

Void « Default
Life
Earth
Wind
Water
Fire
Light 
Pq exatamente fazer uma validação em Banco? Ainda mais usando uma trigger
Um dos porque é, digamos que você tenha um unico banco de dados para mais de um aplicativo(web, desktop, mobile, etc), sendo assim a validação não precisa ser feita em cada um dos aplicativos, uma unica validação é feita para todos os aplicativos, fazendo assim com que os dados sejam todos validados da mesma maneira, evitando inconsistencias. Pensando em grandes sistemas aonde existem vários programadores trabalhando em cima do mesmo banco/sistema, evitamos que algum dos programadores esqueça de fazer a validação na tela X ou Y. Pense que dessa forma não tem como o dado entrar incorreto no banco, até mesmo se alguem conseguir colocar uma query diretamente no banco, essa query vai ser validada.
Assim temos 100% de certeza que os dados só entram na tabela se forem válidos.
Talvez o exemplo de email e de CPF não seja o melhor exemplo pois são coisas “banais” que dificilmente são esquecidas, e geralmente são bem testadas, mas se você tiver uma validação peculiar a aquele campo, onde é preciso fazer um calculo complexo, algo não tão comum ou um calculo “secreto” de segurança que não pode ser divulgado nem dentro da propria empresa, nesse caso não precisa ensinar ou divulgar a forma como tal dado é validado, simplesmente o dado só irá entrar no banco se estiver correto. Estou escrevendo um outro post que mostra um exemplo mais peculiar onde a necessidade é mais clara.
Lembrando que triggers e procedures não são só para validações, existem muitas outras utilidades que pretendo exclarecer em próximos posts.
Obrigado pela participação, e espero ter sido claro.
Ótimo post Roberson parabéns!
Só uma observação:
No ultimo END da função de validar CPF faltou o “$$”
Tudo bem Roberson!
Ótimo post, parabéns, só pra endossar ai o que você falou sobre a utilidade de se ter a validação no banco, quando criei a função para SQL Server a estava desenvolvendo um integração com uma URA (Unidade de Resposta Audível) essa o sistemas da URA precisava por meio de funções no banco fazer uma série de consistências uma delas era o CPF que o cliente havia digitado no telefone.
Obrigado Cristiano por esse excelente exemplo de utilização, também tenho usado muito esse tipo de validação em integrações de webservice.
Onde se coloca esse código?
Para utilizar você deve customizar para as suas necessidades e executar no banco de dados da mesma maneira que você executa uma query. Ao Executar as procedures/functions/ trigger serão criadas no seu banco.
Qualquer dúvida manda ai.
Olá.
Fazia um tempo que eu procurava uma coisa como está ue vc apresentou aqui e eu agradeço muito por você ter postado isso.
Ms nasceu em mim uma duvida
Suponha que eu tenha uma base com 1000 cpfs cadastrados e que eu deseje testar e validar todos estes cadastros para, no final, mostrar em tela todos os cadastros com cps frios (…).
Eu acho que é um select a ser feito, mas posso estar enganado, sou novo na área.
Poderia me dar uma luz por favor?
desde já obrigado
Olá Cláudio
É só executar um select mesmo, ele vai correr todos os registros validando e retornando TRUE ou FALSE.
SELECT validarCpf(campo_cpf) FROM tabela
Testa ai, qualquer coisa deixa um comentário.
Então Roberson, eu sou novo em PHP
eu tentei assim, mas nao encontro a maneira de buscar os cpfs falsos
Pode me dar uma luz?
Obrigado
$conn = mysql_connect(“localhost”, “root”, “zyUGA69BUGA”,”testes_roberson”);
$sql = “SELECT validarCpf(Cpf) FROM clientes”;
echo ”;
while ($dados = mysqli_fetch_array ($sql))
{
echo “”;
echo “” . $dados['cpf'] . “”;
echo “”;
}
Olá Cláudio, é isso mesmo, vou modificar um pouco seu código para ficar mais facil a visualização. Testa ai e me diz se deu certo.
$conn = mysql_connect(“localhost”, “root”, “zyUGA69BUGA”,”testes_roberson”);
$sql = “SELECT cpf, validarCpf(Cpf) as valid FROM clientes”;
while ($dados = mysqli_fetch_array ($sql))
{
echo $dados['cpf'] . “ = ”;
var_dump($dados['valid']);
echo “
“;
}
Assim vai listar os CPF e ao lado se ele é válido ou não. Acredito que assim fique mais facil de visualizar a validação.
Pois é ara, eu penei aqui pp meu apache parou de rodar e eu estou de noite virada.
Deu erro, este aqui
Warning: mysql_fetch_array() expects parameter 1 to be resource, string given in C:\xampp\htdocs\valido.php on line 5
isso aqui: while ($dados = mysql_fetch_array ($sql))
Muito obrigado pela paciência que vc esta tendo
Cláudio, eu só copiei o seu codigo e ajuste, não reparei que estava faltando o mysql_query(). Segue novamente o codigo:
$conn = mysql_connect(“localhost”, “root”, “zyUGA69BUGA”,”testes_roberson”);
$sql = “SELECT cpf, validarCpf(Cpf) as valid FROM clientes”;
$result = mysql_query($sql);
while ($dados = mysqli_fetch_array ($result))
{
echo $dados['cpf'] . “ = ”;
var_dump($dados['valid']);
echo ““;
}
Valeu
Nós comemoos bola, faltava um monte de coisa, inclusive a seleção da base
Eu fiz assim:
<?php
$conn = mysql_connect("localhost", "root", "","testes_roberson");
mysql_select_db("testes_roberson", $conn);
$sql = mysql_query("SELECT cpf, validarCpf(Cpf) as valid FROM clientes");
while($dados = mysql_fetch_array ($sql))
{
echo $dados['cpf'] . " = " . "”;
echo($dados['valid']) . “”;
echo “”;
}
?>
resultou num 0 (falso) e tres verdadeiros.
Deu para eu entender.
eu queria que vc me sanasse uma curiosidade
Se eu entendi bem o que vc escreveu a rotina de validação era, no passado, uma rotin Java script… Isso está correto?
Poque se estiver correto eu posso usar uma rotina que avalie cpf e cnpj dando maior amplitude ao esquema.
Agora vou estudar uma maneira de retornar documento Autentico e documento falso com base nos zeros e nos 1.
muito obrigado
eu sei que on erro foi meu, estava trebado de sono
No fim, para alcançar minhas finalidades, eu deicei assim:
<?php
$conn = mysql_connect("localhost", "root", "","testes_roberson");
mysql_select_db("testes_roberson", $conn);
$sql = mysql_query("SELECT cpf, nome, sobrenome, email, validarCpf(Cpf) as valid, email FROM clientes");
while($dados = mysql_fetch_array ($sql))
{
If ($dados['valid']== 0 )
echo "O documento " . $dados['cpf'] . " de " .$dados['nome']." " . $dados['sobrenome'] . " é inválido. “;
}
?>
Roberson, tentando me aprofundar nisso eu acabei achando uma procedure para validação de cnpj.
Estou postando ela aqui sem testar.
Minha meta e fundir as duas procedures em uma só para validar um campo onde entraria o cpf e o cnpj
Muito obrigado pela atenção
DELIMITER $$
DROP FUNCTION IF EXISTS fc_validarCNPJ $$
CREATE FUNCTION fc_validarCNPJ(CNPJ CHAR(20))
RETURNS int(11)
BEGIN
DECLARE _CNPJ varchar (14);
DECLARE _multiplicador_1 varchar(12);
DECLARE _multiplicador_2 varchar(13);
DECLARE _resultado int;
DECLARE _contador int;
DECLARE _digito_1 int;
DECLARE _digito_2 int;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
RETURN 0;
END;
SET _contador = 1;
SET _resultado = 0;
SET _digito_1 = 0;
SET _digito_2 = 0;
SET _CNPJ = substring(CNPJ, 1, 12);
SET _multiplicador_1 = ’543298765432′;
SET _multiplicador_2 = ’6543298765432′;
IF(CNPJ IS NULL) THEN
RETURN NULL;
END IF;
IF(CHAR_LENGTH(CNPJ) != 14) THEN
RETURN 0;
END IF;
WHILE(_contador <= 12) DO
SET _resultado = _resultado
+ CAST( substring(_CNPJ, _contador, 1) AS UNSIGNED)
* CAST( substring(_multiplicador_1, _contador, 1) AS UNSIGNED);
SET _contador = _contador + 1;
END WHILE;
SET _resultado = _resultado%11;
IF (_resultado < 2)THEN
SET _digito_1 = 0;
ELSE
SET _digito_1 = 11 – _resultado;
END IF;
SET _CNPJ = CONCAT( _CNPJ, _digito_1);
SET _contador = 1;
SET _resultado = 0;
WHILE(_contador <= 13) DO
SET _resultado = _resultado
+ CAST(substring(_CNPJ, _contador, 1) AS UNSIGNED)
* CAST(substring(_multiplicador_2, _contador, 1) AS UNSIGNED);
SET _contador = _contador + 1;
END WHILE;
SET _resultado = (_resultado%11);
IF(_resultado < 2)THEN
SET _digito_2 = 0;
ELSE
SET _digito_2 = 11 – _resultado;
END IF;
SET _CNPJ = CONCAT( _CNPJ , _digito_2);
IF(substring(CNPJ, 13, 1) _digito_1)
OR (substring(CNPJ, 14, 1) _digito_2) THEN
RETURN 0;
END IF;
RETURN 1;
END $$
DELIMITER ;
Opa legal Cláudio, vou ver de montar algo do tipo e publicar uma parte 03 desse post complementando com o cnpj.
Valeu