Primeiramente, vamos resumir o que será apresentado nessa leitura, você aprenderá a criar e como fazer um sistema de login com PHP e MySQL.
Tabela de Conteúdo
Autenticação dos Usuários
No desenvolvimento web moderno, autenticação de usuários é algo bastante comum e serve como mecanismo de segurança para acessos não autorizados a um ambiente onde somente quem tem cadastro pode entrar, como uma área de membros.
Sistema de Registro
Então, aqui o usuário terá a opção de criar um cadastro preenchendo um formulário, resumindo, se cadastrando. Portanto, o primeiro passo é criar a tabela no banco de dados
Passo 01 – Criar tabela no banco de dados
CREATE TABLE users (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
Dessa forma, para criar a tabela, basta escolher abrir o PHPMyAdmin e clicar no BD “test” -> SQL (colar o código lá) -> Executar. Conforme imagem abaixo:

Passo 02 – Criação do arquivo de configuração (config.php)
Aqui nós iremos conectar através de um script PHP ao servidor do banco de dados MySQL.
Vamos criar o famoso “config.php” e colocar o devido código dentro dele:
<?php
/* Credenciais do banco de dados. Supondo que você esteja executando o MySQL
servidor com configuração padrão (usuário 'root' sem senha) */
define('DB_SERVER', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'test');
/* Tentativa de conexão com o banco de dados MySQL */
try{
$pdo = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USERNAME, DB_PASSWORD);
// Defina o modo de erro PDO para exceção
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
die("ERROR: Não foi possível conectar." . $e->getMessage());
}
?>
Nota: Substitua as credenciais de acordo com a configuração do seu servidor MySQL antes de testar este código, por exemplo, substitua o nome do banco de dados ‘test’ pelo seu próprio nome do banco de dados, substitua o nome de usuário ‘root’ pelo seu nome de usuário do banco de dados, especifique a senha do banco de dados, se houver. Caso não faça isso, certifique-se que a tabela tenha sido criado em “test e deixem igual ao exemplo acima sem alterar usuário root ou senha, para fins de aprendizado.
Passo 03 – Vamos criar o formulário de inscrição (register.php)
Aqui vamos criar o arquivo register.php e dentro dele vai ter um script que permitirá que o usuário se registre. Dessa forma, totalmente configurado para gerar mensagens de erro caso usuário não insira nenhum valor ou caso o nome inserido já esteja em uso.
<?php
// Incluir arquivo de configuração
require_once "config.php";
// Defina variáveis e inicialize com valores vazios
$username = $password = $confirm_password = "";
$username_err = $password_err = $confirm_password_err = "";
// Processando dados do formulário quando o formulário é enviado
if($_SERVER["REQUEST_METHOD"] == "POST"){
// Validar nome de usuário
if(empty(trim($_POST["username"]))){
$username_err = "Por favor coloque um nome de usuário.";
} elseif(!preg_match('/^[a-zA-Z0-9_]+$/', trim($_POST["username"]))){
$username_err = "O nome de usuário pode conter apenas letras, números e sublinhados.";
} else{
// Prepare uma declaração selecionada
$sql = "SELECT id FROM users WHERE username = :username";
if($stmt = $pdo->prepare($sql)){
// Vincule as variáveis à instrução preparada como parâmetros
$stmt->bindParam(":username", $param_username, PDO::PARAM_STR);
// Definir parâmetros
$param_username = trim($_POST["username"]);
// Tente executar a declaração preparada
if($stmt->execute()){
if($stmt->rowCount() == 1){
$username_err = "Este nome de usuário já está em uso.";
} else{
$username = trim($_POST["username"]);
}
} else{
echo "Ops! Algo deu errado. Por favor, tente novamente mais tarde.";
}
// Fechar declaração
unset($stmt);
}
}
// Validar senha
if(empty(trim($_POST["password"]))){
$password_err = "Por favor insira uma senha.";
} elseif(strlen(trim($_POST["password"])) < 6){
$password_err = "A senha deve ter pelo menos 6 caracteres.";
} else{
$password = trim($_POST["password"]);
}
// Validar e confirmar a senha
if(empty(trim($_POST["confirm_password"]))){
$confirm_password_err = "Por favor, confirme a senha.";
} else{
$confirm_password = trim($_POST["confirm_password"]);
if(empty($password_err) && ($password != $confirm_password)){
$confirm_password_err = "A senha não confere.";
}
}
// Verifique os erros de entrada antes de inserir no banco de dados
if(empty($username_err) && empty($password_err) && empty($confirm_password_err)){
// Prepare uma declaração de inserção
$sql = "INSERT INTO users (username, password) VALUES (:username, :password)";
if($stmt = $pdo->prepare($sql)){
// Vincule as variáveis à instrução preparada como parâmetros
$stmt->bindParam(":username", $param_username, PDO::PARAM_STR);
$stmt->bindParam(":password", $param_password, PDO::PARAM_STR);
// Definir parâmetros
$param_username = $username;
$param_password = password_hash($password, PASSWORD_DEFAULT); // Creates a password hash
// Tente executar a declaração preparada
if($stmt->execute()){
// Redirecionar para a página de login
header("location: login.php");
} else{
echo "Ops! Algo deu errado. Por favor, tente novamente mais tarde.";
}
// Fechar declaração
unset($stmt);
}
}
// Fechar conexão
unset($pdo);
}
?>
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Cadastro</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<style>
body{ font: 14px sans-serif; }
.wrapper{ width: 360px; padding: 20px; }
</style>
</head>
<body>
<div class="wrapper">
<h2>Cadastro</h2>
<p>Por favor, preencha este formulário para criar uma conta.</p>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
<div class="form-group">
<label>Nome do usuário</label>
<input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
<span class="invalid-feedback"><?php echo $username_err; ?></span>
</div>
<div class="form-group">
<label>Senha</label>
<input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $password; ?>">
<span class="invalid-feedback"><?php echo $password_err; ?></span>
</div>
<div class="form-group">
<label>Confirme a senha</label>
<input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $confirm_password; ?>">
<span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Criar Conta">
<input type="reset" class="btn btn-secondary ml-2" value="Apagar Dados">
</div>
<p>Já tem uma conta? <a href="login.php">Entre aqui</a>.</p>
</form>
</div>
</body>
</html>
Após a inserção do código, o resultado será igual o da imagem abaixo:

Dessa forma, como no exemplo acima, usamos a função embutida password_hash()
do PHP para criar um hash de senha a partir da string de senha inserida pelo usuário. Portanto, esta função cria um hash de senha usando um algoritmo de hash unilateral forte. Ele também gera e aplica um salt aleatório automaticamente ao fazer o hash da senha; Isso basicamente significa que, mesmo que dois usuários tenham as mesmas senhas, seus hashes de senha serão diferentes.
No momento do login, verificaremos a senha fornecida com o hash de senha armazenado no banco de dados usando a função PHP password_verify()
, conforme demonstrado no próximo exemplo.
Usamos a estrutura do Bootstrap para criar layouts de formulário de maneira rápida e bonita. Por favor, verifique a seção do tutorial do Bootstrap para aprender mais sobre esta estrutura.
Dica: Salting de senha é uma técnica amplamente usada para proteger senhas por meio da randomização de hashes de senha, de forma que, se dois usuários tiverem a mesma senha, eles não terão os mesmos hashes de senha. Dessa forma, isso é feito anexando ou prefixando uma String aleatória, chamada de salt, à senha antes de fazer o hash.
Sistema de Login (login.php)
Aqui o criaremos o formulário de login onde usuário irá inserir suas credenciais cadastradas no formulário de cadastro, login e senha.
Então, ao inserir os dados, as informações inseridas serão verificadas com as informações armazenadas no banco de dados.
Caso os dados estejam certos, o usuário será redirecionado e terá acesso ao sistema, caso os dados não confiram, mensagens de erro serão retornadas para ele.
Passo 01 – Formulário de login
Aqui vamos criar nosso arquivo dentro da pasta raiz do projeto “login.php”.
<?php
// Inicialize a sessão
session_start();
// Verifique se o usuário já está logado, em caso afirmativo, redirecione-o para a página de boas-vindas
if(isset($_SESSION["loggedin"]) && $_SESSION["loggedin"] === true){
header("location: welcome.php");
exit;
}
// Incluir arquivo de configuração
require_once "config.php";
// Defina variáveis e inicialize com valores vazios
$username = $password = "";
$username_err = $password_err = $login_err = "";
// Processando dados do formulário quando o formulário é enviado
if($_SERVER["REQUEST_METHOD"] == "POST"){
// Verifique se o nome de usuário está vazio
if(empty(trim($_POST["username"]))){
$username_err = "Por favor, insira o nome de usuário.";
} else{
$username = trim($_POST["username"]);
}
// Verifique se a senha está vazia
if(empty(trim($_POST["password"]))){
$password_err = "Por favor, insira sua senha.";
} else{
$password = trim($_POST["password"]);
}
// Validar credenciais
if(empty($username_err) && empty($password_err)){
// Prepare uma declaração selecionada
$sql = "SELECT id, username, password FROM users WHERE username = :username";
if($stmt = $pdo->prepare($sql)){
// Vincule as variáveis à instrução preparada como parâmetros
$stmt->bindParam(":username", $param_username, PDO::PARAM_STR);
// Definir parâmetros
$param_username = trim($_POST["username"]);
// Tente executar a declaração preparada
if($stmt->execute()){
// Verifique se o nome de usuário existe, se sim, verifique a senha
if($stmt->rowCount() == 1){
if($row = $stmt->fetch()){
$id = $row["id"];
$username = $row["username"];
$hashed_password = $row["password"];
if(password_verify($password, $hashed_password)){
// A senha está correta, então inicie uma nova sessão
session_start();
// Armazene dados em variáveis de sessão
$_SESSION["loggedin"] = true;
$_SESSION["id"] = $id;
$_SESSION["username"] = $username;
// Redirecionar o usuário para a página de boas-vindas
header("location: welcome.php");
} else{
// A senha não é válida, exibe uma mensagem de erro genérica
$login_err = "Nome de usuário ou senha inválidos.";
}
}
} else{
// O nome de usuário não existe, exibe uma mensagem de erro genérica
$login_err = "Nome de usuário ou senha inválidos.";
}
} else{
echo "Ops! Algo deu errado. Por favor, tente novamente mais tarde.";
}
// Fechar declaração
unset($stmt);
}
}
// Fechar conexão
unset($pdo);
}
?>
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Login</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<style>
body{ font: 14px sans-serif; }
.wrapper{ width: 360px; padding: 20px; }
</style>
</head>
<body>
<div class="wrapper">
<h2>Login</h2>
<p>Por favor, preencha os campos para fazer o login.</p>
<?php
if(!empty($login_err)){
echo '<div class="alert alert-danger">' . $login_err . '</div>';
}
?>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
<div class="form-group">
<label>Nome do usuário</label>
<input type="text" name="username" class="form-control <?php echo (!empty($username_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $username; ?>">
<span class="invalid-feedback"><?php echo $username_err; ?></span>
</div>
<div class="form-group">
<label>Senha</label>
<input type="password" name="password" class="form-control <?php echo (!empty($password_err)) ? 'is-invalid' : ''; ?>">
<span class="invalid-feedback"><?php echo $password_err; ?></span>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Entrar">
</div>
<p>Não tem uma conta? <a href="register.php">Inscreva-se agora</a>.</p>
</form>
</div>
</body>
</html>
Após inserir o código do arquivo “login.php” o resultado será igual o da imagem abaixo:

Passo 02 – Página de boas-vindas (welcome.php)
Então, aqui será a página onde usuário será redirecionado ao ter sua credenciais de login validades pelo nosso sistema.
<?php
// Inicialize a sessão
session_start();
// Verifique se o usuário está logado, se não, redirecione-o para uma página de login
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
header("location: login.php");
exit;
}
?>
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Bem vindo</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<style>
body{ font: 14px sans-serif; text-align: center; }
</style>
</head>
<body>
<h1 class="my-5">Oi, <b><?php echo htmlspecialchars($_SESSION["username"]); ?></b>. Bem vindo ao nosso site.</h1>
<p>
<a href="reset-password.php" class="btn btn-warning">Redefina sua senha</a>
<a href="logout.php" class="btn btn-danger ml-3">Sair da conta</a>
</p>
</body>
</html>
A página terá essa aparência após o termino do passo acima:

Passo 03 – Script de logout (logout.php)
Dessa forma, agora vamos criar um arquivo “logout.php”. Portanto, quando o usuário clica no link de logout ou logout, o script dentro desse arquivo destrói a sessão e redireciona o usuário de volta para a página de login.
<?php
// Inicialize a sessão
session_start();
// Remova todas as variáveis de sessão
$_SESSION = array();
// Destrua a sessão.
session_destroy();
// Redirecionar para a página de login
header("location: login.php");
exit;
?>
Passo 04 – Página e script para redefinir a senha (reset-password.php)
Então, aqui vamos criar nossa página e script para redefinir a senha. Portanto, vamos criar o arquivo reset-password.php na pasta raiz do nosso projeto e adicionar o seguinte código nele:
<?php
// Inicialize a sessão
session_start();
// Verifique se o usuário está logado, caso contrário, redirecione para a página de login
if(!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true){
header("location: login.php");
exit;
}
// Incluir arquivo de configuração
require_once "config.php";
// Defina variáveis e inicialize com valores vazios
$new_password = $confirm_password = "";
$new_password_err = $confirm_password_err = "";
// Processando dados do formulário quando o formulário é enviado
if($_SERVER["REQUEST_METHOD"] == "POST"){
// Validar nova senha
if(empty(trim($_POST["new_password"]))){
$new_password_err = "Por favor insira a nova senha.";
} elseif(strlen(trim($_POST["new_password"])) < 6){
$new_password_err = "A senha deve ter pelo menos 6 caracteres.";
} else{
$new_password = trim($_POST["new_password"]);
}
// Validar e confirmar a senha
if(empty(trim($_POST["confirm_password"]))){
$confirm_password_err = "Por favor, confirme a senha.";
} else{
$confirm_password = trim($_POST["confirm_password"]);
if(empty($new_password_err) && ($new_password != $confirm_password)){
$confirm_password_err = "A senha não confere.";
}
}
// Verifique os erros de entrada antes de atualizar o banco de dados
if(empty($new_password_err) && empty($confirm_password_err)){
// Prepare uma declaração de atualização
$sql = "UPDATE users SET password = :password WHERE id = :id";
if($stmt = $pdo->prepare($sql)){
// Vincule as variáveis à instrução preparada como parâmetros
$stmt->bindParam(":password", $param_password, PDO::PARAM_STR);
$stmt->bindParam(":id", $param_id, PDO::PARAM_INT);
// Definir parâmetros
$param_password = password_hash($new_password, PASSWORD_DEFAULT);
$param_id = $_SESSION["id"];
// Tente executar a declaração preparada
if($stmt->execute()){
// Senha atualizada com sucesso. Destrua a sessão e redirecione para a página de login
session_destroy();
header("location: login.php");
exit();
} else{
echo "Ops! Algo deu errado. Por favor, tente novamente mais tarde.";
}
// Fechar declaração
unset($stmt);
}
}
// Fechar conexão
unset($pdo);
}
?>
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<title>Redefinir senha</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<style>
body{ font: 14px sans-serif; }
.wrapper{ width: 360px; padding: 20px; }
</style>
</head>
<body>
<div class="wrapper">
<h2>Redefinir senha</h2>
<p>Por favor, preencha este formulário para redefinir sua senha.</p>
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>" method="post">
<div class="form-group">
<label>Nova senha</label>
<input type="password" name="new_password" class="form-control <?php echo (!empty($new_password_err)) ? 'is-invalid' : ''; ?>" value="<?php echo $new_password; ?>">
<span class="invalid-feedback"><?php echo $new_password_err; ?></span>
</div>
<div class="form-group">
<label>Confirme a senha</label>
<input type="password" name="confirm_password" class="form-control <?php echo (!empty($confirm_password_err)) ? 'is-invalid' : ''; ?>">
<span class="invalid-feedback"><?php echo $confirm_password_err; ?></span>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Redefinir">
<a class="btn btn-link ml-2" href="welcome.php">Cancelar</a>
</div>
</form>
</div>
</body>
</html>
Após o termino do passo acima, a página terá a seguinte aparencia:

Conclusão de sistema de login com PHP e MySQL (PDO)
Portanto, agora temos um sistema de login com PHP e MySQL completinho! Claro, esse é só o começo. Sempre há espaço para melhorias, como adicionar autenticação em duas etapas, reforçar a segurança contra ataques como CSRF e XSS e também aprender a implementar essa abordagem seguindo o padrão de arquitetura de software MVC, ou até integrar um sistema de recuperação de senha. O importante é entender os princípios e construir algo que realmente faça sentido no seu projeto.
Agora é pegar esse conhecimento e colocar em prática. Se der erro, debugue. Se travar, pesquise. E se ficar bom, bora melhorar ainda mais. Código bom é código que evolui.
Conteúdo em vídeo:
Sensacional, parabéns amigão. Acho que só faltou um arquivo para proteger as áreas onde entraremos com o login. Mas acredito quem Welcome.php dá para extrair esse detalhe