Olha eu aqui novamente minha gente!
Hoje vamos dar continuidade a nossa sequëncia de tutoriais que te ensina a criar um sistema de logins usando classes no PHP.
Na parte de hoje, a Parte 4, vamos fazer inúmeros ajustes e correções na classe além implementar a funcionalidade “Lembrar minha senha”.
Lembrando a minha senha
A funcionalidade “Lembrar minha senha” funciona basicamente da seguinte forma: após o usuário se logar (informando que quer que sua senha seja lembrada) são criados cookies na máquina dele salvando o usuário e a senha do mesmo… Depois, quando o usuário voltar no site e não estiver logado o sistema busca esses cookies e tenta validar os dados, se os dados validarem ele é logado automaticamente no sistema e os cookies são reescritos (para durarem mais tempo).
Ajustes e correções
Estou desde ontem revisando a classe e fazendo algumas pequenas correções… Não vou listar todas aqui pois acho mais fácil vocês pegarem o PHPs final e darem uma olhada… Prefiro listar aqui rapidamente o que foi preciso fazer e vocês vão dando uma olhada no código:
- Aumentar as informações nos blocos de comentário (seguindo o padrão do PHPDoc);
- Remover o prefixo “__” dos métodos protegidos (agora todos os métodos são públicos);
- Documentar em qual versão a propriedade ou método apareceu na classe;
- Ajustar os métodos usuarioLogado() e logaUsuario() para atender ao sistema de “Lembrar minha senha”;
- Criar a propriedade filtraDados que permite o uso do mysql_real_escape_string() e evita SQL Injection;
- Criar a propriedade caseSensitive que diferencia “casa” de “CaSa” ou “CASA”.
- Criar a propriedade cookiePath que será usada sempre que um cookie for criado ou deletado.
Novas Propriedades
Para a nossa nova funcionalidade precisamos criar uma nova propriedade na nossa classe:
/**
* Quantidade (em dias) que o sistema lembrará os dados do usuário ("Lembrar minha senha")
*
* Usado apenas quando o terceiro parâmetro do método Usuario::logaUsuario() for true
* Os dados salvos serão encriptados usando base64
*
* @var integer
* @since v1.1
*/
var $lembrarTempo = 7;
Se vocês lerem o comentário vão perceber que um terceiro parâmetro foi adicionado ao método logaUsuario()… É esse terceiro parâmetro que define se os dados serão lembrados pelo o sistema.
Novo Método – lembrarDados()
Vamos criar agora o método lembrarDados() que irá salvar os dados do usuário, criptografados, em cookies:
/**
* Salva os dados do usuário em cookies ("Lembrar minha senha")
*
* @access public
* @since v1.1
*
* @param string $usuario O usuário que será lembrado
* @param string $senha A senha do usuário
* @return void
*/
function lembrarDados($usuario, $senha) {
// Continuaremos aqui...
}
Primeiro nós vamos calcular o UNIX Timestamp que será a data exata de quando os cookies irão expirar:
// Calcula o timestamp final para os cookies expirarem
$tempo = strtotime("+{$this->lembrarTempo} day", time());
Agora nós iremos encriptar os dados do usuário usando base64 e adicionar um caractere no início da string criptografada para impedir que ela seja decriptografada pelo usuário (caso ele encontre o valor do cookie):
// Encripta os dados do usuário usando base64 // O rand(1, 9) cria um digito no início da string que impede a descriptografia $usuario = rand(1, 9) . base64_encode($usuario); $senha = rand(1, 9) . base64_encode($senha);
Agora é só criar os dois cookies e o método está pronto:
// Cria um cookie com o usuário setcookie($this->prefixoChaves . 'lu', $usuario, $tempo, $this->cookiePath); // Cria um cookie com a senha setcookie($this->prefixoChaves . 'ls', $senha, $tempo, $this->cookiePath);
Nosso método que salva os dados em cookies está pronto… Esse método será usado pelo método logaUsuario() após todos os dados serem salvos na sessão.
Agora nós vamos precisar criar um método que verifica os dados (usuario e senha) salvos nos cookies:
Novo Método – verificaDadosLembrados()
Esse método é muito importante pois ele verificará os dados salvos nos cookies tentando logar o usuário! Esse método só será chamado quando o usuário tentar acessar uma página protegida e não estiver logado… O proprio método usuarioLogado() já fará isso!
Vamos começar:
/**
* Verifica os dados do cookie (caso eles existam)
*
* @access public
* @since v1.1
* @uses Usuario::logaUsuario()
*
* @return boolean Os dados são validos?
*/
function verificaDadosLembrados() {
// Continuaremos aqui...
}
Primeiro nós precisamos verificar se os cookies existem, caso eles não existam os dados não foram encontrados e, obviamente, são “inválidos”.
// Os cookies de "Lembrar minha senha" existem?
if (isset($_COOKIE[$this->prefixoChaves . 'lu']) AND isset($_COOKIE[$this->prefixoChaves . 'ls'])) {
// Continuaremos aqui...
}
// Não há nenhum cookie, dados inválidos
return false;
O próximo passo é que faz toda a mágica do método: ele remove o caractere adicionado no início da string criptogafada, descriptografa a string e verifica se os dados são válidos tentando logar o usuário:
// Pega os valores salvos nos cookies removendo o digito e desencriptando $usuario = base64_decode(substr($_COOKIE[$this->prefixoChaves . 'lu'], 1)); $senha = base64_decode(substr($_COOKIE[$this->prefixoChaves . 'ls'], 1)); // Tenta logar o usuário com os dados encontrados nos cookies return $this->logaUsuario($usuario, $senha, true);
Se o usuário for logado com sucesso o método logaUsuario() retornará true para o método verificaDadosLembrados(), que por sua vez também retornará true para o método usuarioLogado() e tudo vai funcionar perfeitamente!
Antes que você desista do tutorial agora mesmo por que acha que tá muito complicado, isso é o “normal” da Orientação a Objetos e você vai adorar.
Nossa nova funcionalidade está quase pronta.. Só falta uma coisinha: um método que limpe os dados lembrados do Cookie para quando o usuário fizer logout… Isso é opcional, vai depender do seu sistema, mas já vamos criar o método e você decide se limpa ou não os dados após o logout (automaticamente, claro).
Novo Método – limpaDadosLembrados()
Para deletar um cookie você deve definir o seu valor como nulo ou falso e definir a sua data de expiração no passado… O método fica asssim:
/**
* Limpa os dados lembrados dos cookies ("Lembrar minha senha")
*
* @access public
* @since v1.1
*
* @return void
*/
function limpaDadosLembrados() {
// Deleta o cookie com o usuário
if (isset($_COOKIE[$this->prefixoChaves . 'lu'])) {
setcookie($this->prefixoChaves . 'lu', false, (time() - 3600), $this->cookiePath);
unset($_COOKIE[$this->prefixoChaves . 'lu']);
}
// Deleta o cookie com a senha
if (isset($_COOKIE[$this->prefixoChaves . 'ls'])) {
setcookie($this->prefixoChaves . 'ls', false, (time() - 3600), $this->cookiePath);
unset($_COOKIE[$this->prefixoChaves . 'ls']);
}
}
Nossa nova funcionalidade está devidamente implementada!
Pra quem quiser, o download do script completo:
- Parte 1 » PHP, RAR ou Pastie
- Parte 2 » PHP, RAR ou Pastie (Inclui a parte 1)
- Parte 3 » PHP, RAR ou Pastie (Inclui as partes 1 e 2)
- Parte 4 » PHP, RAR ou Pastie (Inclui as partes 1, 2 e 3)
Como usar a nova funcionalidade
Agora vamos fazer alguns mínimos ajustes aos códigos mostados no Sistema de logins com classe no PHP – Como usar?.
Validar o login
Agora nós não precisamos mais limpar os dados, a classe já faz isso.. Mas precisamos verificar se o usuário marcou o checkbox “Lembrar minha senha”:
<?php
// Inclui o arquivo com a classe de login
require_once("includes/classes/usuarios.class.php");
// Instancia a classe
$userClass = new Usuario();
// Pega os dados vindos do formulário
$usuario = $_POST['usuario'];
$senha = $_POST['senha'];
$lembrar = (isset($_POST['lembrar']) AND !empty($_POST['lembrar']));
// Tenta logar o usuário com os dados
if ( $userClass->logaUsuario( $usuario, $senha, $lembrar ) ) {
// Usuário logado com sucesso, redireciona ele para a página restrita
header("Location: pagina_restrita.php");
exit;
} else {
// Não foi possível logar o usuário, exibe a mensagem de erro
echo "<strong>Erro: </strong>" . $userClass->erro;
}
?>
Página de logout
Como eu disse anteriormente, agora você tem a opção de limpar os cookies do “Lembrar minha senha” quando seu usuário faz logout… Por padrão os cookies são limpos pois, se o usuário clicou em “Sair”, ele não quer aparecer logado da próxima vez que abrir o site… Concordam?
Mas se você quiser que os cookies continuem lá, você precisa mudar a sua página de logout e adicionar o parâmetro false no método logout(), assim:
<?php
// Inclui o arquivo com a classe de login
require_once("includes/classes/usuarios.class.php");
// Instancia a classe
$userClass = new Usuario();
// Usuário fez logout com sucesso?
if ( $userClass->logout( false ) ) {
// Redireciona pra tela de login
header("Location: login.php");
exit;
}
?>
É só isso!
Não deixem de fazer o download da classe (PHP, RAR ou PasteNinja) e nem de dar uma olhada nas outras partes:
- Criando um sistema de logins com classe no PHP – Parte 1
- Criando um sistema de logins com classe no PHP – Parte 2
- Criando um sistema de logins com classe no PHP – Parte 3
Abraços e até a próxima!
Você também vai gostar de ler:
- Criando um sistema de logins com classe no PHP – Parte 1
- Criando um sistema de logins com classe no PHP – Parte 3
- Criando um sistema de logins com classe no PHP – Parte 2
- Sistema de logins com classe no PHP – Como usar?
- Criando um sistema de destaques – Parte 2
Postado em Artigos, MySQL, PHP, Tutoriais
Com as tags Classes, Código, Cookies, Funcionalidade, Login, MySQL, Orientação a Objetos, PHP, PHPDoc, Script, Senha, Sessão, Sistema, SQL Injection, Tutoriais, Tutorial
Escrito por Thiago Belem
Gostou desse artigo?
Não se esqueça de assinar o RSS e divulgue-o para o mundo:

