Você está na página 1de 15

Criando um sistema de logins com classe

no PHP Parte 1
Fala pessoal! Tudo na paz? Que tal um super tutorial de ano novo?!
Esse o primeiro
artigo do ano, as 00:01 de 1 de Janeiro! Vamos comear o ano bem!
Hoje vamos comear um tutorial que ser divido em vrias partes Nele vamos aprender
a fazer um sistema de logins decente, usando classes no PHP Meu objetivo aqui que
voc aprenda duas coisas: como fazer um sistema de login desde o comeo e aprenda um
pouco mais sobre o uso de classes.
O sistema de login usar banco de dados MySQL e ter suporte a encriptao de
senha(MD5, SHA1 e etc) Totalmente customizvel e ser fcil alter-lo caso voc
precise de alguma coisa especial. Tambm teremos um suporte a opo lembrar minha
senha, onde o usurio permanecer logado caso volte no site algum tempo depois, outra
funcionalidade customizvel e opcional.
Outro detalhe importante sobre o sistema que ele ir funcionar nas verses 4 e 5 do PHP
e do MySQL, ento, se a sua hospedagem uma vergonha, no se preocupe!

A Tabela de Usurios
Se voc j tem uma tabela de usurios pode pular essa parte Se no, vamos criar a
seguinte tabela no banco de dados do seu site:

Tabela de Usurios

Para criar essa tabela, voc poder usar o seguinte cdigo SQL:
1 CREATE TABLE `usuarios` (
2
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
3
`nome` VARCHAR(150) NOT NULL ,
4
`usuario` VARCHAR(100) NOT NULL ,
5
`senha` VARCHAR(40) NOT NULL ,
6
PRIMARY KEY (`id`) )

ENGINE = MyISAM;

A classe Usuario
Vamos ao que interessa!
Antes de tudo, precisamos criar o nosso arquivo, vamos seguir algumas boas pticas de
programao e vamos dar o nome de usuario.class.php. Criado o arquivo vazio, vamos
comear a construir nossa classe:
1
2

<?php
class Usuario {

3
4
5

}
?>

Agora vamos comear a inserir algumas propriedades (variveis) que sero usadas pela
classe ao longo do projeto
04 /**
05 * Nome do banco de dados onde est a tabela de usurios
06
*/
07
var $bancoDeDados = 'meu_site';
08
09
/**
10
* Nome da tabela de usurios
11
*/
12
var $tabelaUsuarios = 'usuarios';
13
14 /**
15 * Nomes dos campos onde ficam o usurio e a senha de cada usurio
16
* Formato: tipo => nome_do_campo
17
*/
18
var $campos = array(
19
'usuario' => 'usuario',
20
21

'senha' => 'senha'


);

So com essas propriedades da classe que voc vai poder customizar a classe para ela
funcionar no seu site.. Cada uma esta devidamente comentada e explicada, s alterar da
forma que voc necessitar.
Agora vamos definir o primeiro mtodo da nossa classe:
23 /**
24 * Usa algum tipo de encriptao para codificar uma senha
25 *
26 * Mtodo protegido: S pode ser acessado por dentro da classe
27 *

28 * @param string $senha - A senha que ser codificada


29
* @return string - A senha j codificada
30
*/
31 function __codificaSenha($senha) {
32
// Altere aqui caso voc use, por exemplo, o MD5:
33
// return md5($senha);
34
return $senha;
35
}

Esse mtodo cuidar da encriptao da senha (caso ela exista, claro) Se o seu sistema
no usar nenhum tipo de criptografia, pode deixar esse mtodo do jeito que est, mas caso
voc use, por exemplo, o SHA1, voc precisa mudar ali na linha 34 e colocar, por exemplo:
34

return sha1($senha);

Caso voc use outro tipo de encriptao, voc vai precisar modificar esse mtodo O
importante voc receber a senha pura/plana como parmetro ($senha) e retornar a
senha encriptada.
Agora vamos criar o segundo mtodo da classe e o ltimo mtodo dessa parte do tutorial:
37
38
39
40
41
42
43
44

