PHP Formulários HTML

Até aqui, os seus programas PHP só falavam: mostravam texto, contas, listas. Com um formulário, o visitante também fala. Ele digita o nome, escolhe um sabor, marca uma opção, clica em Enviar, e o PHP recebe tudo isso para trabalhar. Esta aula é sobre o lado do HTML: como montar o formulário e o que exatamente o navegador manda para o PHP. Na próxima, você vê o lado do PHP em detalhe.

Você vai aprender
  • O que é um formulário e como ele leva dados do navegador até o PHP.
  • A tag <form> e os atributos action (para onde) e method (como).
  • Os campos: <input> (texto, e-mail, número, senha), <select>, <textarea>, checkbox, radio e <button>.
  • Por que o atributo name é o mais importante de todos.
  • O que viaja pela rede: pares nome=valor.
  • A diferença entre GET e POST, e quando usar cada um.
  • Como fazer uma página só que mostra o formulário e processa o envio.

Os exemplos do terminal acontecem na máquina fictícia da Ana (notebook), com o servidor embutido do PHP (php -S, visto em O Servidor Embutido). As caixas Experimente rodam o PHP de verdade no seu navegador, como uma página web: a aba Resultado mostra a página pronta, e os formulários dela funcionam.


A ideia: uma ficha de papel

Pense na ficha que a padaria da Ana usa para anotar encomendas de bolo:

Nome do cliente: ____Bia______________
Sabor:     ( ) cenoura  (x) chocolate  ( ) limão
Entrega?   [x] sim
Observação: __sem açúcar no topo______

Cada linha tem duas partes: um rótulo impresso ("Nome do cliente") e um espaço que o cliente preenche ("Bia"). Quando a ficha chega na cozinha, a confeiteira não lê a ficha inteira como um texto corrido: ela procura o campo "Sabor" e vê o que está marcado.

Um formulário HTML é essa ficha. O navegador desenha os espaços para preencher; quando o visitante clica em Enviar, o navegador junta tudo no formato nome do campo = o que foi preenchido e entrega para um programa PHP (a "cozinha"). O PHP então procura cada campo pelo nome.

  NAVEGADOR (a Ana)                         SERVIDOR (o PHP)
 ┌───────────────────────┐   1. pedido     ┌──────────────────────┐
 │ Nome: [Bia       ]    │ ──────────────▶ │ ola.php              │
 │        [ Enviar ]     │   nome=Bia      │  lê o campo "nome"   │
 └───────────────────────┘                 │  monta uma resposta  │
 ┌───────────────────────┐   2. resposta   │                      │
 │ Olá, Bia!             │ ◀────────────── │ "Olá, Bia!"          │
 └───────────────────────┘   (HTML)        └──────────────────────┘
O formulário fica no navegador; quem processa é o PHP, no servidor. Cada envio é um pedido novo, e o PHP responde com uma página nova.

O primeiro formulário

Este é o menor formulário útil: um campo e um botão. Ele é HTML puro, sem nenhuma linha de PHP:

<form action="ola.php" method="get">
  <label>Seu nome: <input type="text" name="nome"></label>
  <button>Enviar</button>
</form>
<form> … </form>
A "ficha". Tudo o que estiver entre a abertura e o fechamento é enviado junto. Campo fora do <form> não vai.
action="ola.php"
Action = ação. É o endereço do programa que vai receber os dados (a "cozinha"). Aqui, o arquivo ola.php na mesma pasta.
method="get"
Method = método, a forma de entrega: get (os dados vão no endereço) ou post (os dados vão escondidos no corpo do pedido). Você vê a diferença daqui a pouco.
<label>
O rótulo impresso ("Seu nome:"). Envolver o campo com o <label> faz o clique no texto também colocar o cursor no campo, e ajuda leitores de tela. Não é enviado.
<input type="text">
O espaço para digitar (input = entrada). type="text" é uma linha de texto.
name="nome"
O nome do campo. É por esse nome que o PHP vai encontrar o que foi digitado. Sem name, o campo não é enviado.
<button>Enviar</button>
O botão. Dentro de um formulário, um <button> envia o formulário quando é clicado (apertar Enter num campo de texto também envia).

