PHP Projetos

Nas aulas, você aprendeu uma peça de cada vez. Nos projetos, as peças se juntam: cada um é um pequeno sistema que funciona de verdade, construído em etapas, do arquivo vazio até o código completo. É aqui que "eu entendi a aula" vira "eu sei fazer".

Nesta página
  • Os seis projetos, em que ordem fazer e quais aulas cada um usa.
  • Como uma página de projeto é organizada.
  • Como rodar os projetos no seu computador com o php -S e testar com o navegador ou com o curl.
  • O "esqueleto" que todos os projetos repetem, para você praticar antes de começar.

Os projetos

Faça na ordem: cada projeto reaproveita o que o anterior ensinou. Os quatro primeiros pedem só o Nível 1 e a parte de formulários do Nível 2; o login e os seguintes usam banco de dados e sessão.

ProjetoO que você constróiAulas que ele usa
Calculadora WebDois números, quatro operações, resultado no formato 1.234,50; validação e divisão por zeroPHP Dentro do HTML, Formulários, $_GET e $_POST, match, Validar Dados, Escapar a Saída, Formatar Números
Formulário de ContatoFormulário com erros ao lado de cada campo, mensagens salvas em CSV ou JSON, sem envio duplicadoValidar Dados, mbstring, Arquivos, CSV, JSON, Redirecionamento, Datas
Login com SessãoCadastro, login, área restrita e logout, com senha em hash, sessão renovada e token CSRFSessões, Cookies, Senhas, CSRF, PDO, Prepared Statements, include e require
Tarefas com SQLiteLista de tarefas com criar, listar, marcar, editar e excluir (CRUD); uma injeção de SQL demonstrada e evitadaBanco de Dados, PDO, CRUD com PDO, Prepared Statements
Mini BlogPosts no SQLite, página de cada post, formulário de novo post, cabeçalho e rodapé incluídos, paginaçãoinclude e require, CRUD com PDO, Prepared Statements, $_GET e $_POST, Escapar a Saída, Datas
API RESTUma API de tarefas em JSON, com GET, POST, PUT e DELETE e os códigos de status certos, testada com o curlJSON, $_SERVER, Criar uma API JSON, PDO, Prepared Statements

Se uma aula da lista ainda não foi feita, faça-a antes: o projeto explica cada linha nova, mas não repete a aula inteira.

Como uma página de projeto é organizada

  1. Antes de começar: o que o projeto usa e as aulas de cada coisa; os arquivos do projeto.
  2. As etapas: o projeto cresce uma novidade por vez. Cada etapa mostra só o código novo, explica cada parte (tabela ou "anatomia"), mostra a saída real (conferida com o PHP 8.5 rodando de verdade) e termina com uma caixa Experimente, que tem o arquivo completo daquela etapa e uma missão.
  3. Quando dá errado: as mensagens de erro que aparecem nesse tipo de projeto, com a mensagem completa, o que ela quer dizer e como consertar.
  4. O código completo: a versão final, para copiar e comparar com a sua.
  5. Desafios extras (sem resposta pronta), uma missão final, exercícios e resumo.

As caixas "Experimente" dos projetos

Nos projetos, as caixas funcionam no modo web: o código roda como uma página de site, servida pelo PHP de verdade dentro do seu navegador (veja O Editor do Guia).

  • A aba Resultado mostra a página como o navegador mostraria. Formulários, links e redirecionamentos funcionam, e a sessão, os cookies e o banco SQLite continuam existindo entre um clique e outro, até você rodar de novo.
  • A aba Código-fonte HTML mostra o HTML que o PHP gerou (é o que o curl mostra no terminal).
  • Quando o projeto tem vários arquivos, cada um é uma aba do editor. O primeiro é a página que abre.
  • Muitas caixas já começam com um envio de formulário pronto (por exemplo, "dividir 10 por 4"), para a missão poder ser conferida na hora. Depois disso, use o formulário na aba Resultado à vontade.

Rodando no seu computador

