Pular para o conteúdo
murad.guide

PHP

Capítulo 13

Um formulário que chega por POST

6 min de leitura 999 palavras 1 gravura

Neste capítulo você vai enviar campos ao PHP local e reconhecer a resposta sem gravar ainda.

Seu ponto de partida

Estude depois do capítulo 12. O exemplo deste capítulo é 13-formulario-post, no pacote que acompanha o volume. Copie a pasta inicio para um diretório de prática e preserve o original. A raiz do exemplo é a referência concluída desta etapa. Sua cópia permite experimentar sem perder a referência.

Execute o PHP na raiz da sua cópia com php -S 127.0.0.1:8000 -t public. Abra http://127.0.0.1:8000/. Não abra PHP por duplo clique nem use o servidor de Python. Encerre com Ctrl+C antes de trocar de etapa.

Como praticar

Leia a explicação e digite ou confira o código indicado. Mude uma coisa. Antes de conferir, anote sua previsão. Salve, recarregue e compare. Se não acontecer o esperado, investigue o erro antes de avançar. Cada experiência parte dos valores da referência. Depois de conferir, desfaça somente a mudança desse experimento antes de começar a próxima lição. Você pode parar depois de uma lição e retomar mais tarde.

Ligue rótulo e campo

O formulário já está completo em public/index.php. Cada campo tem um rótulo visível. For no label combina com id no campo e permite focá-lo ao clicar no texto.

Name tem outra tarefa: identifica a chave que o PHP recebe em $_POST. Um id sozinho não cria essa chave. Method=post escolhe o tipo de envio; action=index.php aponta para este arquivo no servidor local.

Use Lia, lia@example.invalid e uma mensagem fictícia. O domínio invalid é reservado para exemplos e não serve como destino de e-mail. Este formulário não envia e-mail nem cria cadastro.

Faça no seu exemplo

Localize o campo de nome no formulário.

<label for="nome">Nome fictício</label>
<input id="nome" name="nome" required maxlength="80">

Mude uma coisa e preveja

Troque somente o texto do rótulo para Personagem do exercício.

Anote o que você acha que vai acontecer antes de salvar e recarregar.

Recarregue e confira

Recarregue e clique no rótulo. O cursor deve continuar entrando no mesmo campo. O PHP ainda recebe a chave nome.

Se não acontecer

Se o clique não focar, compare for e id. Não troque name só para mudar o texto visível do rótulo.

Execute o bloco só no envio

O bloco de leitura confere o método antes de tratar o formulário. Abrir a página produz GET e não entra nesse bloco. Pressionar Enviar para conferência produz POST.

Campo lê nome, email e mensagem de $_POST. Depois a resposta mostra a mensagem recebida com escapar. Até esta etapa não existe gravação no disco: recarregar uma nova abertura limpa os campos.

O formulário usa a validação básica do navegador para orientar o preenchimento. Ela será complementada no servidor antes da primeira gravação. A ferramenta do navegador e o programa no servidor fazem verificações em momentos diferentes.

Faça no seu exemplo

No início de public/index.php, confira a condição e a leitura de mensagem.

if (($_SERVER["REQUEST_METHOD"] ?? "") === "POST") {
    $valores["mensagem"] = campo($_POST, "mensagem");
}

Mude uma coisa e preveja

Preencha os três campos fictícios e mude somente a mensagem para Esta mensagem chegou ao PHP local.

Anote o que você acha que vai acontecer antes de salvar e recarregar.

Recarregue e confira

Envie. A resposta deve mostrar a mensagem como texto e informar Recebido para conferência. Nada foi gravado.

Se não acontecer

Se a mensagem ficar vazia, confira name=“mensagem” e a chave no PHP. Se o navegador tentar abrir outro arquivo, confira action e a pasta public do teste.

Preserve o que foi digitado na resposta

Depois de um POST, a página é construída de novo. Para manter o valor no formulário, a resposta precisa usar os valores que acabou de ler. Input usa value; textarea usa conteúdo entre abertura e fechamento.

Os valores são preparados com escapar antes de entrar no HTML. Isso vale também para as aspas do atributo value. Alterar só o texto visível não autoriza o programa a misturar dados com marcação.