Do outro lado, o ola.php só precisa olhar o que chegou. Por enquanto, vamos apenas espiar com print_r (de var_dump e print_r) o array $_GET, onde o PHP guarda o que veio pelo método GET. A próxima aula, $_GET e $_POST, explica esse array com calma.

<?php
print_r($_GET);

A Ana abriu o servidor na pasta e, no navegador, digitou Ana Maria e clicou em Enviar. O navegador foi para este endereço:

http://localhost:8000/ola.php?nome=Ana+Maria

E a página mostrou:

$ curl -s "localhost:8000/ola.php?nome=Ana+Maria"
Array
(
    [nome] => Ana Maria
)

(O curl pede a mesma página que o navegador pediu, e mostra a resposta no terminal. Vamos usá-lo a aula inteira para ver exatamente o que o PHP recebe e devolve.)

Repare na última parte do endereço: ?nome=Ana+Maria. É o formulário inteiro, "dobrado" dentro da URL. O PHP desdobrou e montou o array com a chave nome e o valor Ana Maria.


O que o navegador envia: pares nome=valor

Quando você clica em Enviar, o navegador percorre os campos do formulário, na ordem, e para cada um que tem name escreve nome=valor. Os pares são ligados por & ("e"):

cliente=Ana&sabor=chocolate&tamanho=M&entrega=on

Alguns caracteres não podem viajar como estão, porque já têm significado nesse formato (& separa pares, = separa nome e valor, o espaço quebraria o endereço). O navegador os codifica:

Você digitaViaja comoPor quê
espaço+Endereços não podem ter espaços.
ã, é, ç%C3%A3, %C3%A9, %C3%A7Letras acentuadas viram os bytes do UTF-8, cada um como % + dois dígitos hexadecimais.
&%26Senão, pareceria o começo de outro par.
=%3DSenão, pareceria a separação entre nome e valor.

Você não precisa fazer nada disso à mão: o navegador codifica na ida e o PHP decodifica na chegada. Mas é bom reconhecer quando vê um endereço cheio de %. O próprio PHP sabe montar esse texto com a função http_build_query (que você usa em $_GET e $_POST):

<?php
echo http_build_query(['nome' => 'Ana Maria', 'cidade' => 'São Paulo', 'obs' => 'café & pão']), "\n";
$ php codifica.php
nome=Ana+Maria&cidade=S%C3%A3o+Paulo&obs=caf%C3%A9+%26+p%C3%A3o

Mesmo com o endereço codificado, o PHP entrega os valores já "limpos":

$ curl -s "localhost:8000/ola.php?nome=Ana+Maria&cidade=S%C3%A3o+Paulo"
Array
(
    [nome] => Ana Maria
    [cidade] => São Paulo
)
Regra para guardar: o que viaja é sempre texto. Mesmo que o campo seja de número, o PHP recebe "29" (uma string), não 29. Converter e conferir é trabalho seu, na aula Validar Dados.

Os campos, um de cada vez

Agora vamos montar a ficha de encomenda da padaria, campo por campo. Para cada tipo, o que importa é: como aparece na tela e o que é enviado.

1. <input>: uma linha

O <input> é o campo mais comum. O atributo type muda a aparência e o teclado (no celular), mas o que chega no PHP é sempre o texto digitado:

<input type="text"     name="cliente" value="Ana">
<input type="email"    name="email"   placeholder="voce@exemplo.com">
<input type="number"   name="qtd"     min="1" max="10">
<input type="password" name="senha">
<input type="hidden"   name="loja"    value="centro">
Atributo / tipoO que faz
type="text"Texto livre, uma linha. É o padrão: <input name="x"> já é texto.
type="email"O navegador confere se tem cara de e-mail antes de enviar.
type="number"Mostra setinhas; min e max limitam a faixa. Chega no PHP como texto ("3").
type="password"Mostra bolinhas no lugar das letras. Só esconde da tela: o valor viaja normalmente.
type="hidden"Campo invisível: o visitante não vê, mas ele é enviado. Serve para mandar junto uma informação fixa.
value="Ana"O texto que já vem preenchido (o visitante pode apagar e trocar).
placeholder="…"Um texto de exemplo, cinza, que some quando a pessoa digita. Não é enviado.
requiredO navegador não deixa enviar com o campo vazio.
Cuidado: required, type="email", min e max são conferidos pelo navegador, como gentileza para o visitante. Quem quiser burlar consegue (o curl manda o que quiser, sem formulário nenhum). O campo hidden também pode ser trocado. O PHP precisa conferir tudo de novo: veja Validar Dados.

2. <select>: uma lista para escolher

<select name="sabor">
  <option value="cenoura">Cenoura com cobertura</option>
  <option value="chocolate" selected>Chocolate</option>
  <option value="limao">Limão</option>
</select>
<select name="sabor">
A caixinha de escolha. O name fica no <select>, não em cada opção.
<option value="cenoura">
Cada opção. O value é o que é enviado; o texto entre as tags é o que o visitante vê. Escolher "Cenoura com cobertura" envia sabor=cenoura.
selected
A opção que já vem escolhida. Sem nenhum selected, vale a primeira.

Se a <option> não tiver value, o navegador envia o texto visível. Prefira sempre colocar value: um texto curto, sem acentos e sem espaços, é mais fácil de conferir no PHP.

3. <textarea>: várias linhas

<textarea name="obs" rows="3" cols="40"></textarea>

Uma caixa de texto grande, para observações, comentários, mensagens. rows e cols são só o tamanho na tela (linhas e colunas). Diferente do <input>, o texto inicial vai entre as tags, não num value. As quebras de linha que o visitante digitar chegam no PHP.

4. Radio: escolher um entre vários

<label><input type="radio" name="tamanho" value="P"> Pequeno</label>
<label><input type="radio" name="tamanho" value="M" checked> Médio</label>
<label><input type="radio" name="tamanho" value="G"> Grande</label>

Os botões radio (as bolinhas) com o mesmo name formam um grupo: marcar um desmarca os outros, como os botões de estação de um rádio antigo (daí o nome). Só o marcado é enviado: tamanho=M. checked deixa um marcado de início. Se nenhum estiver marcado, o grupo não envia nada.

5. Checkbox: sim ou não

<label><input type="checkbox" name="entrega"> Quero entrega</label>

A caixinha de marcar (checkbox). Esta é a parte que mais confunde quem começa:

  • Marcada: envia entrega=on. O on é o valor padrão; com value="sim", envia entrega=sim.
  • Desmarcada: não envia nada. Nem entrega=, nem entrega=off. O campo simplesmente não existe no pedido.

Por isso, no PHP, a pergunta certa não é "qual o valor de entrega?", e sim "entrega chegou?". Você vê como perguntar isso na próxima aula. Para várias caixinhas com o mesmo assunto (as frutas de uma salada, por exemplo), existe o truque do name="frutas[]", também em $_GET e $_POST.

6. <button>: enviar

<button>Enviar</button>
<button type="submit">Enviar</button>    <!-- o mesmo, escrito por extenso -->
<button type="reset">Limpar</button>     <!-- volta os campos ao início, não envia -->
<button type="button">Nada</button>      <!-- não faz nada sozinho (usado com JavaScript) -->

Você também vai ver <input type="submit" value="Enviar"> em códigos mais antigos: faz o mesmo que o <button>. Um botão com name e value também é enviado, mas só o que foi clicado; isso permite dois botões no mesmo formulário (acao=salvar e acao=apagar).

Tudo junto: a ficha de encomenda

