Pular para o conteúdo
murad.guide

PHP

Capítulo 18

Recarregar sem repetir a gravação

6 min de leitura 1.052 palavras 1 gravura

Neste capítulo você vai separar o envio da página de confirmação usando redirecionamento.

Seu ponto de partida

Estude depois do capítulo 17. O exemplo deste capítulo é 18-redirecionamento, 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.

Veja o problema do POST recarregado

Nas etapas anteriores, a resposta a um envio ainda era a resposta de POST. Recarregar essa resposta pode pedir autorização para enviar novamente. Se você aceitar, grava outra visita.

Agora, depois de uma escrita bem-sucedida, o PHP responde com um redirecionamento 303 para index.php. O navegador segue com GET. Assim, recarregar a página de resultado apenas pede a leitura novamente.

Esse percurso é chamado POST, Redirect, GET: envio, redirecionamento e consulta. Ele não impede dois envios distintos de uma pessoa apertando o botão novamente; resolve a repetição provocada por recarregar o resultado.

Faça no seu exemplo

Confira as instruções logo depois de confirmar os bytes gravados.

$_SESSION["aviso"] = "Visita guardada neste computador.";
header("Location: index.php", true, 303);
exit;

Mude uma coisa e preveja

Envie uma visita com a mensagem Conferência do recarregar. Anote quantos registros espera depois de dois recarregamentos.

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

Recarregue e confira

O navegador volta para index.php por GET. Recarregue duas vezes e confira que o arquivo não ganhou outra cópia dessa visita.

Se não acontecer

Se o navegador pedir reenvio, confira o código 303, a chamada depois do sucesso e o exit. Não redirecione antes de verificar a gravação.

Envie cabeçalhos antes do conteúdo

Header envia uma informação de resposta HTTP. Ele precisa ser chamado antes de imprimir HTML ou qualquer outra saída. Index.php faz a leitura, a validação, a escrita e o possível redirecionamento antes do doctype.

Um espaço solto antes de , evitando espaços acidentais depois do fechamento.

Exit encerra essa execução quando o redirecionamento foi enviado. Sem ele, o arquivo pode continuar tentando montar uma página que não faz parte da confirmação esperada.

Faça no seu exemplo

Confira que o início de public/index.php começa com PHP e que o HTML vem depois do bloco de tratamento.

Mude uma coisa e preveja

Numa cópia de prática, acrescente temporariamente echo “teste”; antes do header.

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

Recarregue e confira

Observe o aviso ou a saída inesperada e remova o echo. Refaça o envio e confirme o redirecionamento limpo. A forma do aviso pode variar com a configuração do PHP.

Se não acontecer

Se o aviso continuar, confira espaços antes da abertura PHP e saídas em apoio.php. Não mantenha um echo de diagnóstico no projeto concluído.

Mostre um aviso só uma vez

Uma sessão permite manter um valor entre pedidos do mesmo navegador. Aqui ela guarda um aviso curto de sucesso, não uma conta nem o texto completo da visita.

Session_start abre a sessão antes de enviar HTML. Depois da gravação, aviso recebe uma frase. No GET seguinte, o programa lê essa frase e a remove com unset. O novo recarregar mostra a lista, mas não anuncia outra gravação.

As sessões deste exemplo ficam em sessoes, fora de public. Esses arquivos são temporários de execução, não registros para entregar ao aluno. Uma cópia nova traz só o README dessa pasta; não copie sessões de um teste para o ZIP.

Faça no seu exemplo

No início do index.php, confira a leitura do aviso após abrir a sessão.

$aviso = $_SESSION["aviso"] ?? "";
unset($_SESSION["aviso"]);

Mude uma coisa e preveja

Envie uma visita e depois recarregue uma vez.

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

Recarregue e confira

O aviso aparece no primeiro GET após o envio e desaparece no seguinte. A visita continua na lista e no arquivo.

Se não acontecer

Se a frase sumir antes da primeira confirmação, confira a atribuição antes do header. Se surgir erro de sessão, confirme que a pasta sessoes existe fora de public e é gravável.

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

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. Envie uma visita e recarregue sem duplicar o registro.

  2. Explique por que exit acompanha header.

  3. Compare desaparecimento do aviso com permanência da visita.

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. Depois de sucesso, o 303 leva a GET. Esse recarregar não envia outro POST.

  2. Exit interrompe a execução após encaminhar o navegador.

  3. O aviso é temporário na sessão; a visita está no arquivo persistente. Remover um não apaga o outro.

Quando seguir

Você confere que recarregar o GET não repete a escrita e que o aviso é temporário. 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 18-redirecionamento, reproduzida aqui para que você possa conferir sem sair da página.

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; } }