LP3

LP3

LP3

profile-pic

Prática 03 — Login e Fluxo de Requisição em PHP

Esta prática apresenta o fluxo mínimo de autenticação em PHP sem banco de dados: formulário HTML, envio por POST, validação no servidor, redirecionamento com header() em caso de erro e exibição da área autenticada pelo próprio backend.

Objetivo desta prática: compreender o caminho que os dados fazem entre navegador e servidor e perceber que a permissão de acesso depende da validação feita pelo backend. O uso de hash de senha aparece na prática 05, e o controle de sessão será discutido em uma aula subsequente.

Animação do fluxo

O fluxo de comunicação trabalhado nesta prática está demonstrado abaixo. A animação mostra o navegador pedindo login.php, enviando POST para autenticar.php e recebendo a resposta do servidor. Para melhor visualização, abra a animação em tela cheia.

Conceitos centrais desta prática
  • require carrega um arquivo externo que a página precisa para funcionar.
  • header("Location: ...") faz o PHP redirecionar o navegador para outra página.
  • Login é uma comparação de informações feita no servidor.
  • O array associativo organiza os dados de cada usuário com chaves como login, senha e perfil.

Selecione uma prática no menu lateral ou abaixo para construir o sistema passo a passo.

Prática 01 — Separando os arquivos no servidor

Para esta prática, comece criando uma pasta login dentro de htdocs.

Passo a passo
  1. Na pasta htdocs, crie a pasta login.
  2. Dentro dela, crie os arquvios, ainda em branco, usuarios.php, login.php e autenticar.php.
  3. Ligue o Apache no XAMPP.
  4. Acesse http://localhost/login/ para conferir se a pasta responde pelo servidor.
Estrutura sugerida da pasta
login/
├── usuarios.php
├── login.php
└── autenticar.php

Prática 02 — Criando o vetor hardcoded de usuários

Agora vamos guardar os usuários em um arquivo separado. Isso é importante porque deixa visível qual parte do sistema contém os dados e qual parte contém a regra de login.

Passo a passo
  1. Abra usuarios.php.
  2. Copie o vetor de usuários do exemplo abaixo.
  3. Confira os campos de cada registro: id, login, senha, nome e perfil.
  4. Salve o arquivo. Ele será carregado depois pelo autenticar.php.
Arquivo usuarios.php
<?php
$usuarios = [
    [
        "id" => 1,
        "login" => "ana",
        "senha" => "1234",
        "nome" => "Ana Souza",
        "perfil" => "aluno"
    ],
    [
        "id" => 2,
        "login" => "bruno",
        "senha" => "abcd",
        "nome" => "Bruno Lima",
        "perfil" => "monitor"
    ],
    [
        "id" => 3,
        "login" => "carla",
        "senha" => "9999",
        "nome" => "Carla Rocha",
        "perfil" => "professor"
    ]
];
?>

Cada usuário já aparece como uma entidade com campos nomeados: id, login, senha, nome e perfil. Depois, essa mesma ideia pode virar uma linha de banco ou um objeto da classe Usuario sem mudar o fluxo geral do sistema.

Esse tipo de vetor facilita a leitura do código, porque cada informação é acessada pelo nome do campo. Em vez de pensar em posições numéricas, o código usa chaves como $usuario["login"] e $usuario["senha"].

Observação: a senha está em texto puro apenas nesta primeira versão. Isso será trocado em uma etapa posterior.

Prática 03 — Página de login

A página de login contém essencialmente um formulário html. Nesta prática, vamos criá-la.

Passo a passo
  1. Abra login.php e copie o código do formulário abaixo.
  2. Observe os pontos principais: action="autenticar.php", method="POST" e os campos name="login" e name="senha".
  3. Mantenha o bloco PHP que mostra erro quando existir $_GET["erro"]. Por conta deste trecho de código (que ficará mais clara nas próximas práticas), este arquivo é .php e não .html.
  4. Salve e acesse http://localhost/login/login.php.