Você não precisa instalar um servidor como o Apache para estudar: o próprio PHP tem um servidor embutido (veja O Servidor Embutido). A rotina de todo projeto é esta:

  1. Crie uma pasta para o projeto e salve os arquivos nela.
  2. Num terminal, entre na pasta e suba o servidor. Deixe esse terminal aberto: ele é o servidor, e cada visita aparece nele.
  3. Abra http://localhost:8000 no navegador.
  4. Para parar o servidor, volte ao terminal dele e aperte Ctrl+C.

Um exemplo pequeno, com o mesmo formato dos projetos (o index.php da caixa logo abaixo):

$ mkdir ola
$ cd ola
$ nano index.php                        « cole o código e salve
$ php -S localhost:8000
[Fri Oct 16 21:09:29 2026] PHP 8.5.8 Development Server (http://localhost:8000) started
[Fri Oct 16 21:09:30 2026] 127.0.0.1:49694 Accepted
[Fri Oct 16 21:09:30 2026] 127.0.0.1:49694 [200]: GET /
[Fri Oct 16 21:09:30 2026] 127.0.0.1:49694 Closing
[Fri Oct 16 21:09:30 2026] 127.0.0.1:49700 Accepted
[Fri Oct 16 21:09:30 2026] 127.0.0.1:49700 [200]: GET /?nome=Ana
[Fri Oct 16 21:09:30 2026] 127.0.0.1:49700 Closing

Cada visita gera três linhas: a conexão aceita (Accepted), o pedido com o código da resposta ([200]: GET /?nome=Ana) e o fim da conexão (Closing). Quando o PHP der um erro fatal, ele também aparece aqui, no fim da linha do pedido.

Testando com o curl

Nas páginas dos projetos, as saídas foram conferidas com o curl, um programa de terminal que faz o papel do navegador e mostra o HTML que chegou. Ele é ótimo para ver exatamente o que o PHP respondeu. Use-o num segundo terminal, com o servidor rodando no primeiro:

$ curl -s localhost:8000/
<!DOCTYPE html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Olá</title></head>
<body>
  <form>
    <input name="nome" placeholder="Seu nome">
    <button>Enviar</button>
  </form>
</body>
</html>
$ curl -s "localhost:8000/?nome=Ana" | grep Olá
<head><meta charset="utf-8"><title>Olá</title></head>
  <p>Olá, Ana!</p>
$ curl -si "localhost:8000/?nome=Ana" | head -6
HTTP/1.1 200 OK
Host: localhost:8000
Date: Sat, 17 Oct 2026 00:09:30 GMT
Connection: close
X-Powered-By: PHP/8.5.8
Content-type: text/html; charset=UTF-8
Como aparece nos projetosO que faz
curl -s URLBusca a página (GET) e mostra o HTML. O -s (silent) esconde a barra de progresso.
curl -s -d 'a=10&b=4' URLEnvia um formulário por POST com esses campos, como um clique no botão.
curl -si URLO -i mostra também os cabeçalhos da resposta (código, Location, Set-Cookie…).
curl -sL URLO -L segue redirecionamentos, como o navegador.
curl -c jar.txt -b jar.txt URLGuarda (-c) e devolve (-b) os cookies num arquivo: é assim que o curl "continua logado" entre um comando e outro.
… | grep textoMostra só as linhas do HTML que contêm o texto, para não encher a tela.
… | tail -5, … | head -8Só as últimas 5 / as primeiras 8 linhas.
Navegador ou curl?

Use o navegador para usar o projeto, e o curl quando quiser ver por dentro: os cabeçalhos de um redirecionamento, o cookie da sessão, o HTML exato de um campo escapado. No navegador, o equivalente é a ferramenta do desenvolvedor (F12, aba Rede).

Caixa livre: este é o index.php do exemplo. A caixa já abre com ?nome=Ana; clique em voltar ou rode de novo e use o formulário com o seu nome. Veja também a aba Código-fonte HTML.

<?php
$nome = trim($_GET['nome'] ?? '');
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Olá</title></head>
<body>
<?php if ($nome === ''): ?>
  <form>
    <input name="nome" placeholder="Seu nome">
    <button>Enviar</button>
  </form>
<?php else: ?>
  <p>Olá, <?= htmlspecialchars($nome) ?>!</p>
<?php endif; ?>
</body>
</html>

O esqueleto de todo projeto

Repare na forma do arquivo, porque ela vai se repetir em todos os projetos:

  1. No topo, só PHP: ler o que chegou ($_GET, $_POST), validar, gravar, redirecionar. Nada é impresso aqui.
  2. Embaixo, o HTML: com pedacinhos de PHP só para mostrar (<?= … ?>) e decidir o que aparece (<?php if (…): ?> … <?php endif; ?>).
  3. Tudo que veio do usuário passa por htmlspecialchars antes de ir para a página.

Essa separação não é enfeite: funções como header() (redirecionar) e session_start() só funcionam antes de a página começar a sair. Com o PHP todo no topo, isso fica garantido.

Missão: mostre o nome em letras maiúsculas: Olá, ANA!. Use mb_strtoupper($nome) (a versão que entende acentos: experimente depois com "Zé") e não tire o htmlspecialchars.

<?php
$nome = trim($_GET['nome'] ?? '');
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Olá</title></head>
<body>
<?php if ($nome === ''): ?>
  <form>
    <input name="nome" placeholder="Seu nome">
    <button>Enviar</button>
  </form>
<?php else: ?>
  <p>Olá, <?= htmlspecialchars($nome) ?>!</p>
<?php endif; ?>
</body>
</html>
<?php
$nome = trim($_GET['nome'] ?? '');
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Olá</title></head>
<body>
<?php if ($nome === ''): ?>
  <form>
    <input name="nome" placeholder="Seu nome">
    <button>Enviar</button>
  </form>
<?php else: ?>
  <p>Olá, <?= htmlspecialchars(mb_strtoupper($nome)) ?>!</p>
<?php endif; ?>
</body>
</html>

Quando dá errado

Failed to listen on localhost:8000 (reason: Address in use)
$ php -S localhost:8000
[Fri Oct 16 21:09:30 2026] Failed to listen on localhost:8000 (reason: Address in use)

O que significa: "endereço em uso": outro programa já está usando a porta 8000, quase sempre um php -S de outro projeto, esquecido noutro terminal. Como consertar: pare o outro (Ctrl+C no terminal dele) ou use outra porta: php -S localhost:8001 e http://localhost:8001.

O navegador mostra o código PHP, ou baixa o arquivo

Você abriu o arquivo direto (endereço começando com file://). Só o servidor executa o PHP: abra http://localhost:8000.

Qualquer endereço mostra o index.php
$ curl -s localhost:8000/nada.php
<!DOCTYPE html>
<html lang="pt-BR">
<head><meta charset="utf-8"><title>Olá</title></head>
<body>
  <form>
    <input name="nome" placeholder="Seu nome">
    <button>Enviar</button>
  </form>
</body>
</html>

Não existe nada.php, mas o servidor embutido, quando não acha o arquivo pedido, responde com o index.php da pasta. Se um link "não funciona" e você sempre volta à página inicial, confira o nome do arquivo no link.

Mudei o código e nada mudou

Confira se você salvou o arquivo, se o servidor está rodando na pasta certa (a pasta onde você deu o php -S) e recarregue a página. Num formulário, recarregar com F5 depois de um envio pode reenviar os dados: abra o endereço de novo em vez disso.

Exercícios

Complete o comando que sobe o servidor embutido na porta 8000:

php localhost:8000

Qual opção do curl envia um formulário por POST?

Por que os projetos põem todo o PHP de "processar" no topo do arquivo, antes do HTML?

Resumo

  • Seis projetos, na ordem: calculadora, contato, login, tarefas, blog e API.
  • Cada um cresce em etapas: código novo explicado, saída real e uma caixa Experimente com missão.
  • No seu computador: php -S localhost:8000 na pasta do projeto, http://localhost:8000 no navegador, Ctrl+C para parar.
  • O curl mostra a resposta por dentro: -d envia POST, -i mostra cabeçalhos, -L segue redirecionamentos, -c/-b guardam cookies.

Comece pela Calculadora Web.