Pressionar Limpar restaura os valores iniciais presentes nessa resposta. Após um envio, esses valores podem ser os reapresentados pelo servidor. Para abrir um formulário novo e vazio, use o link Novo formulário. Não confunda reset do HTML com apagar um arquivo gravado.

Faça no seu exemplo

Confira a saída entre as tags do textarea.

<textarea id="mensagem" name="mensagem" required
          maxlength="1000" rows="4"><?= escapar($valores["mensagem"]) ?></textarea>

Mude uma coisa e preveja

Envie uma mensagem fictícia com uma quebra de linha.

Anote o que você acha que vai acontecer antes de salvar e recarregar.

Recarregue e confira

As duas linhas devem continuar no campo e na confirmação. Abra Novo formulário e confira que a nova abertura está vazia.

Se não acontecer

Se value no textarea não funcionar, coloque o texto entre as tags. Se os sinais virarem HTML, confira escapar na saída.

Trecho do resultado de referência do capítulo 13

A captura mostra um trecho da referência concluída. Abra e percorra o exemplo para conferir o restante. Experimentos temporários podem produzir outra aparência; restaure os valores indicados antes de comparar.

Atividades para fazer antes das respostas

Use uma nova cópia do exemplo. Tente aplicar o que aprendeu antes de consultar os comentários.

  1. Mude o rótulo sem mudar a chave recebida.

  2. Envie texto contendo teste.

  3. Abra Novo formulário após conferir uma mensagem.

Respostas comentadas

Compare sua explicação e o que realmente aconteceu. Outra solução pode funcionar se cumprir o objetivo e preservar o acesso ao conteúdo.

  1. Altere o conteúdo de label; preserve name, for e id.

  2. O texto deve continuar literal, sem virar negrito.

  3. O link abre index.php por GET. Os campos voltam vazios e não havia arquivo para apagar.

Quando seguir

Você reconhece o caminho do campo até $_POST e a reapresentação da resposta. Se ainda precisa de ajuda, repita a experiência pequena antes de avançar.

Consulta opcional

Não é preciso ler os links externos para executar os arquivos fornecidos. Eles servem para consultar detalhes quando você quiser.

O arquivo completo

Referência do exemplo 13-formulario-post, reproduzida aqui para que você possa conferir sem sair da página.

apoio.php

<?php
declare(strict_types=1);

function escapar(string $texto): string
{
    return htmlspecialchars($texto, ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8");
}

function campo(array $dados, string $chave): string
{
    $valor = $dados[$chave] ?? "";
    if (!is_string($valor) || preg_match('//u', $valor) !== 1) {
        return "";
    }
    return trim($valor);
}

function tamanho(string $texto): int
{
    if (function_exists("mb_strlen")) {
        return mb_strlen($texto, "UTF-8");
    }
    return preg_match_all('/./us', $texto);
}

public/estilos.css

* { box-sizing: border-box; }
body { margin: 0; background: #f4f7fb; color: #203246;
  font: 1.05rem/1.65 Arial, sans-serif; }
header, main, footer { max-width: 48rem; margin-inline: auto; padding: 1.5rem; }
header { padding-top: 2.5rem; }
h1 { font-size: clamp(1.8rem, 5vw, 2.7rem); line-height: 1.2; }
main { background: #fff; border-radius: .8rem; }
article { border-top: 1px solid #cad4df; padding-block: 1rem; }
a { color: #124e77; text-underline-offset: .2em; }
nav { display: flex; flex-wrap: wrap; gap: 1rem; }
label { display: block; font-weight: bold; }
input:not([type=hidden]), textarea { width: 100%; max-width: 34rem;
  border: 2px solid #718095; border-radius: .35rem; padding: .7rem;
  font: inherit; color: inherit; background: #fff; }
button { font: inherit; background: #124e77; color: white;
  border: 0; border-radius: .35rem; padding: .75rem 1.2rem; cursor: pointer; }
button:hover { background: #103b59; }
.mensagem { white-space: pre-wrap; overflow-wrap: anywhere; }
.erros { color: #8b142c; }
.ok { color: #175c30; font-weight: bold; }
:focus-visible { outline: 3px solid #b04d00; outline-offset: 3px; }
.pular { position: absolute; left: -10000px; }
.pular:focus { position: static; display: block; padding: 1rem; background: white; }
@media (max-width: 35rem) { header,main,footer { padding: 1rem; } }