Este arquivo não é HTML puro. Ele se chama login.php porque contém um trecho de PHP embutido no final da página. Por isso, precisa ser processado no servidor pelo interpretador PHP antes de a resposta chegar ao navegador.

Nas próximas práticas ficará claro por que esse trecho PHP existe: ele será usado para mostrar uma mensagem quando o backend redirecionar o usuário de volta após uma tentativa de login inválida.

Arquivo login.php
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
</head>
<body>
    <h1>Login do sistema</h1>

    <form action="autenticar.php" method="POST">
        <label for="login">Login:</label>
        <input type="text" name="login" id="login" required>

        <br><br>

        <label for="senha">Senha:</label>
        <input type="password" name="senha" id="senha" required>

        <br><br>

        <button type="submit">Entrar</button>
    </form>

    <?php
    if (isset($_GET["erro"])) {
        echo '<p style="color: red;">Login ou senha inválidos.</p>';
    }
    ?>
</body>
</html>
Pontos de atenção
  • method="POST" evita mandar usuário e senha na URL.
  • action="autenticar.php" indica qual arquivo receberá os dados.
  • O bloco com $_GET["erro"] mostra uma mensagem quando o login falha.
  • Esta página apenas coleta dados e envia para o backend.

Prática 04 — Autenticando e decidindo entre erro e sucesso

Agora aparece a parte central do backend: receber os dados do formulário, comparar com os usuários cadastrados e decidir entre erro e sucesso. Se o login falhar, o PHP redireciona de volta para o formulário. Se passar, o próprio autenticar.php continua e monta o HTML da área autenticada.

Passo a passo
  1. Abra autenticar.php e copie a versão final abaixo.
  2. Localize quatro partes: require, leitura do POST, busca no vetor e decisão final.
  3. Repare que o HTML só começa depois do teste com $usuarioEncontrado === null.
  4. Exiba nome e perfil usando os dados de $usuarioEncontrado.
  5. Teste o fluxo completo: formulário → autenticação → resposta de sucesso.
Versão final de autenticar.php
<?php
require "usuarios.php";

$loginDigitado = $_POST["login"];
$senhaDigitada = $_POST["senha"];

$usuarioEncontrado = null;

foreach ($usuarios as $usuario) {
    if ($usuario["login"] === $loginDigitado && $usuario["senha"] === $senhaDigitada) {
        $usuarioEncontrado = $usuario;
    }
}

if ($usuarioEncontrado === null) {
    header("Location: login.php?erro=1");
    exit;
}

?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Painel</title>
</head>
<body>
    <h1>Área autenticada</h1>
    <p>Bem-vindo, <?php echo htmlspecialchars($usuarioEncontrado["nome"]); ?>.</p>
    <p>Seu perfil é: <?php echo htmlspecialchars($usuarioEncontrado["perfil"]); ?>.</p>
    <p><a href="login.php">Voltar ao login</a></p>
</body>
</html>
O papel do require

O comando require "usuarios.php"; carrega o arquivo de usuários antes de o restante do código continuar. Assim, o vetor $usuarios fica disponível dentro de autenticar.php.

Isso separa responsabilidades: um arquivo guarda os dados e o outro executa a regra de autenticação.

Como o login funciona neste exemplo

Autenticar significa comparar as credenciais recebidas com uma fonte de dados. O servidor recebe $_POST["login"] e $_POST["senha"], percorre o vetor de usuários e verifica se existe um registro com os mesmos valores.

Login não é um comando pronto da linguagem. Login é uma regra de comparação feita no servidor. Quando a comparação dá certo, o script continua e pode gerar o HTML da área autenticada.

O operador de identidade (===)

Em PHP, === compara valor e tipo. Já == compara apenas o valor depois de tentar converter os tipos automaticamente.

No código, $usuarioEncontrado começa como null. Se nenhum usuário for encontrado, ele continua exatamente null. Por isso usamos $usuarioEncontrado === null, sem conversões automáticas.