Ola Thiago
Ótimo script man. Parabéns.
Uma dúvida. Há algum motivo em especial, talvez de segurança, para que o script consulte duas vezes a tabela?
Pensando em sistemas com grande quantidade de acesso, seria ideal consultar somente uma vez ja pegando todos os dados necessarios do usuario.
Um grande abraco
@Gabriel
Motivo especial propriamente dito não há… Mas eu – pessoalmente – prefiro fazer esse tipo de rotina… Verificar se o usuário existe antes de pegar os seus dados.. Pois assim eu evito [teoricamente] uma possibilidade de SQL Injection na consulta que pega os dados do visitante.
Cara, eu uso o NetBeans e digo, essa documentação PHPDoc é muito boa!
Quando digita-se o “$this->” já aparece todos os métodos e variáveis da classe!
Facilita muito!
Obrigado pelo tutorial!
Thiago, tudo em paz?
Cara a não está iniciando a sessão, o que poderia ser?
“Warning: session_start() [function.session-start]: Cannot send session cache limiter – headers already sent ”
Abraço
@Lucas
Resolvendo o problema de “headers already sent”
SHOW DE BOLA PARABENS!
Fala Thiago,
Eu denovo, creioooo que funciona rsrsrs,muito show este teu script, cara uma coisinha, ele recorda a senha do cookie somente com a sessao aberta, depois nao lembra mais, sera por que?
Bixo podia implementar pra nos ai uma funcao esqueçi minha senha, aquela tradicional enviada por email…
Tb podia fazer um artigo de como criar uma pagina de area de membros tipo dos fouruns hehehehe.
Forte abraco
Ricardo
Mas aí é q tá, aparentemente, tá tudo certo.
O banco de dados e a tabela estão corretos, o usuário eu cadastrei no banco de dados, transformei a senha em md5 e salvei lá. E não vai de jeito nenhum. Até fiz algumas alterações, mas não adiantaram muita coisa. Também fiquei na dúvida em relação ao campo senha duas vezes, que o Joabe falou aí em baixo. Outra coisa, em canto algum tem conexão com o banco de dados. Como que ele consegue pegar informações sem se conectar ao banco? não entendi…
@Michael
1 – Se a sua senha está sendo salva em MD5 você precisa fazer modificações no método codificaSenha() da classe Usuario para ela retornar a senha passada ($senha) em MD5.
2 – O campo senha não precisava estar lá duas vezes, vou fazer a correção.
Thiago, nesses campos do array ai no class, o campo senha é apresentado duas vezes mesmo?
@Joabe
O campo senha não precisava estar lá duas vezes, vou fazer a correção.
Não deu certo, apareceu:
Erro: Usuário inválido
@Michael
Então… o erro já diz o que está errado.
Fala Thiago,
Show de bola, funfa tudo somente a senha nao lembra, que poderia ser?
abs
ricardo
@Ricardo
Nos testes que fiz localmente funcionou tranquilamente… Tente configurar a classe com mais atenção e verifique os valores salvos nos cookies.
Cara, vc podia dar um help postando como fazer pra ele conversar com o banco?
@Amauri
É só fazer uma conexão MySQL normal.
Cara existe a possibilidade de você publicar um exemplo pratico de como ultilizar o class no formulario de login com o checkbox de lembrar senha?
@Joabe
Existe um artigo aqui no blog sobre isso… Leia-o e depois leia o “Como Usar” dessa parte 4 que você vai conseguir
@Thiago,
outro problema que estou tendo é quando eu marco o campo de “lembrar dados”.
Eu fecho o browser, e quando retorno ele dá esse erro:
Warning: Cannot modify header information - headers already sent by (output started at ...) in D:\www2\meusite\_incs\classes\usuarios.class.php on line 432
@Gabriel
Verifique o UTF-8* (sem BOM)
Thiago, ficou bem bacana essa nova versão, tá bem organizada e talz.. :p
Mas eu ainda estou tendo problemas com os coockies, igual a versão anterior.
Se eu setar var $cookie = false;, a minha validação if ($userClass->usuarioLogado()) {…}, funciona legal, mas se eu setar var $cookie = true;, essa validação deixa de funcionar…
O que será que está errado?
@Gabriel
Me parece um erro com o seu servidor, já tentou em outra hospedagem?
Thiago, muito show parabéns, vou utilizar esse script como base para um projeto que estou fazendo..
Thiago, você indica alguma leitura para PHP OO e PHP Doc?
abraços!
Muito Show Thiago!! Eu sou novo nesta area (PHP), mas to aprendendo bastante contigo!!! Vlw por compartilhar os seus conhecimentos =D
Agora fiquei com mais vontade de usar esse sistema de login. Simplemente completo! Ae cara gostei do CAPTCHA.
Olá Thiago!! Gostei do tutorial parabéns! Estou com uma dúvida…
Essa maneira que você de fez o sistema de login entitulado “[...] ensina a criar um sistema de logins usando classes no PHP” seria programação orientada a objetos ou é programação estruturada dentro de uma definição de classe?
Abraços…
@Fernando
Sim, é programação orientada a objeto sim.