Inclusão – Sistema de Cadastro com PHP + PDO e MySQL
Hoje vamos construir um formulário para inclusão de dados com HTML, CSS, JavaScript, PHP e MySQL, esse post é o primeiro de uma série de 4 onde vou demonstrar como Incluir, Editar, Excluir e Listar dados, basicamente teremos sistema de cadastro de clientes.
No meu blog tem muito material sobre como montar CRUD com PHP e PDO, mas nunca escrevi um post partindo do front-end com HTML, CSS e JavaScript até chegar a gravação dos dados no MySQL com PHP.
Alguns pontos importantes:
- Quando falo em CSS me refiro ao framework Bootstrap, pois não sou especialista em front-end então nossas páginas serão estilizadas com ele.
- Não vamos usar nenhum tipo de plugin jQuery, toda a parte de validação e máscara no front-end será escrita com JavaScript puro.
- Não vamos trabalhar Orientados a Objeto, pois iria demorar mais para explicar os conceitos de O.O.
Outros posts que podem interessar:
Consulta – Sistema de Cadastro com PHP + PDO e MySQL
Edição – Sistema de Cadastro com PHP + PDO e MySQL
Exclusão – Sistema de Cadastro com PHP + PDO e MySQL
Editado em 30/10/2015: Atendendo a pedidos acrescentei nesse cadastro o campo “foto”, onde será possível fazer o upload de uma foto do cliente, não estou me atendo a detalhes de redimensionamento de imagem para não deixar o post muito longo.
Requisitos para essa série de posts:
- Baixar Bootstrap
- PHP 5.3 ou superior
- Extensão pdo_mysql habilitada no PHP
- MySQL 5.5 ou superior
Script do Banco de Dados
Nosso banco de dados “db_blog” terá apenas uma tabela “tab_clientes” com alguns campos básicos, observem que entre os campos temos “data_cadastro” esse campo vai conter a data e hora em que foi incluído o registro, depois temos “data_alteracao” nesse campo será gravado a data e a hora em que foi executado algum tipo de modificação nesse no registro.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
CREATE DATABASE IF NOT EXISTS db_blog; USE db_blog; CREATE TABLE tab_clientes( id integer auto_increment primary key, nome varchar(100), cpf varchar(20), email varchar(50), telefone varchar(20), celular varchar(20), data_nascimento date, status varchar(10), foto varchar(200), data_cadastro timestamp default CURRENT_TIMESTAMP, data_alteracao timestamp ); |
Formulário HTML para Inclusão de Dados
Abaixo temos o script “cadastro.php” com um formulário HTML que será submetido via POST, observem que nesse script temos apenas código HTML, tudo o que for ligado a folha de estilo fica na pasta “css“, a base de estilização fica no arquivo do “bootstrap.min.css” e estilizações customizadas ficam no arquivo “custom.css“.
Não existe nenhum tipo de evento JavaScript para validação ou máscara ligado diretamente nos inputs, esses eventos estão declarados no script “custom.js“.
Se os dados forem validados pela função JavaScript o formulário dessa página será enviado para o script PHP “action_cliente.php“, observem que temos um input hidden com name=”acao” onde passo o valor “incluir“. Isso indica para o script “action_cliente.php” que os dados recebidos deverão ser incluídos no banco de dados, nos outros posts dessa série serão passados valores “editar” e “excluir“.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Cadastro de Cliente</title> <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="css/custom.css"> </head> <body> <div class='container'> <fieldset> <legend><h1>Formulário - Cadastro de Cliente</h1></legend> <form action="action_cliente.php" method="post" id='form-contato' enctype='multipart/form-data'> <div class="row"> <label for="nome">Selecionar Foto</label> <div class="col-md-2"> <a href="#" class="thumbnail"> <img src="img/padrao.jpg" height="190" width="150" id="foto-cliente"> </a> </div> <input type="file" name="foto" id="foto" value="foto" > </div> <div class="form-group"> <label for="nome">Nome</label> <input type="text" class="form-control" id="nome" name="nome" placeholder="Infome o Nome"> <span class='msg-erro msg-nome'></span> </div> <div class="form-group"> <label for="email">E-mail</label> <input type="email" class="form-control" id="email" name="email" placeholder="Informe o E-mail"> <span class='msg-erro msg-email'></span> </div> <div class="form-group"> <label for="cpf">CPF</label> <input type="cpf" class="form-control" id="cpf" maxlength="14" name="cpf" placeholder="Informe o CPF"> <span class='msg-erro msg-cpf'></span> </div> <div class="form-group"> <label for="data_nascimento">Data de Nascimento</label> <input type="data_nascimento" class="form-control" id="data_nascimento" maxlength="10" name="data_nascimento"> <span class='msg-erro msg-data'></span> </div> <div class="form-group"> <label for="telefone">Telefone</label> <input type="telefone" class="form-control" id="telefone" maxlength="12" name="telefone" placeholder="Informe o Telefone"> <span class='msg-erro msg-telefone'></span> </div> <div class="form-group"> <label for="celular">Celular</label> <input type="celular" class="form-control" id="celular" maxlength="13" name="celular" placeholder="Informe o Celular"> <span class='msg-erro msg-celular'></span> </div> <div class="form-group"> <label for="status">Status</label> <select class="form-control" name="status" id="status"> <option value="">Selecione o Status</option> <option value="Ativo">Ativo</option> <option value="Inativo">Inativo</option> </select> <span class='msg-erro msg-status'></span> </div> <input type="hidden" name="acao" value="incluir"> <button type="submit" class="btn btn-primary" id='botao'> Gravar </button> </form> </fieldset> </div> <script type="text/javascript" src="js/custom.js"></script> </body> </html> |
Folha de estilo CSS customizada
No decorrer dos próximos posts essa folha de estilo “custom.css” poderá sofrer algumas alterações conforme forem surgindo necessidades nas outras páginas, a maior parte das regras de estilização como já citado acima vem do arquivo “bootstrap.min.css“.
1 2 3 |
fieldset{margin:1% auto;} .box-mensagem-crud{ margin-top: 10px;} .msg-erro{ color: red; } |
Script JavaScript com Validação, Máscaras e Load de Imagem
Abaixo segue o script “custom.js“, nesse arquivo temos a função que valida os dados “validaCadastro()” antes do evento submit, nesse ponto deixei todos os campos com preenchimento obrigatório, para mais detalhes sobre validação com JavaScript indico a leitura do post Validar Formulário usando JavaScript.
Essa validação tem como objetivo facilitar a vida do usuário, pois as mensagens são processadas no front-end mas ainda temos que construir uma validação completa no back-end com PHP.
Também temos a função que coloca uma máscara nos campos CPF, Data de Nascimento, Telefone e Celular, isso facilita para o usuário preencher de maneira correta esses campos.
Na função “loadFoto()” tem como objetivo exibir instantaneamente a imagem selecionada para upload dentro do elemento <img>, deixando o usuário mais seguro sobre a imagem que será feito o upload. Essa função recebe 2 parâmetros, sendo o primeiro o ID do input FILE e o segundo parâmetro é o ID do elemento <img> onde será exibida a foto.
Podemos observar que estou atribuindo os eventos JavaScript usando as chamadas “addEventListener” atualmente suportada pela maioria dos navegadores e para os I.E. mais antigos uso “attachEvent”, claro que usando jQuery seria necessário menos linhas nesse script, mas para efeitos didáticos vamos só de JavaScript mesmo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
/* Atribui ao evento submit do formulário a função de validação de dados */ var form = document.getElementById("form-contato"); if (form.addEventListener) { form.addEventListener("submit", validaCadastro); } else if (form.attachEvent) { form.attachEvent("onsubmit", validaCadastro); } /* Atribui ao evento keypress do input cpf a função para formatar o CPF */ var inputCPF = document.getElementById("cpf"); if (inputCPF.addEventListener) { inputCPF.addEventListener("keypress", function(){mascaraTexto(this, '###.###.###-##')}); } else if (inputCPF.attachEvent) { inputCPF.attachEvent("onkeypress", function(){mascaraTexto(this, '###.###.###-##')}); } /* Atribui ao evento keypress do input data de nascimento a função para formatar o data (dd/mm/yyyy) */ var inputDataNascimento = document.getElementById("data_nascimento"); if (inputDataNascimento.addEventListener) { inputDataNascimento.addEventListener("keypress", function(){mascaraTexto(this, '##/##/####')}); } else if (inputDataNascimento.attachEvent) { inputDataNascimento.attachEvent("onkeypress", function(){mascaraTexto(this, '##/##/####')}); } /* Atribui ao evento keypress do input telefone a função para formatar o Telefone (00 0000-0000) */ var inputTelefone = document.getElementById("telefone"); if (inputTelefone.addEventListener) { inputTelefone.addEventListener("keypress", function(){mascaraTexto(this, '## ####-####')}); } else if (inputTelefone.attachEvent) { inputTelefone.attachEvent("onkeypress", function(){mascaraTexto(this, '## ####-####')}); } /* Atribui ao evento keypress do input celular a função para formatar o Celular (00 00000-0000) */ var inputCelular = document.getElementById("celular"); if (inputCelular.addEventListener) { inputCelular.addEventListener("keypress", function(){mascaraTexto(this, '## #####-####')}); } else if (inputCelular.attachEvent) { inputCelular.attachEvent("onkeypress", function(){mascaraTexto(this, '## #####-####')}); } /* Atribui ao evento change do input FILE para upload da foto*/ var inputFile = document.getElementById("foto"); var foto_cliente = document.getElementById("foto-cliente"); if (inputFile.addEventListener) { inputFile.addEventListener("change", function(){loadFoto(this, foto_cliente)}); } else if (inputFile.attachEvent) { inputFile.attachEvent("onchange", function(){loadFoto(this, foto_cliente)}); } /* Função para validar os dados antes da submissão dos dados */ function validaCadastro(evt){ var nome = document.getElementById('nome'); var email = document.getElementById('email'); var cpf = document.getElementById('cpf'); var status = document.getElementById('status'); var data_nascimento = document.getElementById('data_nascimento'); var telefone = document.getElementById('telefone'); var celular = document.getElementById('celular'); var filtro = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i; var contErro = ; /* Validação do campo nome */ caixa_nome = document.querySelector('.msg-nome'); if(nome.value == ""){ caixa_nome.innerHTML = "Favor preencher o Nome"; caixa_nome.style.display = 'block'; contErro += 1; }else{ caixa_nome.style.display = 'none'; } /* Validação do campo email */ caixa_email = document.querySelector('.msg-email'); if(email.value == ""){ caixa_email.innerHTML = "Favor preencher o E-mail"; caixa_email.style.display = 'block'; contErro += 1; }else if(filtro.test(email.value)){ caixa_email.style.display = 'none'; }else{ caixa_email.innerHTML = "Formato do E-mail inválido"; caixa_email.style.display = 'block'; contErro += 1; } /* Validação do campo cpf */ caixa_data = document.querySelector('.msg-data'); if(data_nascimento.value == ""){ caixa_data.innerHTML = "Favor preencher a Data de Nascimento"; caixa_data.style.display = 'block'; contErro += 1; }else{ caixa_data.style.display = 'none'; } /* Validação do campo cpf */ caixa_cpf = document.querySelector('.msg-cpf'); if(cpf.value == ""){ caixa_cpf.innerHTML = "Favor preencher o CPF"; caixa_cpf.style.display = 'block'; contErro += 1; }else{ caixa_cpf.style.display = 'none'; } /* Validação do campo telefone */ caixa_telefone = document.querySelector('.msg-telefone'); if(telefone.value == ""){ caixa_telefone.innerHTML = "Favor preencher o Telefone"; caixa_telefone.style.display = 'block'; contErro += 1; }else{ caixa_telefone.style.display = 'none'; } /* Validação do campo celular */ caixa_celular = document.querySelector('.msg-celular'); if(celular.value == ""){ caixa_celular.innerHTML = "Favor preencher o Celular"; caixa_celular.style.display = 'block'; contErro += 1; }else{ caixa_celular.style.display = 'none'; } /* Validação do campo status */ caixa_status = document.querySelector('.msg-status'); if(status.value == ""){ caixa_status.innerHTML = "Favor preencher o Status"; caixa_status.style.display = 'block'; contErro += 1; }else{ caixa_status.style.display = 'none'; } if(contErro > ){ evt.preventDefault(); } } /* Função para formatar dados conforme parâmetro enviado, CPF, DATA, TELEFONE e CELULAR */ function mascaraTexto(t, mask){ var i = t.value.length; var saida = mask.substring(1,); var texto = mask.substring(i); if (texto.substring(,1) != saida){ t.value += texto.substring(,1); } } /* Função para exibir a imagem selecionada no input file na elemento <img> */ function loadFoto(file, img){ if (file.files && file.files[]) { var reader = new FileReader(); reader.onload = function (e) { img.src = e.target.result; } reader.readAsDataURL(file.files[]); } } |
Script PHP para Inclusão dos Dados
O script “action_cliente.php” possui praticamente toda a lógica CRUD do nosso sistema de cadastro, por padrão e uma pequena medida de segurança esse script só recebe dados vias POST, implementei toda a parte de validação dos dados recebidos sempre via POST e a lógica para inclusão de novos registros.
Nos outros posts de Edição e Exclusão dessa série também será utilizado esse script, para sistemas simples onde não uso frameworks utilizo essa técnica de agrupar no mesmo script a lógica de Inclusão, Edição e Exclusão de registros, basta passar um parâmetro “$_POST[‘acao’]” indicando qual será o tipo de processamento necessário.
Para conexão com o banco de dados MySQL utilizo a extensão PDO, o script de conexão “conexao.php” é o mesmo utilizado nesse post PDO – conexão seguindo padrão Singleton no PHP, basta alterar os dados de conexão conforme o ambiente de desenvolvimento do leitor.
Antes de executar o INSERT dos dados é processado o upload da imagem enviada pelo formulário, validando se é uma extensão de imagem (jpeg, jpg, png ou bmp) e posteriormente gravando na pasta “fotos”, no blog existe um post detalhando upload em PHP com detalhes e passo a passo para ajudar o leitor que deseja conhecer mais sobre esse assunto. Se não for enviado nenhum upload então é gravado no campo foto o valor “padrao.jpg”, na pasta fotos já existe essa imagem.
O INSERT dos dados também é executado de maneira parametrizada, já escrevi diversos posts no blog explicando os benefícios de se trabalhar parametrizado com PDO principalmente no quesito segurança, para o leitor que deseja obter mais conhecimentos sobre essa extensão indico o post Curso sobre PHP com PDO, onde publiquei vários vídeos sobre PDO.
Observem que no “miolo” do script fica o código PHP, assim é possível exibir mensagens de erro durante a validação dos dados e as mensagens de sucesso ou erro durante as operação no banco de dados, ao final da inclusão dos dados será emitido a mensagem de sucesso e após 3 segundos o usuário será redirecionado para página “index.php” (ainda não foi construída) que deverá conter a listagem dos clientes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sistema de Cadastro</title> <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="css/custom.css"> </head> <body> <div class='container box-mensagem-crud'> <?php require 'conexao.php'; // Atribui uma conexão PDO $conexao = conexao::getInstance(); // Recebe os dados enviados pela submissão $acao = (isset($_POST['acao'])) ? $_POST['acao'] : ''; $id = (isset($_POST['id'])) ? $_POST['id'] : ''; $nome = (isset($_POST['nome'])) ? $_POST['nome'] : ''; $cpf = (isset($_POST['cpf'])) ? str_replace(array('.','-'), '', $_POST['cpf']): ''; $email = (isset($_POST['email'])) ? $_POST['email'] : ''; $foto_atual = (isset($_POST['foto_atual'])) ? $_POST['foto_atual'] : ''; $data_nascimento = (isset($_POST['data_nascimento'])) ? $_POST['data_nascimento'] : ''; $telefone = (isset($_POST['telefone'])) ? str_replace(array('-', ' '), '', $_POST['telefone']) : ''; $celular = (isset($_POST['celular'])) ? str_replace(array('-', ' '), '', $_POST['celular']) : ''; $status = (isset($_POST['status'])) ? $_POST['status'] : ''; // Valida os dados recebidos $mensagem = ''; if ($acao == 'editar' && $id == ''): $mensagem .= '<li>ID do registros desconhecido.</li>'; endif; // Se for ação diferente de excluir valida os dados obrigatórios if ($acao != 'excluir'): if ($nome == '' || strlen($nome) < 3): $mensagem .= '<li>Favor preencher o Nome.</li>'; endif; if ($cpf == ''): $mensagem .= '<li>Favor preencher o CPF.</li>'; elseif(strlen($cpf) < 11): $mensagem .= '<li>Formato do CPF inválido.</li>'; endif; if ($email == ''): $mensagem .= '<li>Favor preencher o E-mail.</li>'; elseif(!filter_var($email, FILTER_VALIDATE_EMAIL)): $mensagem .= '<li>Formato do E-mail inválido.</li>'; endif; if ($data_nascimento == ''): $mensagem .= '<li>Favor preencher a Data de Nascimento.</li>'; else: $data = explode('/', $data_nascimento); if (!checkdate($data[1], $data[], $data[2])): $mensagem .= '<li>Formato da Data de Nascimento inválido.</li>'; endif; endif; if ($telefone == ''): $mensagem .= '<li>Favor preencher o Telefone.</li>'; elseif(strlen($telefone) < 10): $mensagem .= '<li>Formato do Telefone inválido.</li>'; endif; if ($celular == ''): $mensagem .= '<li>Favor preencher o Celular.</li>'; elseif(strlen($celular) < 11): $mensagem .= '<li>Formato do Celular inválido.</li>'; endif; if ($status == ''): $mensagem .= '<li>Favor preencher o Status.</li>'; endif; if ($mensagem != ''): $mensagem = '<ul>' . $mensagem . '</ul>'; echo "<div class='alert alert-danger' role='alert'>".$mensagem."</div> "; exit; endif; // Constrói a data no formato ANSI yyyy/mm/dd $data_temp = explode('/', $data_nascimento); $data_ansi = $data_temp[2] . '/' . $data_temp[1] . '/' . $data_temp[]; endif; // Verifica se foi solicitada a inclusão de dados if ($acao == 'incluir'): $nome_foto = 'padrao.jpg'; if(isset($_FILES['foto']) && $_FILES['foto']['size'] > ): $extensoes_aceitas = array('bmp' ,'png', 'svg', 'jpeg', 'jpg'); $extensao = strtolower(end(explode('.', $_FILES['foto']['name']))); // Validamos se a extensão do arquivo é aceita if (array_search($extensao, $extensoes_aceitas) === false): echo "<h1>Extensão Inválida!</h1>"; exit; endif; // Verifica se o upload foi enviado via POST if(is_uploaded_file($_FILES['foto']['tmp_name'])): // Verifica se o diretório de destino existe, senão existir cria o diretório if(!file_exists("fotos")): mkdir("fotos"); endif; // Monta o caminho de destino com o nome do arquivo $nome_foto = date('dmY') . '_' . $_FILES['foto']['name']; // Essa função move_uploaded_file() copia e verifica se o arquivo enviado foi copiado com sucesso para o destino if (!move_uploaded_file($_FILES['foto']['tmp_name'], 'fotos/'.$nome_foto)): echo "Houve um erro ao gravar arquivo na pasta de destino!"; endif; endif; endif; $sql = 'INSERT INTO tab_clientes (nome, email, cpf, data_nascimento, telefone, celular, status, foto) VALUES(:nome, :email, :cpf, :data_nascimento, :telefone, :celular, :status, :foto)'; $stm = $conexao->prepare($sql); $stm->bindValue(':nome', $nome); $stm->bindValue(':email', $email); $stm->bindValue(':cpf', $cpf); $stm->bindValue(':data_nascimento', $data_ansi); $stm->bindValue(':telefone', $telefone); $stm->bindValue(':celular', $celular); $stm->bindValue(':status', $status); $stm->bindValue(':foto', $nome_foto); $retorno = $stm->execute(); if ($retorno): echo "<div class='alert alert-success' role='alert'>Registro inserido com sucesso, aguarde você está sendo redirecionado ...</div> "; else: echo "<div class='alert alert-danger' role='alert'>Erro ao inserir registro!</div> "; endif; echo "<meta http-equiv=refresh content='3;URL=index.php'>"; endif; ?> </div> </body> </html> |
Resultado Final
Abaixo temos o exemplo caso o usuário clique em “gravar” sem preencher os campos:
Agora o preenchimento correto com as devidas máscaras nos campos:
E por último a mensagem caso o cadastro seja executado com sucesso:
Bom pessoal, nesse post demonstrei como podemos construir um formulário de inclusão com validação de dados para serem gravados em um banco de dados MySQL com PHP usando a biblioteca PDO. Observem que podem ser necessários diversos campos conforme a necessidade, mas o fluxo de informação serás o mesmo, as validações podem ser mais complexas como validações de CPF, número de telefone e etc, a partir desse ponto o leitor adapta a sua necessidade.
Nos dias atuais está se tornando normal o uso de frameworks PHP para construir esse tipo de aplicação, eu acho interessante essa prática pois traz ganho de tempo e redução de custos nos projetos, mas vejo iniciantes na área de desenvolvimento WEB partindo para o uso desses frameworks sem nem mesmo saber construir o formulário desse post.
Fica a dica, primeiro aprenda o simples para depois evoluir para o complexo.
Link para Download do projeto final com INCLUSÃO, EDIÇÃO, EXCLUSÃO E CONSULTA. (8152 downloads)
Até a próxima pessoal …