O que este código mostra
  • header("Location: ...") manda o navegador ir para outra página.
  • exit; encerra a execução quando o login falha.
  • Se o login falhar, o redirecionamento volta para login.php.
  • Se o login der certo, o código passa pelo if e chega ao HTML de sucesso.
  • Os dados exibidos vêm do usuário encontrado no vetor pelo backend.

Cuidado importante: header() precisa ser chamado antes de qualquer saída HTML ou echo. Se a página já tiver enviado conteúdo ao navegador, o redirecionamento falha.

Prática 05 — Função hash e senha criptografada

Até aqui, o arquivo usuarios.php guardava a senha exatamente como ela era digitada. Isso ajuda a entender o fluxo inicial, mas não é adequado para uma aplicação real. Na prática, não armazenamos a senha em claro: armazenamos um hash da senha.

O que é hash

Uma função de hash recebe um texto e gera uma sequência fixa de caracteres. Se a entrada for a mesma, o resultado será o mesmo. Por isso, o servidor consegue comparar o hash da senha digitada com o hash salvo no cadastro.

A ideia importante é: o usuário continua digitando a senha normal no formulário, mas o backend transforma essa senha com hash("sha256", $senhaDigitada) antes de comparar com o valor armazenado.

Essa estratégia é importante pois se alguém visualizar o arquivo de usuários (ou so dados no banco de dados), não verá as senhas originais em claro. Verá apenas os hashes. Nesta prática, vamos usar sha256 para entender a ideia.

Passo a passo
  1. Abra usuarios.php e troque as senhas em claro pelos hashes abaixo.
  2. Abra autenticar.php e calcule o hash da senha recebida pelo formulário.
  3. Compare o login digitado com $usuario["login"] e o hash calculado com $usuario["senha"].
  4. Teste usando as senhas originais: 1234, abcd e 9999.
Arquivo usuarios.php
<?php
$usuarios = [
    [
        "id" => 1,
        "login" => "ana",
        "senha" => "03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4",
        "nome" => "Ana Souza",
        "perfil" => "aluno"
    ],
    [
        "id" => 2,
        "login" => "bruno",
        "senha" => "88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589",
        "nome" => "Bruno Lima",
        "perfil" => "monitor"
    ],
    [
        "id" => 3,
        "login" => "carla",
        "senha" => "888df25ae35772424a560c7152a1de794440e0ea5cfee62828333a456a506e05",
        "nome" => "Carla Rocha",
        "perfil" => "professor"
    ]
];
?>
Arquivo autenticar.php
<?php
require "usuarios.php";

$loginDigitado = $_POST["login"];
$senhaDigitada = $_POST["senha"];
$hashSenhaDigitada = hash("sha256", $senhaDigitada);

$usuarioEncontrado = null;

foreach ($usuarios as $usuario) {
    if ($usuario["login"] === $loginDigitado && $usuario["senha"] === $hashSenhaDigitada) {
        $usuarioEncontrado = $usuario;
    }
}

if ($usuarioEncontrado === null) {
    header("Location: login.php?erro=1");
    exit;
}

?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Painel</title>
</head>
<body>
    <h1>Área autenticada</h1>
    <p>Bem-vindo, <?php echo htmlspecialchars($usuarioEncontrado["nome"]); ?>.</p>
    <p>Seu perfil é: <?php echo htmlspecialchars($usuarioEncontrado["perfil"]); ?>.</p>
    <p><a href="login.php">Voltar ao login</a></p>
</body>
</html>
Conferindo a mudança

A senha de Ana ainda é 1234, mas o arquivo guarda 03ac674216f3e15c761ee1a5e255f067953623c8b388b4459e13f978d7c846f4. Quando Ana digita 1234, o PHP calcula o mesmo hash e a comparação passa.

Se a senha digitada for diferente, o hash gerado também será diferente, e o usuário será redirecionado de volta para login.php?erro=1.