/**
* Valida se um usurio existe
*
* @param string $usuario - O usurio que ser validado
* @param string $senha - A senha que ser validada
* @return boolean - Se o usurio existe ou no
*/
function validaUsuario($usuario, $senha) {

45

$senha = $this->__codificaSenha($senha);

46
47
48
49
50
51
52
53
54

// Procura por usurios com o mesmo usurio e senha


$sql = "SELECT COUNT(*)
FROM `{$this->bancoDeDados}`.`{$this->tabelaUsuarios}`
WHERE
`{$this->campos['usuario']}` = '{$usuario}'
AND
`{$this->campos['senha']}` = '{$senha}'";
$query = mysql_query($sql);

55

if ($query) {

56
57
58
59
60
61
62
63
64

$total = mysql_result($query, 0);


} else {
// A consulta foi mal sucedida, retorna false
return false;
}
// Se houver apenas um usurio, retorna true
return ($total == 1) ? true : false;
}

Esse mtodo, como o comentrio explica, cuidar de validar se um usurio existe,


procurando o par $usuario + $senha no banco de dados Ele s retornar verdadeiro
(true) quando apenas um registro for encontrado.
Se voc reparar logo ali no comeo do mtodo, na linha 45, ele usa o
mtodo__codificaSenha() que ir encriptar (ou no) a senha Simples n?
Ento isso gente Por hoje vamos ficar por aqui. Em breve postarei a Parte 2, onde
iremos criar os mtodos que deixam um usurio logado (usando sesses E cookies) E
antes que algum reclame, essa classe ainda no est usvel Ela apenas a 1 parte
de uma classe que vamos fazendo ao longo dessa sequencia de tutoriais.
Pra quem quiser, o download do script completo da Parte 1: PHP ou RAR.
No deixem de dar uma olhada nas outras partes:

Criando um sistema de logins com classe no PHP Parte 2


Vamos que vamos! Essa a segunda parte do nosso tutorial Criando um sistema de
logins com classe no PHP, na Parte 1 comeamos a criar a classe e definimos um
mtodo que validava se o usurio existe, agora vamos continuar a classe e criar um
mtodo que deixar o usurio logado no sistema usando sesso e cookies.
Primeiro, vamos adicionar algumas novas propriedades que iremos usar nessa parte
do tutorial:
32 /**
33

* Nomes dos campos que sero pegos da tabela de usuarios e salvos


na sesso,

34

* caso o valor seja false nenhum dado ser consultado

35

* @var mixed

36
37

*/
var $dados = array('id', 'nome');

38
39

/**

40

* Inicia a sesso se necessrio?

41

* @var boolean

42
43
44

*/
var $iniciaSessao = true;

45

/**

46

* Prefixo das chaves usadas na sesso

47

* @var string

48
49

*/
var $prefixoChaves = 'usuario_';

50
51

/**

52

* Usa um cookie para melhorar a segurana?

53

* @var boolean

54

*/

55

var $cookie = true;

56
57

/**

58

* Armazena as mensagens de erro

59

* @var string

60

*/

61

var $erro = '';

Todas as propriedades esto comentadas, bom vocs irem se acostumando com


