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 Postado em Artigos, MySQL, PHP, Tutoriais Com as tags Ajuste, API, Busca, Classe, Classes, Código, Cookie, Cookies, Criptografia, Download, empty, Formulário, Funcionalidade, Header, Login, MySQL, Orientação a Objetos, PHP, PHPDoc, PHPS, Scripts, Senha, Sessão, Sistema, SQL, SQL Injection, Tutoriais, Tutorial Escrito por Thiago Belem Não se esqueça de assinar o RSS e divulgue-o para o mundo:Você também vai gostar de ler:
Gostou desse artigo?

Sim, testei em todos, mas descobri o erro agora.
Na sua classe, você utiliza o campo “usuario” da tabela, e no meu caso o campo era “login”. Então, tive que alterar manualmente em todos os lugares que faziam referência a este campo, mas acabei não retirando na parte que faz a validação do cookie no método usuarioLogado().
Depois que vi isso, funcionou direitinho.. xDD
Mas valeu aí a ajuda…
@Gabriel
Existe uma parte na configuração da classe que você pode definir em qual campo está o “usuário”… É uma parte onde tem:
<code>’usuario’ => ‘usuario’</code>
Aí é só você mudar para:
<code>’usuario’ => ‘login’</code>
E tudo deve funcionar.
É mesmo, valeu Thiago, não me atentei a isso no começo daí tive que modificar tudo na mão, aí acabei me atrabalhando um pouco.. mas valeu.. tá funcionando direitinho agora…
Mas uma coisa que eu reparei: quando passa um certo tempo, a sessão acaba, e o usuário tem que se logar dinovo. É a classe que faz isso? Pq antes de ajeitar essa parada dos Cookies… a sessão não esgotava de jeito nenhum…
Ness caso, como que eu faria pra voltar pra página que estava antes da sessão acabar? Salvando em uma sessão também?
Ficaria massa implementar isso na classe também..
Daew Thiago,
Tava tentando resolver aquele problema do cookie de novo mas o erro continua. Já testei o script tanto local (server Apache), quanto no Locaweb.
O lance ainda é o mesmo.
Se eu setar <em><b>var</b> $cookie = false</em> na classe, eu consigo validar corretamente o usuário, mas o cookie não é criado e quando o browser é reaberto, as informações são perdidas.
Mas se eu setar <em><b>var</b> $cookie = true</em>, quando eu faço a verificação para se o usuário está logado ou não, ele informa que o cookie ou a sessão não foram definidas:
<code>Notice: Undefined index: user_auth-usuario</code>
Onde poderia estar o erro?
@Gabriel
De onde veio esse <strong>user_auth</strong>? Você definiu no <strong>$prefixoChaves</strong>?
Isso mesmo Thiago,
está assim:
<code>
var $prefixoChaves = ‘user_auth-’;
</code>
@Gabriel
Muito estranho… Poderia me dizer a versão do seu PHP e do seu Apache? Já testou em outros navegadores?
Thiago,
O sistema está ok, agora só estou com uma duvida, como fasso para quando o usuário se logar, e entrar novamente na pagina de login, ela ja redirecione automaticamente para a pagina restrita.
Atenciosamente,
Hugo Fabricio
@Hugo
É uma questão de lógica.. É só você verificar, na página de login, se o usuário já está logado e fazer o redirecionamento pra página restrita.
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:www2meusite_incsclassesusuarios.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.