Discussão 01 — Entendendo o limite deste modelo

Neste modelo, não existe uma segunda página protegida. A área autenticada é o trecho de HTML que aparece no final de autenticar.php, depois da validação.

Regra de leitura do autenticar.php
if ($usuarioEncontrado === null) {
    header("Location: login.php?erro=1");
    exit;
}

// Se chegou aqui, o backend já validou login e senha.
// O HTML abaixo só será gerado no caso de sucesso.
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Sistema interno</title>
</head>
<body>
    <h1>Bem-vindo ao sistema interno</h1>

    <p>Olá, <?php echo htmlspecialchars($usuarioEncontrado["nome"]); ?>.</p>
    <p>Login: <?php echo htmlspecialchars($usuarioEncontrado["login"]); ?></p>
    <p>Perfil: <?php echo htmlspecialchars($usuarioEncontrado["perfil"]); ?></p>

    <p>Você está visualizando uma área gerada pelo backend após a autenticação.</p>
    <p><a href="login.php">Voltar ao login</a></p>
</body>
</html>

Neste fluxo, o HTML autenticado fica dentro de autenticar.php e só é executado depois que o backend compara POST com o vetor de usuários. O navegador envia os dados; o PHP decide se gera ou não gera a resposta de sucesso.

Limite importante: sem sessão, conceito que ainda será trabalhado, o login não fica guardado entre páginas ou entre requisições. Este modelo serve para entender a decisão do backend, não para manter um usuário navegando autenticado por várias telas.

Discussão 02 — Preparando a evolução da aplicação

O sistema já cumpre o objetivo desta prática: mostrar o caminho completo do formulário até a decisão de acesso. A próxima etapa será melhorar esse modelo.

Mapa de substituições para as próximas aulas

Hoje: require "usuarios.php" carrega um vetor hardcoded.

Depois: esse ponto pode virar uma consulta no banco e retornar os usuários.

Versão inicial: a comparação usa $usuario["senha"] === $senhaDigitada.

Evolução imediata: esse ponto passa a comparar o hash salvo com hash("sha256", $senhaDigitada).

Hoje: cada usuário é um array associativo.

Depois: cada usuário pode virar objeto.

Hoje: o HTML autenticado fica no próprio autenticar.php.

Depois: a aplicação pode usar sessão para manter o login entre várias páginas.

Desafio final: adicione o campo turma em cada usuário, e exiba esse valor no HTML de sucesso gerado por autenticar.php.

Exercício 01 — Adicionando um novo usuário

Este exercício parte do sistema já pronto. O objetivo é alterar apenas o vetor de usuários e observar como isso já modifica o comportamento do login.

Tarefa

Adicione um novo usuário em usuarios.php com os campos id, login, senha, nome e perfil. Em seguida, teste o login com esse novo cadastro.

Arquivos envolvidos
  • usuarios.php para cadastrar o novo registro.
  • login.php para testar o formulário com o novo login.
  • autenticar.php para observar que a lógica não precisa ser alterada.
usuarios.php
<?php
$usuarios = [
    [
        "id" => 1,
        "login" => "ana",
        "senha" => "123",
        "nome" => "Ana Souza",
        "perfil" => "aluno"
    ],
    [
        "id" => 2,
        "login" => "bruno",
        "senha" => "456",
        "nome" => "Bruno Lima",
        "perfil" => "professor"
    ],
    [
        // Novo usuário adicionado ao vetor.
        // A lógica de autenticação não muda: o foreach já percorre todos os registros.
        "id" => 3,
        "login" => "carla",
        "senha" => "789",
        "nome" => "Carla Mendes",
        "perfil" => "aluno"
    ]
];
?>

Exercício 02 — Exibindo um novo campo

Agora o objetivo é ampliar a estrutura de dados do usuário e acompanhar essa mudança no fluxo até o HTML de sucesso.

Tarefa

Adicione o campo turma em todos os usuários do vetor. Depois, altere autenticar.php para que esse valor também seja exibido no HTML gerado em caso de sucesso.