essa necessidade dos comentrios organizados e padronizados, isso vai se tornar um
must have num futuro no muito distante Mas isso assunto pra um outro tutorial.
Reparem que criamos uma propriedade $erro, ela ser usada para armazenar as
mensagens de erro quando algo der errado
Agora vamos comear a criar o novo, gigantesco e magnfico mtodo que ir salvar o
usurio no sistema, mantendo-o logado:
106 /**
107

* Loga um usurio no sistema salvando seus dados na sesso

108

109

* @param string $usuario - O usurio que ser logado

110

* @param string $senha - A senha do usurio

111

* @return boolean - Se o usurio foi logado ou no

112
113

*/
function logaUsuario($usuario, $senha) {

114
115

Primeiro de tudo, precisamos validar os dados passados por parmetro:


114

// Verifica se um usurio vlido

115

if ($this->validaUsuario($usuario, $senha)) {

116
117

// Continuaremos aqui...

118
119

} else {

120

$this->erro = 'Usurio invlido';

121

return false;

122

J sabemos se o usurio foi validado, agora ns vamos verificar se necessrio (e


possvel) iniciar a sesso:
117

// Inicia a sesso?

118

if ($this->iniciaSessao AND !isset($_SESSION)) {

119
120

session_start();
}

O prximo passo atrazer (ou no) os dados do banco de dados para a sesso:
122

// Traz dados da tabela?

123

if ($this->dados != false) {

124

// Adiciona o campo do usurio na lista de dados

125

if (!in_array($this->campos['usuario'], $this->dados)) {

126
127

$this->dados[] = 'usuario';
}

128
129

// Monta o formato SQL da lista de campos

130

$dados = '`' . join('`, `', array_unique($this->dados)) . '`';

131
132

// Consulta os dados

133

$sql = "SELECT {$dados}

134

FROM `{$this->bancoDeDados}`.`{$this->tabelaUsuarios}`

135

WHERE `{$this->campos['usuario']}` = '{$usuario}'";

136

$query = mysql_query($sql);

137
138

// Se a consulta falhou

139

if (!$query) {

140

// A consulta foi mal sucedida, retorna false

141

$this->erro = 'A consulta dos dados invlida';

142
143

return false;
} else {

144

// Traz os dados encontrados para um array

145

$dados = mysql_fetch_assoc($query);

146

// Limpa a consulta da memria

147

mysql_free_result($query);

148
149

// Passa os dados para a sesso

150

foreach ($dados AS $chave=>$valor) {

151

$_SESSION[$this->prefixoChaves . $chave] = $valor;

152
153

}
}

154

Da linha 124 at a linha 135 n montamos a consulta que ser usada para fazer a
busca no banco de dados, depois disso ns a executamos e, caso a consulta tenha
sido bem sucedida, salvamos os dados na sesso.

Repare que para isso usamos $_SESSION[$this->prefixoChaves . $chave], isso ir


criar valores na sesso usando o prefixo (definido na propriedade $this>prefixoChaves no comeo da classe) seguido o nome do campo que estava no
banco de dados Ento, segundo o nosso exemplo: se estamos pegando o
campo id e o campo nome l da tabela, as chaves criadas na sesso
sero usuario_id e usuario_nome Legal no?
Mas calma que ainda no acabou!
Precisamos ainda definir um valor na sesso e criar (caso seja possvel) o cookie que
ir ajudar na identificao (e segurana) do usurio:
156

// Usurio logado com sucesso

157

$_SESSION[$this->prefixoChaves . 'logado'] = true;

158
159

// Define um cookie para maior segurana?

160 if ($this->cookie) {
161

// Monta uma cookie com informaes gerais sobre o usurio:


usuario, ip e navegador

16
$valor = join('#', array($usuario, $_SERVER['REMOTE_ADDR'],
2 $_SERVER['HTTP_USER_AGENT']));
163
164

// Encripta o valor do cookie

165

$valor = sha1($valor);

166
167

setcookie($this->prefixoChaves . 'token', $valor, 0, '/');

168

169
170

// Fim da verificao, retorna true

171

return true;

A parte do cookie pode parecer complexa mais no Criamos um cookie chamado


usuario_token contendo informaes adicionais do usurio: usurio, IP e informaes
do navegador Essas informaes sero usadas para proteger o login do usurio
caso outros usurios tentem roubar o ID de sesso ou forjar IDs falsos.
Agora sim o mtodo terminou!

Resumindo tudo:
Depois de logado, seguindo o nosso exemplo, sero criados os seguintes valores na
sesso:

usuario_id Contendo o ID do usurio (vindo da coluna `id` da tabela);

usuario_nome Contendo o nome do usurio (vindo da coluna `nome` da


tabela);

usuario_usuario Contendo o usuario do usurio (?!) (vindo da coluna


`usuario` da tabela);

usuario_logado (true) Contendo um booleano (sempre true) informando que


o usurio est logado, apenas para facilitar as coisas no futuro.

E ser criado um cookie (com as informaes do visitante), criptografado, que ir durar


apenas enquanto o visitante estiver com o navegador aberto:

usuario_token Exemplo de valor:


a9f0a6edefc3d61895d5b8054ed6b8a175bc2851

Por hoje s pessoal Na Parte 3 do tutorial iremos criar o mtodo que ir verificar o
usurio est logado (que vocs podero usar nas suas pginas protegidas) e o mtodo
para logout, mas isso no tudo Ainda vai faltar o lembrar minha senha e outras
implementaes Talvez um sisteminha de permisses, quem sabe?
Pra quem quiser, o download do script completo:

Parte 1 PHP ou RAR

Parte 2 PHP ou RAR (J inclui os cdigos da Parte 1)

No deixem de dar uma olhada nas outras partes:


Criando um sistema de logins com classe no PHP Parte 3
Opa opa opa! Vamos continuar hoje com a terceira parte do nosso tutorial de Criando
um sistema de logins com classe no PHP
J passamos vitoriosos pela Parte 1 e Parte 2 e hoje vamos fazer o mtodo que
usaremos para verificar se um usurio est logado e o mtodo que usaremos para
deslogar o usurio A boa notcia que depois da aula de hoje a classe estar pronta

para vocs usarem em vossos sites, lembrando sempre que o importante aqui que
vocs aprendam como fazer e no apenas copiem o cdigo e usem.
Vamos comear fazendo uma correo que o Leo Baiano sugeriu no
mtodovalidaUsuario() criado na Parte 1 A mudana vai acontecer entre a linha 87
e a linha 96:
097 // Procura por usurios com o mesmo usurio e senha
098 $sql = "SELECT COUNT(*)
099

FROM `{$this->bancoDeDados}`.`{$this->tabelaUsuarios}`

100

WHERE

101

`{$this->campos['usuario']}` = '{$usuario}'

102

AND

103

`{$this->campos['senha']}` = '{$senha}'";

104 $query = mysql_query($sql);


105
106

if ($query) {
$total = mysql_result($query, 0);

Mudaremos a consulta e outras trs linhas depois:


87 // Procura por usurios com o mesmo usurio e senha
88 $sql = "SELECT COUNT(*) AS total
89

FROM `{$this->bancoDeDados}`.`{$this->tabelaUsuarios}`

90

WHERE

91

`{$this->campos['usuario']}` = '{$usuario}'

92

AND

93

`{$this->campos['senha']}` = '{$senha}'";

94 $query = mysql_query($sql);
95
96

if ($query) {
$total = mysql_result($query, 0, 'total');

97
98
99

// Limpa a consulta da memria


mysql_free_result($query);

Essa mudana foi necessria por causa de um probleminha com a funo


mysql_result() que tem dificuldades de identificar qual resultado ns queremos Com
esse ajuste tudo ir funcionar perfeitamente.

Agora ns iremos comear a criar o mtodo que verifica se h um usurio logado


Ele ir retornar TRUE quando um usurio estiver logado e retornar FALSE em
qualquer situao que indique que no h um usurio logado, por isso precisamos
verificar todas as possibilidades:
183

/**

184

* Verifica se h um usurio logado no sistema

185

186

* @return boolean - Se h um usurio logado ou no

187
188

*/
function usuarioLogado() {

189
190

// Continuaremos aqui...
}

Primeiro ns verificamos a necessidade de iniciar a sesso e lgo aps isso iremos


verificar se existe o valor logado na sesso:
189

// Inicia a sesso?

190

if ($this->iniciaSessao AND !isset($_SESSION)) {

191
192

session_start();
}

193
194
195
196

// Verifica se no existe o valor na sesso


if (!isset($_SESSION[$this->prefixoChaves . 'logado']) OR !
$_SESSION[$this->prefixoChaves . 'logado']) {
return false;

197

Pra quem no lembra, esse valor $this->prefixoChaves . logado foi criado pelo
mtodologaUsuario().

Agora ns precisamos verificar (caso seja necessrio) o cookie que contm as


informaes (usurio, IP e navegador) do usurio para ver se elas batem com o que
est armazenado no cookie:
199

// Faz a verificao do cookie?

200

if ($this->cookie) {

201

// Verifica se o cookie no existe

202

if (!isset($_COOKIE[$this->prefixoChaves . 'token'])) {

203

return false;

204

} else {

205
206

// Continuaremos aqui...
}

207

Caso haja o cookie, precisamos criar novamente uma string encriptada contendo as
informaes do usurio para checar com o valor salvo no cookie:
205 // Monta o valor do cookie
$valor = join('#', array($_SESSION[$this206 >prefixoChaves . 'usuario'],
$_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']));
207
208
209

// Encripta o valor do cookie


$valor = sha1($valor);

210
211 // Verifica o valor do cookie
212 if ($_COOKIE[$this->prefixoChaves . 'token'] !== $valor) {
213
214

return false;
}

Feita a verificao do cookie sabemos que, depois disso tudo, o usurio est logado e
podemos retornar true e fechar o mtodo..
218 // A sesso e o cookie foram verificados, h um usurio logado
219 return true;

Terminamos o mtodo que informa se h um usurio logado, agora vamos comear o


mtodo que far o logout do usurio:
222
223

/**
* Faz logout do usurio logado

224

225

* @return boolean

226

*/

227

function logout() {

228
229

// Continuaremos aqui...
}

O primeiro passo do logout iniciar a sesso e remover todos os valores da sesso


228

// Inicia a sesso?

229

if ($this->iniciaSessao AND !isset($_SESSION)) {

230
231

session_start();
}

232
233
234

// Tamanho do prefixo
$tamanho = strlen($this->prefixoChaves);

235
236 // Destroi todos os valores da sesso relativos ao sistema de login
237 foreach ($_SESSION AS $chave=>$valor) {
238
239

// Remove apenas valores cujas chaves comecem com o prefixo


correto
if (substr($chave, 0, $tamanho) == $this->prefixoChaves) {

240
241
242

unset($_SESSION[$chave]);
}
}

Repare que entre a linha 236 e 242 fizemos uma coisa interessante: removemos da
sesso apenas os valores que pertencerem ao nosso sistema de login Muita gente

usa um simples session_destroy() para acabar com a sesso, mas se o seu site
salvar valores na sesso no podemos simplesmente apag-los, concorda?

Por isso ns fazemos uma verificao a mais, que checa se ainda existem valores na
sesso e [caso no exista nada] usamos o session_destroy() e depois removemos o
cookie que identifica qual sesso de qual visitante:
244

// Destri asesso se ela estiver vazia

245

if (count($_SESSION) == 0) {

246

session_destroy();

247
248

// Remove o cookie da sesso se ele existir

249

if (isset($_COOKIE['PHPSESSID'])) {

250

setcookie('PHPSESSID', false, (time() - 3600));

251

unset($_COOKIE['PHPSESSID']);

252

253

Agora o ltimo passo do logout remover o cookie que armazena as informaes do


visitante:
255 // Remove o cookie com as informaes do visitante
256

if ($this->cookie AND isset($_COOKIE[$this>prefixoChaves . 'token'])) {

257

setcookie($this->prefixoChaves . 'token', false, (time() 3600),'/');

258

unset($_COOKIE[$this->prefixoChaves . 'token']);

259

Terminando o mtodo poremos retornar o valor booleano (true ou false) que informa se
o usurio foi deslogado com sucesso Existe forma melhor de fazer isso do que
verificando se no h um usurio logado?
261

// Retorna SE no h um usurio logado

262

return !$this->usuarioLogado();

E a nossa classe de controle e gerencia de usurios logados est completa!

Espero realmente que tenham gostado e aprendido com essa sequencia de tutoriais.
Abraos e at a prxima!

Você também pode gostar