Esta é a parte 3 de uma série de tutoriais sobre como criar um sistema de gerenciamento de contas de usuário. Você pode encontrar as outras partes aqui: parte 1, parte 2.
Validação do formulário
Neste ponto na página signup.php, se você clicar no botão de inscrição sem preencher nenhum dos campos do formulário, não receberá nenhum feedback, mas o formulário também não fará nada. Ele só fica lá olhando para você. Permanece assim porque há erros em uma $errors da nossa função validateUser() definida anteriormente que ainda não estamos exibindo no formulário. Esses erros existem em pares chave-valor.
Por exemplo, $errors['username'] contém o erro, se houver, para o campo de nome de usuário. Para que possamos verificar se o erro de nome de usuário existe, adicionamos a classe bootstrap has-error ao elemento div que envolve o campo de entrada de nome de usuário. Isso torna o texto do rótulo e a borda de entrada vermelha, indicando que há um erro.
Validaremos os campos de nome de usuário, e-mail, senha e confirmação de senha. Então abra seu arquivo signup.php e substitua estes quatro campos por este código:
<div class="form-group <?php echo isset($errors['username']) ? 'has-error' : '' ?>">
<label class="control-label">Username</label>
<input type="text" name="username" value="<?php echo $username; ?>" class="form-control">
<?php if (isset($errors['username'])): ?>
<span class="help-block"><?php echo $errors['username'] ?></span>
<?php endif; ?>
</div>
<div class="form-group <?php echo isset($errors['email']) ? 'has-error' : '' ?>">
<label class="control-label">Email Address</label>
<input type="email" name="email" value="<?php echo $email; ?>" class="form-control">
<?php if (isset($errors['email'])): ?>
<span class="help-block"><?php echo $errors['email'] ?></span>
<?php endif; ?>
</div>
<div class="form-group <?php echo isset($errors['password']) ? 'has-error' : '' ?>">
<label class="control-label">Password</label>
<input type="password" name="password" class="form-control">
<?php if (isset($errors['password'])): ?>
<span class="help-block"><?php echo $errors['password'] ?></span>
<?php endif; ?>
</div>
<div class="form-group <?php echo isset($errors['passwordConf']) ? 'has-error' : '' ?>">
<label class="control-label">Password confirmation</label>
<input type="password" name="passwordConf" class="form-control">
<?php if (isset($errors['passwordConf'])): ?>
<span class="help-block"><?php echo $errors['passwordConf'] ?></span>
<?php endif; ?>
</div>
Logo abaixo de cada campo de entrada, estamos exibindo condicionalmente a mensagem de erro para cada campo do formulário.
Caso você não conheça o operador ternário, aqui está uma breve explicação.
<?php echo isset($errors['username']) ? 'has-error' : '' ?>
Essa instrução basicamente diz que, se a variável $errors['username'] for definida como um valor (não estiver vazio), exibirá o erro, caso contrário, exibirá uma string vazia. É basicamente apenas uma instrução if-else.
Agora você pode experimentar esta validação clicando no formulário vazio. Você verá mensagens de validação bem formatadas.
Login do usuário
Na pasta raiz do seu aplicativo, crie um arquivo chamado login.php.
login.php:
<?php include('config.php'); ?>
<?php include(INCLUDE_PATH . '/logic/userSignup.php'); ?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>UserAccounts - Login</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<!-- Custome styles -->
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<?php include(INCLUDE_PATH . "/layouts/navbar.php") ?>
<div class="container">
<div class="row">
<div class="col-md-4 col-md-offset-4">
<form class="form" action="login.php" method="post">
<h2 class="text-center">Login</h2>
<hr>
<!-- display form error messages -->
<?php include(INCLUDE_PATH . "/layouts/messages.php") ?>
<div class="form-group <?php echo isset($errors['username']) ? 'has-error' : '' ?>">
<label class="control-label">Username or Email</label>
<input type="text" name="username" id="password" value="<?php echo $username; ?>" class="form-control">
<?php if (isset($errors['username'])): ?>
<span class="help-block"><?php echo $errors['username'] ?></span>
<?php endif; ?>
</div>
<div class="form-group <?php echo isset($errors['password']) ? 'has-error' : '' ?>">
<label class="control-label">Password</label>
<input type="password" name="password" id="password" class="form-control">
<?php if (isset($errors['password'])): ?>
<span class="help-block"><?php echo $errors['password'] ?></span>
<?php endif; ?>
</div>
<div class="form-group">
<button type="submit" name="login_btn" class="btn btn-success">Login</button>
</div>
<p>Don't have an account? <a href="signup.php">Sign up</a></p>
</form>
</div>
</div>
</div>
<?php include(INCLUDE_PATH . "/layouts/footer.php") ?>
Agora abra userSignup.php e no final do arquivo, adicione este código para logar usuário:
// ...
// USER LOGIN
if (isset($_POST['login_btn'])) {
// validate form values
$errors = validateUser($_POST, ['login_btn']);
$username = $_POST['username'];
$password = $_POST['password']; // don't escape passwords.
if (empty($errors)) {
$sql = "SELECT * FROM users WHERE username=? OR email=? LIMIT 1";
$user = getSingleRecord($sql, 'ss', [$username, $username]);
if (!empty($user)) { // if user was found
if (password_verify($password, $user['password'])) { // if password matches
// log user in
loginById($user['id']);
} else { // if password does not match
$_SESSION['error_msg'] = "Wrong credentials";
}
} else { // if no user found
$_SESSION['error_msg'] = "Wrong credentials";
}
}
}
Se você clicar no botão de login sem preenchê-lo, as mensagens de validação aparecerão no formulário, assim como no caso da página de inscrição.
Agora digite o e-mail e a senha da conta de usuário que criamos anteriormente e clique no botão de login. Se as credenciais estiverem corretas, você será logado e redirecionado para a página inicial. Uma mensagem flash será exibida informando que você está logado.
Mas você notará que mesmo que o usuário esteja logado agora, os links de inscrição e login na barra de navegação ainda estão sendo exibidos, o que não faz sentido, certo? Vamos substituí-los pelo nome de usuário conectado e um menu suspenso com um link de logout.
Abra o arquivo navbar.php e substitua o código que está nele com este:
navbar.php:
<!-- the whole site is wrapped in a container div to give it some margin on the sides -->
<!-- closing container div can be found in the footer -->
<div class="container">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">UserAccounts</a>
</div>
<!-- <ul class="nav navbar-nav">
<li class="active"><a href="#">Home</a></li>
<li><a href="#">Page 1</a></li>
<li><a href="#">Page 2</a></li>
</ul> -->
<ul class="nav navbar-nav navbar-right">
<?php if (isset($_SESSION['user'])): ?>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<?php echo $_SESSION['user']['username'] ?> <span class="caret"></span></a>
<?php if (isAdmin($_SESSION['user']['id'])): ?>
<ul class="dropdown-menu">
<li><a href="<?php echo BASE_URL . 'admin/profile.php' ?>">Profile</a></li>
<li><a href="<?php echo BASE_URL . 'admin/dashboard.php' ?>">Dashboard</a></li>
<li role="separator" class="divider"></li>
<li><a href="<?php echo BASE_URL . 'logout.php' ?>" style="color: red;">Logout</a></li>
</ul>
<?php else: ?>
<ul class="dropdown-menu">
<li><a href="<?php echo BASE_URL . 'logout.php' ?>" style="color: red;">Logout</a></li>
</ul>
<?php endif; ?>
</li>
<?php else: ?>
<li><a href="<?php echo BASE_URL . 'signup.php' ?>"><span class="glyphicon glyphicon-user"></span> Sign Up</a></li>
<li><a href="<?php echo BASE_URL . 'login.php' ?>"><span class="glyphicon glyphicon-log-in"></span> Login</a></li>
<?php endif; ?>
</ul>
</div>
</nav>
Agora atualize a página index.php. Se você ainda estava logado, verá que o cabeçalho mudou e agora exibe seu nome de usuário na barra de navegação. Quando você clicar no nome de usuário, uma lista suspensa aparecerá com um link de logout. Se você clicar nele, dirá página não encontrada porque ainda não criamos o arquivo logout.php. Vamos criar esse arquivo agora na pasta raiz do nosso aplicativo.
logout.php:
<?php
session_start();
session_destroy();
unset($_SESSION['user']);
header("location: login.php");
?>
E terminamos com a autenticação normal do usuário. Agora vamos para o cerne da questão que é a seção de administração. Espero que você esteja gostando.
No momento, estamos logando o usuário por meio de apenas uma função, a função loginById(). Nessa função, se o usuário que está efetuando login for um usuário administrativo, ele será redirecionado para o arquivo dashboard.php.
Seção de administração
Dentro da pasta admin, crie o arquivo dashboard.php:
painel.php:
<?php include('../config.php') ?>
<?php include(ROOT_PATH . '/admin/middleware.php') ?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Admin</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<!-- Custome styles -->
<link rel="stylesheet" href="../static/css/style.css">
</head>
<body>
<?php include(INCLUDE_PATH . "/layouts/admin_navbar.php") ?>
<div class="col-md-4 col-md-offset-4">
<h1 class="text-center">Admin</h1>
<br />
<ul class="list-group">
<a href="<?php echo BASE_URL . 'admin/posts/postList.php' ?>" class="list-group-item">Manage Posts</a>
<a href="<?php echo BASE_URL . 'admin/users/userList.php' ?>" class="list-group-item">Manage Users</a>
<a href="<?php echo BASE_URL . 'admin/roles/roleList.php' ?>" class="list-group-item">Manage Roles</a>
</ul>
</div>
<?php include(INCLUDE_PATH . "/layouts/footer.php") ?>
</body>
</html>
No seu navegador, visite http://localhost/user-accounts/admin/dashboard.php e você verá algumas mensagens de aviso. Isso porque estamos incluindo dois arquivos que ainda não existem:middleware.php e admin_navbar.php.
Quanto ao middleware.php, trabalharemos nele mais tarde. Mas, por enquanto, basta criá-lo dentro da pasta admin e deixá-lo em branco para que a mensagem de aviso desapareça e nos deixe em paz.
Quanto ao admin_navbar.php, crie-o dentro da pasta includes/layouts:
admin_navbar.php:
<!-- the whole site is wrapped in a container div to give it some margin on the sides -->
<!-- closing container div can be found in the footer -->
<div class="container">
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="<?php echo BASE_URL . 'admin/dashboard.php' ?>">Dashboard</a>
</div>
<ul class="nav navbar-nav navbar-right">
<?php if (isset($_SESSION['user'])): ?>
<li><a href="<?php echo BASE_URL . 'index.php' ?>"><span class="glyphicon glyphicon-globe"></span></a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<?php echo $_SESSION['user']['username'] . ' (' . $_SESSION['user']['role'] . ')'; ?> <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="<?php echo BASE_URL . 'admin/users/editProfile.php' ?>">Profile</a></li>
<li><a href="<?php echo BASE_URL . 'admin/dashboard.php' ?>">Dashboard</a></li>
<li role="separator" class="divider"></li>
<li><a href="<?php echo BASE_URL . 'logout.php' ?>" style="color: red;">Logout</a></li>
</ul>
</li>
<?php endif; ?>
</ul>
</div>
</nav>
<?php include(INCLUDE_PATH . "/layouts/messages.php") ?>
No seu navegador, atualize a página dashboard.php agora e as mensagens de aviso desaparecerão.
O dashboard.php é a área administrativa, certo? Não deve ser acessado por usuários comuns. Portanto, precisamos redirecionar qualquer usuário normal que tente visitar esta página de volta à página inicial. Além disso, ainda não estamos criando/gerenciando usuários e funções de administrador. Tudo isso está para breve.
Vamos encerrar esta parte aqui. Na próxima parte, continuamos com o gerenciamento de contas de usuários administrativos e também com o controle de acesso.
Se você está gostando desses tutoriais e quer mais deles, considere compartilhar/recomendar os tutoriais entre seus amigos. Isso ajudará muito a me apoiar na criação de mais disso.
Obrigado por acompanhar e até a próxima parte.