Arquivos envolvidos
  • usuarios.php para incluir o novo campo.
  • autenticar.php para exibir a informação após validar o login.
usuarios.php e autenticar.php
<?php
// usuarios.php
// O campo turma passa a fazer parte de cada usuário.
$usuarios = [
    [
        "id" => 1,
        "login" => "ana",
        "senha" => "123",
        "nome" => "Ana Souza",
        "perfil" => "aluno",
        "turma" => "3INFOA"
    ],
    [
        "id" => 2,
        "login" => "bruno",
        "senha" => "456",
        "nome" => "Bruno Lima",
        "perfil" => "professor",
        "turma" => "3INFOB"
    ]
];

// autenticar.php
// Depois da validação, o novo campo pode ser exibido no HTML de sucesso.
?>
<p>Turma: <?php echo htmlspecialchars($usuarioEncontrado["turma"]); ?></p>

Exercício 03 — Melhorando as mensagens de erro

Neste exercício, o foco é refinar a resposta do sistema quando o login falha. Em vez de uma mensagem genérica, o código deve explicar melhor o motivo do erro.

Tarefa

Altere o sistema para diferenciar pelo menos dois erros: login inexistente e senha incorreta. Depois, faça login.php mostrar uma mensagem apropriada para cada caso.

Arquivos envolvidos
  • autenticar.php para identificar os diferentes cenários de falha.
  • login.php para ler o parâmetro de erro e exibir a mensagem correta.
Dicas
  • Primeiro procure apenas pelo login digitado, sem comparar a senha.
  • Se nenhum usuário tiver esse login, redirecione com um erro específico, como erro=login.
  • Se o login existir, compare a senha desse usuário com a senha digitada.
  • Se a senha estiver errada, redirecione com outro erro, como erro=senha.
  • Em login.php, use o valor de $_GET["erro"] para escolher qual mensagem mostrar.
autenticar.php
<?php
require "usuarios.php";

$loginDigitado = $_POST["login"];
$senhaDigitada = $_POST["senha"];

$usuarioEncontrado = null;

foreach ($usuarios as $usuario) {
    // Primeiro procuramos apenas pelo login.
    if ($usuario["login"] === $loginDigitado) {
        $usuarioEncontrado = $usuario;
    }
}

if ($usuarioEncontrado === null) {
    // O login digitado não existe no vetor.
    header("Location: login.php?erro=login");
    exit;
}

if ($usuarioEncontrado["senha"] !== $senhaDigitada) {
    // O login existe, mas a senha não confere.
    header("Location: login.php?erro=senha");
    exit;
}

// Se chegou aqui, login e senha estão corretos.
?>
login.php
<?php
if (isset($_GET["erro"]) && $_GET["erro"] === "login") {
    echo '<p style="color: red;">Login inexistente.</p>';
} elseif (isset($_GET["erro"]) && $_GET["erro"] === "senha") {
    echo '<p style="color: red;">Senha incorreta.</p>';
}
?>

Exercício 04 — Exibindo HTML por perfil

Agora o login deve continuar validando usuário e senha, mas o HTML de sucesso dependerá do perfil encontrado pelo backend.

Tarefa

Modifique autenticar.php para exibir uma área interna diferente dependendo do campo perfil do usuário autenticado.

Se o perfil for aluno, mostre um HTML com conteúdo da área dos alunos. Se o perfil for professor, mostre um HTML com conteúdo da área dos professores. Não use redirecionamento para outras páginas neste exercício.

Arquivos envolvidos
  • autenticar.php para validar login e senha e depois escolher qual HTML mostrar.
  • login.php continua sendo usado apenas quando a autenticação falha.
Dicas
  • Depois que $usuarioEncontrado deixar de ser null, verifique $usuarioEncontrado["perfil"].
  • Use um if para o perfil aluno e outro para o perfil professor.
  • Dentro de cada if, feche o PHP com ?>, escreva o HTML daquele perfil e volte para o PHP se precisar continuar.
  • Esse modelo evita criar páginas separadas que precisariam de sessão para serem protegidas corretamente.
