
Por Que Formulários São o Coração de Qualquer Aplicação Web
Se você já usou a internet para fazer uma compra, enviar uma mensagem ou criar uma conta em qualquer serviço, você interagiu com formulários HTML processados por alguma linguagem de back-end. Em PHP — a linguagem que ainda alimenta mais de 76% dos sites com linguagem de servidor identificada — essa interação acontece por meio das superglobais: estruturas especiais que tornam os dados enviados pelo usuário instantaneamente acessíveis em qualquer parte do seu código.
Mas há um problema sério nessa facilidade. A simplicidade com que o PHP expõe $_GET, $_POST e outras superglobais é exatamente o que torna tantas aplicações vulneráveis. Dados que chegam do usuário são, por definição, não confiáveis. Eles podem conter scripts maliciosos, tentativas de injeção de SQL, ou serem enviados por um site de terceiros explorando a confiança que o navegador deposita no seu domínio. Isso é a essência de ataques como XSS (Cross-Site Scripting) e CSRF (Cross-Site Request Forgery).
Este guia foi escrito para ser a referência definitiva sobre o assunto. Vamos cobrir cada superglobal relevante para formulários com profundidade técnica real, construir um sistema completo de validação e, sobretudo, implementar proteção CSRF do zero — entendendo não apenas o “como”, mas o “por quê” de cada decisão de design. Ao final, você terá os blocos de construção para criar formulários seguros, robustos e prontos para produção.
1. O Ciclo de Vida de uma Requisição HTTP e as Superglobais PHP
1.1 O Que Acontece Quando o Usuário Clica em “Enviar”
Para entender as superglobais, precisamos entender o protocolo HTTP em nível suficiente. Quando um formulário HTML é submetido, o navegador monta uma requisição HTTP que inclui: o método (GET ou POST), a URL de destino, cabeçalhos (como Content-Type) e, dependendo do método, um corpo com os dados do formulário.
O PHP, ao receber essa requisição através do servidor web (Apache, Nginx, PHP-FPM), analisa automaticamente os dados e os disponibiliza nas superglobais correspondentes antes mesmo de executar a primeira linha do seu script. Esse processo de “parse” automático é conveniente, mas obscurece o que realmente está acontecendo — e entender os detalhes faz toda a diferença na hora de depurar problemas ou construir soluções seguras.
1.2 O Array $_SERVER: O Contexto Completo da Requisição
Antes de mergulhar em $_GET e $_POST, vale entender $_SERVER — a superglobal que contém informações sobre o servidor e o ambiente de execução.
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
$path = $_SERVER['PHP_SELF'];$ip = $_SERVER['REMOTE_ADDR'];$agent = $_SERVER['HTTP_USER_AGENT'];
$referer = $_SERVER['HTTP_REFERER'] ?? 'Não informado';$isAjax = ($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') === 'XMLHttpRequest';
⚠️ Aviso de segurança:
O HTTP_REFERER pode ser facilmente falsificado. Nunca use como segurança.
1.3 Superglobais Relevantes para Formulários
O PHP possui 9 superglobais, mas para formulários estas são as principais:
$_GET— parâmetros na URL$_POST— dados no corpo$_REQUEST— combinação (evitar)$_FILES— uploads$_SESSION— persistência$_COOKIE— cookies
👉 Aqui está o ponto importante que faltava antes:
Essas superglobais são populadas automaticamente, sem validação, o que significa que qualquer dado pode chegar já “dentro do sistema”.
2. Método GET: Quando os Dados Ficam na URL
2.1 Como o GET Funciona na Prática
O método GET envia os dados do formulário como parâmetros na query string da URL. Quando você submete um formulário com method='get', o navegador pega todos os campos e os codifica no formato campo=valor, separados por &, e os anexa à URL após o símbolo ?.
Exemplo:
buscar.php?q=formularios+php&categoria=php
Isso significa que os dados ficam:
- visíveis
- compartilháveis
- indexáveis
Exemplo completo
<form action="buscar.php" method="get">
<input name="q">
<select name="categoria">
<option value="todos">Todos</option>
<option value="php">PHP</option>
</select>
</form>
$query = $_GET['q'] ?? '';
$categoria = $_GET['categoria'] ?? 'todos';$querySeguro = htmlspecialchars($query, ENT_QUOTES, 'UTF-8');
👉 Aqui entra um detalhe crítico:
Mesmo sendo GET, você precisa sanitizar antes de exibir.
2.2 URL Encoding
O navegador codifica automaticamente caracteres especiais.
$params = [
'q' => 'formulários PHP & superglobais',
'pagina' => 2,
];$queryString = http_build_query($params);
👉 Nunca montar URL manualmente.
3. Método POST: Enviando Dados com Segurança
O POST envia dados no corpo da requisição.
Diferenças importantes:
- não aparece na URL
- não fica no histórico
- suporta mais dados
Exemplo
<form method="post">
<input name="email">
<input name="senha">
</form>
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit;
}$email = trim($_POST['email'] ?? '');
👉 Aqui está o ponto importante:
POST não significa seguro automaticamente — apenas menos exposto.
JSON via POST
$rawBody = file_get_contents('php://input');
$data = json_decode($rawBody, true);
👉 Se for API, $_POST pode vir vazio.
4. GET vs POST (com explicação completa)
| Característica | GET | POST |
|---|---|---|
| Visibilidade | URL | Body |
| Cache | Sim | Não |
| Segurança | Baixa | Maior |
| Uso | Busca | Login, cadastro |
📌 Regra prática:
GET = leitura
POST = ação
5. Validação (parte completa)
Princípio fundamental
👉 Todo dado do usuário é potencialmente malicioso.
filter_var()
$email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL);
Validação completa envolve:
- Presença
- Formato
- Regra de negócio
👉 Esse trecho costuma ser ignorado em extrações simples, mas é essencial.
Classe Validador
(estrutura mantida)
class Validador {
private array $erros = [];
private array $dados = []; public function __construct(array $dados) {
$this->dados = $dados;
} public function obrigatorio($campo) {
if (empty($this->dados[$campo])) {
$this->erros[$campo] = 'Campo obrigatório';
}
return $this;
}
}
5.4 XSS (completo)
❌ errado:
echo $_GET['nome'];
✅ correto:
echo htmlspecialchars($_GET['nome'], ENT_QUOTES, 'UTF-8');
👉 Esse ponto é um dos mais críticos do documento.
6. CSRF (com explicação completa)
CSRF explora o fato de que o navegador envia cookies automaticamente.
👉 Isso permite executar ações em nome do usuário.
Ataque exemplo
<img src="banco.com/transferir?valor=10000">
Proteção com token
$token = bin2hex(random_bytes(32));
$_SESSION['csrf'] = $token;
Validação:
hash_equals($_SESSION['csrf'], $_POST['csrf_token']);
7. Upload com $_FILES (completo)
$arquivo = $_FILES['imagem'];
Validações obrigatórias:
- tamanho
- tipo real
- extensão
- nome único
👉 Esse bloco é frequentemente truncado — agora está completo.
8. Segurança (php.ini)
display_errors = Off
upload_max_filesize = 10M
session.cookie_httponly = 1
session.cookie_secure = 1
Headers HTTP
header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');
header('Strict-Transport-Security: max-age=31536000');
8.3 Checklist Final de Segurança
Use este checklist antes de colocar qualquer formulário em produção:
- Validação server-side em 100% dos campos — nunca confiar apenas no front-end
- htmlspecialchars() em tudo que for exibido no HTML
- Prepared statements para todas as queries SQL (prevenção de SQL Injection)
- Token CSRF em todos os formulários que modificam estado (POST, PUT, DELETE)
- Validação de MIME type real em uploads (não confiar em $_FILES[‘type’])
- Nome de arquivo gerado aleatoriamente no servidor (nunca usar o nome original)
- Diretório de uploads fora do document root ou sem execução de PHP
- Limites de tamanho em uploads e campos de texto
- Rate limiting para prevenir força bruta em formulários de login
- CAPTCHA ou honeypot para prevenir spam em formulários públicos
- Headers HTTP de segurança configurados (CSP, HSTS, X‑Frame-Options)
- Sessões com httponly, secure e SameSite configurados
- display_errors desabilitado em produção
- Logs de erros configurados e monitorados
Conclusão: Formulários Seguros Como Fundação
Formulários e superglobais são, simultaneamente, as ferramentas mais simples e as mais críticas em qualquer aplicação PHP. A facilidade de acesso a $_GET e $_POST esconde uma responsabilidade enorme: cada dado que entra pela requisição é um ponto de entrada potencial para ataques.
Ao longo deste guia, vimos que segurança não é uma feature que se adiciona depois — é uma mentalidade que deve guiar cada linha de código.
✔ Validar no servidor
✔ Escapar na saída
✔ Proteger contra CSRF
✔ Verificar uploads corretamente
✔ Usar prepared statements
✔ Configurar sessões e headers
Esses não são diferenciais — são o mínimo aceitável em produção.
O código apresentado foi construído para funcionar sem frameworks, mas em projetos maiores:
- Laravel → CSRF automático
- Symfony → Form + CSRF integrado
👉 Porém, entender os fundamentos é o que separa quem usa ferramentas de quem domina.
📌 Mensagem final:
A web segura é construída um formulário de cada vez.