<form action="pedido.php" method="post">
  <p><label>Nome: <input type="text" name="cliente" required></label></p>
  <p><label>Sabor:
    <select name="sabor">
      <option value="cenoura">Cenoura com cobertura</option>
      <option value="chocolate">Chocolate</option>
      <option value="limao">Limão</option>
    </select></label></p>
  <p>Tamanho:
    <label><input type="radio" name="tamanho" value="P"> P</label>
    <label><input type="radio" name="tamanho" value="M" checked> M</label>
    <label><input type="radio" name="tamanho" value="G"> G</label></p>
  <p><label><input type="checkbox" name="entrega"> Quero entrega</label></p>
  <p><label>Observação:<br><textarea name="obs" rows="3" cols="40"></textarea></label></p>
  <button>Encomendar</button>
</form>

E um pedido.php que só mostra o que chegou (com method="post", os dados ficam em $_POST, e não em $_GET):

<?php
echo "<pre>";
print_r($_POST);
echo "</pre>";

A Bia encomendou um bolo de chocolate médio, com entrega e uma observação. O navegador enviou o pedido abaixo (o curl -d envia exatamente os mesmos dados, por POST):

$ curl -s localhost:8000/pedido.php -d "cliente=Bia&sabor=chocolate&tamanho=M&entrega=on&obs=Sem+a%C3%A7%C3%BAcar+no+topo%2C+por+favor."
<pre>Array
(
    [cliente] => Bia
    [sabor] => chocolate
    [tamanho] => M
    [entrega] => on
    [obs] => Sem açúcar no topo, por favor.
)
</pre>

Agora a mesma encomenda, sem marcar a entrega e sem escrever observação:

$ curl -s localhost:8000/pedido.php -d "cliente=Bia&sabor=chocolate&tamanho=M&obs="
<pre>Array
(
    [cliente] => Bia
    [sabor] => chocolate
    [tamanho] => M
    [obs] =>          « a textarea vazia chega, com texto vazio
)
</pre>                « e "entrega" nem aparece: checkbox desmarcada não é enviada
CampoPreenchidoVazio / desmarcado
<input type="text">, <textarea>nome=textonome= (chega, vazio)
<select>nome=value da opçãosempre tem uma opção escolhida
radionome=value do marcadonão é enviado
checkboxnome=on (ou o value)não é enviado
campo sem namenunca é enviado
campo com disablednunca é enviado (use readonly se quiser só impedir a edição)

Este é o formulário de encomenda, com action apontando para a própria página. Preencha na aba Resultado, clique em Encomendar e veja o que o PHP recebeu. Depois, desmarque a entrega e envie de novo; tire o name de um campo e veja ele sumir.

<form method="post">
  <p><label>Nome: <input type="text" name="cliente"></label></p>
  <p><label>Sabor:
    <select name="sabor">
      <option value="cenoura">Cenoura com cobertura</option>
      <option value="chocolate">Chocolate</option>
      <option value="limao">Limão</option>
    </select></label></p>
  <p>Tamanho:
    <label><input type="radio" name="tamanho" value="P"> P</label>
    <label><input type="radio" name="tamanho" value="M" checked> M</label>
    <label><input type="radio" name="tamanho" value="G"> G</label></p>
  <p><label><input type="checkbox" name="entrega"> Quero entrega</label></p>
  <p><label>Observação:<br><textarea name="obs" rows="3" cols="40"></textarea></label></p>
  <button>Encomendar</button>
</form>

<h3>O que o PHP recebeu</h3>
<pre><?php print_r($_POST); ?></pre>

GET ou POST?

Os dois métodos levam os mesmos pares nome=valor. A diferença é onde eles vão.

GET (pegar): os dados vão no endereço, depois do ?. É como escrever o pedido no lado de fora do envelope: qualquer um que olhe vê.

GET /ola.php?nome=Ana HTTP/1.1
Host: localhost:8000

POST (postar, como no correio): o endereço fica limpo e os dados vão no corpo do pedido, dentro do envelope. O curl -v mostra o pedido que sai (linhas com >); repare no Content-Type e no Content-Length: 25, o tamanho do corpo:

$ curl -sv -d "nome=Ana&senha=segredo123" localhost:8000/ola.php -o /dev/null 2>&1 | grep '^[>}]'
> POST /ola.php HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/8.18.0
> Accept: */*
> Content-Length: 25
> Content-Type: application/x-www-form-urlencoded
>
} [25 bytes data]          « o corpo: nome=Ana&senha=segredo123 (25 letras)

O application/x-www-form-urlencoded é o nome oficial do formato nome=valor&nome=valor codificado. É o que todo formulário usa, a não ser que envie arquivos (veja Upload de Arquivos).

Uma diferença que pouca gente nota: o servidor anota cada endereço pedido no registro dele (o log). Veja o que o php -S da Ana escreveu quando recebeu um login por GET e outro por POST:

[Fri Oct 16 20:46:40 2026] 127.0.0.1:59658 [200]: GET /ola.php?usuario=ana&senha=segredo123
[Fri Oct 16 20:46:40 2026] 127.0.0.1:59670 [200]: POST /ola.php

A senha enviada por GET ficou gravada no log, em texto puro. A do POST, não. O mesmo vale para o histórico do navegador e para os favoritos: eles guardam o endereço inteiro.

GETPOST
Onde vão os dadosNo endereço: ola.php?nome=AnaNo corpo do pedido; o endereço fica ola.php
Aparece na barra de endereçoSimNão
TamanhoLimitado: endereços muito longos são recusados (fique abaixo de uns 2 mil caracteres)Grande (o PHP aceita até post_max_size, 8 MB por padrão)
Favoritos e linksDá para salvar e compartilhar o resultado (busca.php?q=bolo)Não dá: o favorito guarda só o endereço, sem os dados
Histórico e logs do servidorGuardam os dados junto com o endereçoGuardam só o endereço
Senhas e dados pessoaisNuncaSim (com HTTPS)
Apertar F5 no resultadoPede de novo, sem perguntarO navegador pergunta se quer reenviar o formulário
Arquivos (upload)NãoSim
Use paraConsultar: buscas, filtros, páginas de uma listaMudar algo: cadastrar, comprar, enviar mensagem, login
A regra prática: se enviar duas vezes não faz mal nenhum (buscar "bolo" de novo), use GET. Se enviar duas vezes cria problema (duas encomendas, duas cobranças), use POST. O problema do F5 reenviando um POST tem solução própria, o padrão Post/Redirect/Get, em header e Redirecionamento.

Se o method faltar (ou estiver escrito errado), o navegador usa GET. Se o action faltar, o formulário é enviado para a mesma página em que está. Esses dois "padrões" são usados o tempo todo, como você vê agora.


A mesma página mostra e processa

Ter dois arquivos (form.html e ola.php) funciona, mas é comum fazer tudo num arquivo só: a página mostra o formulário e, quando ele volta preenchido, mostra também a resposta. Para isso, deixe o action de fora (ou vazio) e pergunte ao PHP se o campo chegou, com isset ("está definido?", de null):

<!doctype html>
<html lang="pt-BR">
<body>
<h1>Boas-vindas</h1>
<?php if (isset($_GET['nome'])): ?>
  <p>Olá, <?= htmlspecialchars($_GET['nome']) ?>!</p>
<?php endif; ?>
<form method="get">
  <label>Seu nome: <input type="text" name="nome"></label>
  <button>Enviar</button>
</form>
</body>
</html>
LinhaO que faz
<?php if (isset($_GET['nome'])): ?>"Chegou um campo nome?" Na primeira visita, não chegou nada, e o parágrafo é pulado.
<?= htmlspecialchars($_GET['nome']) ?>Escreve o nome recebido. O htmlspecialchars é uma proteção obrigatória sempre que você mostra algo que veio do visitante; o motivo está em Escapar a Saída (XSS).
<?php endif; ?>Fim do if (a forma com : e endif, de PHP Dentro do HTML).
<form method="get">Sem action: envia para o próprio index.php.

Primeira visita (sem nada no endereço) e depois do envio:

$ curl -s localhost:8000/
<!doctype html>
<html lang="pt-BR">
<body>
<h1>Boas-vindas</h1>
<form method="get">
  <label>Seu nome: <input type="text" name="nome"></label>
  <button>Enviar</button>
</form>
</body>
</html>
$ curl -s "localhost:8000/?nome=Ana"
<!doctype html>
<html lang="pt-BR">
<body>
<h1>Boas-vindas</h1>
  <p>Olá, Ana!</p>          « só aparece quando "nome" chegou
<form method="get">
  <label>Seu nome: <input type="text" name="nome"></label>
  <button>Enviar</button>
</form>
</body>
</html>

O mesmo arquivo produziu duas páginas diferentes. Esse é o padrão que você vai usar em quase todo formulário deste guia. Com POST, a pergunta "foi enviado?" é um pouco diferente ($_SERVER['REQUEST_METHOD'] === 'POST'), e é a próxima aula que mostra.


Quando dá errado

O campo foi preenchido, mas não chegou no PHP
<input type="text" id="nome">
$ curl -s "localhost:8000/ola.php?"
Array
(
)

O que aconteceu: o campo não tem name. O id serve para CSS e JavaScript, mas o navegador só envia campos com name. O mesmo acontece com campos fora do <form> e com campos disabled.

Como resolver: <input type="text" name="nome" id="nome">. Pode ter os dois; o PHP só olha o name.

"Not Found" depois de clicar em Enviar
$ curl -si "localhost:8000/olaa.php?nome=Ana"
HTTP/1.1 404 Not Found
…
<h1>Not Found</h1><p>The requested resource <code class="url">/olaa.php?nome=Ana</code> was not found on this server.</p>

E no terminal do php -S:

[Fri Oct 16 20:43:42 2026] 127.0.0.1:51122 [404]: GET /olaa.php?nome=Ana - No such file or directory

O que aconteceu: o action aponta para um arquivo que não existe (aqui, olaa.php, digitado errado). O formulário funcionou; quem não foi achado é o "destinatário".

Como resolver: confira o nome no action (maiúsculas contam no Linux) e se o arquivo está na pasta em que o php -S foi aberto.

Dois campos com o mesmo nome: só o último chegou
$ curl -s "localhost:8000/ola.php?nome=Ana&nome=Bia"
Array
(
    [nome] => Bia
)

O que aconteceu: dois campos com name="nome" (comum quando se copia e cola um campo e esquece de trocar o nome). O PHP guarda cada nome uma vez só, e o segundo valor apagou o primeiro.

Como resolver: dê nomes diferentes (nome, sobrenome). Se você quer vários valores (várias frutas marcadas), use colchetes no nome: name="frutas[]", assunto de $_GET e $_POST.

Clico no botão e nada acontece

O que aconteceu: o botão está fora do <form> (ou o </form> fecha antes dele), ou o botão é type="button". Um botão fora do formulário não sabe o que enviar.

Como resolver: coloque todos os campos e o botão entre <form> e </form>, e use <button> sem type ou com type="submit".

O formulário é POST, mas o PHP procura em $_GET
<?php
$nome = $_GET['nome'];
echo "Olá, $nome";
$ curl -s localhost:8000/ -d "nome=Ana"
<br />
<b>Warning</b>:  Undefined array key "nome" in <b>/home/ana/site/index.php</b> on line <b>2</b><br />
Olá, 

O que aconteceu: com method="post", os dados vão para $_POST; o $_GET fica vazio, e o PHP avisa que a chave "nome" não existe ("Undefined array key" = chave de array não definida). No servidor, o aviso vem com as tags <br /> e <b>, para aparecer formatado no navegador.

Como resolver: leia do array que combina com o método: method="post" → $_POST; method="get" (ou sem method) → $_GET. A próxima aula mostra como evitar esse aviso de vez.


Referência

HTMLPara quêEnvia
<form action="x.php" method="post">A ficha: para onde e como enviar—
action ausente ou vazioEnvia para a própria página—
method ausenteUsa GET—
<input name="n">Texto de uma linhan=texto
type="email|number|password|hidden"Variações do inputn=texto
<select name="n"><option value="v">Lista de opçõesn=v
<textarea name="n">Texto de várias linhasn=texto
<input type="radio" name="n" value="v">Um entre vários (mesmo name)n=v do marcado, ou nada
<input type="checkbox" name="n">Sim / nãon=on se marcado, ou nada
<button>Envia o formulárioname=value do botão clicado, se tiver
<label>Rótulo clicável do camponada
value, selected, checkedValor inicial—
placeholder, required, min, maxAjuda e conferência no navegador (não substituem o PHP)—

Exercícios

1. O atributo que manda o campo

Complete para o campo chegar no PHP como email:

<input type="email" >

2. Método para senha

Complete o formulário de login com o método certo:

<form action="entrar.php" method="">

3. Para onde vai?

Um formulário sem action, dentro de contato.php, é enviado para qual arquivo?

4. A checkbox <input type="checkbox" name="aceito"> ficou desmarcada. O que o PHP recebe?

5. Qual uso combina com GET?

6. Na opção <option value="limao">Limão siciliano</option>, o que o PHP recebe quando ela é escolhida?

Missão: a página já cumprimenta pelo nome. Acrescente ao formulário um campo de texto chamado cidade (com o rótulo "Cidade:"), antes do botão. Rode, preencha os dois campos na aba Resultado e envie: o print_r deve mostrar nome e cidade.

<?php if (isset($_GET['nome'])): ?>
  <p>Olá, <?= htmlspecialchars($_GET['nome']) ?>!</p>
<?php endif; ?>
<form method="get">
  <p><label>Nome: <input type="text" name="nome"></label></p>
  <button>Enviar</button>
</form>
<pre><?php print_r($_GET); ?></pre>
<?php if (isset($_GET['nome'])): ?>
  <p>Olá, <?= htmlspecialchars($_GET['nome']) ?>!</p>
<?php endif; ?>
<form method="get">
  <p><label>Nome: <input type="text" name="nome"></label></p>
  <p><label>Cidade: <input type="text" name="cidade"></label></p>
  <button>Enviar</button>
</form>
<pre><?php print_r($_GET); ?></pre>

Missão: transforme o formulário de busca em uma encomenda: troque o método para post e acrescente três botões radio chamados tamanho, com os valores P, M e G. Envie pela aba Resultado e confira: o endereço não muda e os dados aparecem em $_POST.

<form method="get">
  <p><label>Sabor: <input type="text" name="sabor"></label></p>
  <button>Enviar</button>
</form>
<pre><?php print_r($_POST); ?></pre>
<form method="post">
  <p><label>Sabor: <input type="text" name="sabor"></label></p>
  <p>Tamanho:
    <label><input type="radio" name="tamanho" value="P"> P</label>
    <label><input type="radio" name="tamanho" value="M"> M</label>
    <label><input type="radio" name="tamanho" value="G"> G</label></p>
  <button>Enviar</button>
</form>
<pre><?php print_r($_POST); ?></pre>

Resumo

  • Um formulário é a "ficha" que o visitante preenche; o PHP é quem lê. Tudo entre <form> e </form> vai junto.
  • action = para onde enviar (sem ele, a própria página). method = como (sem ele, GET).
  • Só campos com name são enviados, no formato nome=valor&nome=valor, sempre como texto.
  • Radio e checkbox desmarcados não são enviados. Checkbox marcada envia on (ou o seu value).
  • GET põe os dados no endereço (buscas, filtros, links); POST põe no corpo (senhas, cadastros, compras, arquivos).
  • required, type="email", min/max ajudam o visitante, mas não protegem nada: o PHP confere de novo.
  • Uma página só pode mostrar o formulário e processar o envio: action vazio + um if que pergunta se os dados chegaram.