autenticar.php
<?php
require "usuarios.php";

$loginDigitado = $_POST["login"];
$senhaDigitada = $_POST["senha"];

$usuarioEncontrado = null;

foreach ($usuarios as $usuario) {
    // Primeiro autentica: login e senha precisam existir no backend.
    if ($usuario["login"] === $loginDigitado && $usuario["senha"] === $senhaDigitada) {
        $usuarioEncontrado = $usuario;
    }
}

if ($usuarioEncontrado === null) {
    // Se não autenticou, volta para o formulário.
    header("Location: login.php?erro=1");
    exit;
}

// A partir daqui, o usuário já foi autenticado.
// Agora vem a autorização: qual HTML este perfil pode ver?

if ($usuarioEncontrado["perfil"] === "aluno") {
    // Se o perfil for aluno, geramos o HTML da área dos alunos.
    ?>
    <!DOCTYPE html>
    <html lang="pt-BR">
    <body>
        <h1>Área dos alunos</h1>
        <p>Bem-vindo, <?php echo htmlspecialchars($usuarioEncontrado["nome"]); ?>.</p>
        <p>Aqui ficam materiais, atividades e avisos para estudantes.</p>
    </body>
    </html>
    <?php
}

if ($usuarioEncontrado["perfil"] === "professor") {
    // Se o perfil for professor, geramos o HTML da área dos professores.
    ?>
    <!DOCTYPE html>
    <html lang="pt-BR">
    <body>
        <h1>Área dos professores</h1>
        <p>Bem-vindo, <?php echo htmlspecialchars($usuarioEncontrado["nome"]); ?>.</p>
        <p>Aqui ficam lançamento de notas, turmas e materiais administrativos.</p>
    </body>
    </html>
    <?php
}

// Se o perfil não for reconhecido, exibimos uma mensagem simples.
if ($usuarioEncontrado["perfil"] !== "aluno" && $usuarioEncontrado["perfil"] !== "professor") {
    echo "Perfil não reconhecido.";
}
?>

Observação importante: em uma aplicação melhor organizada, o ideal seria redirecionar o usuário para páginas separadas, como area_aluno.php e area_professor.php.

if ($usuarioEncontrado["perfil"] === "aluno") {
    header("Location: area_aluno.php");
    exit;
}

if ($usuarioEncontrado["perfil"] === "professor") {
    header("Location: area_professor.php");
    exit;
}

O problema é que, se fizermos apenas isso agora, qualquer pessoa poderia abrir area_aluno.php ou area_professor.php diretamente pela URL, sem passar pelo login.

Para proteger essas páginas separadas, precisamos de um mecanismo que mantenha no servidor a informação de que aquele usuário já foi autenticado. Esse mecanismo é a sessão, assunto da próxima aula.

Referência rápida

Use esta tabela para revisar os termos centrais da prática.

Termo Significado
HTTP stateless Cada requisição é independente. O servidor responde uma requisição por vez.
$_POST Array superglobal que recebe os dados enviados por formulário com método POST.
header("Location: ...") Adiciona um cabeçalho Location à resposta para orientar o navegador a fazer uma nova requisição.
exit Interrompe o script para que nenhum HTML seja gerado depois do redirecionamento.
require Carrega um arquivo obrigatório, como a base de usuários ou funções de apoio.
array associativo Estrutura que guarda dados com chaves nomeadas, como login, senha e perfil.
=== Compara valor e tipo. Útil para verificar exatamente se algo ainda é null.
autenticação Processo de comparar os dados enviados pelo formulário com os dados cadastrados no servidor.
hash Resultado gerado por uma função que transforma a senha digitada em uma sequência usada para comparação.
hash("sha256", $senha) Função usada nesta prática para gerar o hash da senha antes de comparar com o valor salvo.