Cancelar o reenvio após a atualização da página. PHP: Como evitar que um formulário seja enviado novamente

04.08.2021

Certa vez, fiquei intrigado com a questão de como proteger as páginas do site contra o envio repetido de dados do formulário durante a atualização da página (se houve um envio antes disso, é claro).
Todo webmaster e desenvolvedor provavelmente sabe que se você clicou no botão “enviar” de um site preenchendo algum formulário, após o envio, se você tentar atualizar a página, o navegador exibirá uma mensagem confirmando o reenvio.
Em alguns casos isto pode ser inaceitável. Por exemplo, no caso de um formulário de feedback elementar. Quando o usuário preencheu o formulário e enviou uma mensagem e, por algum motivo que só ele conhecia, atualizou a página, a carta foi enviada novamente. É claro que este pode não ser um caso tão fatal, apenas a título de exemplo. Tudo é muito mais doloroso, por exemplo, ao enviar um pedido para uma loja online.
Então, pensei em encontrar uma solução para esse problema e percebi que só havia uma solução: usar um redirecionamento após enviar o formulário de cabeçalho ('local: endereço'). Aqueles. É simples – após o envio, chamamos um redirecionamento (você pode até ir para a mesma página) e pronto! A atualização da página será limpa, sem POSTs e GETs concluídos.

Tudo ficaria bem, mas pessoalmente tive alguns problemas com isso. Eles são os seguintes. Anteriormente, sem utilizar redirecionamentos, o mecanismo de envio de dados em meus sites funcionava da seguinte forma:
O usuário preenche o formulário, clica em “enviar”, o script aceita os dados enviados, verifica sua exatidão (validade, preenchimento dos dados necessários, etc.) e dá uma resposta - ou a operação foi bem-sucedida ou ocorreu um erro e uma lista de erros (por exemplo: erro - O campo “nome” não está preenchido. E na página de envio é exibida a mensagem correspondente: o envio foi bem-sucedido ou não.
Caso o envio não seja bem-sucedido, o formulário permanece na tela e seus campos são preenchidos com os dados que o usuário inseriu. Aqueles. os dados são retirados da variável $_POST (se o método for POST) e colocados nos campos apropriados (ou seja, retornados do post para seus campos para não inseri-los novamente). Afinal, todo mundo fica irritado quando você preenche um formulário, e Deus me livre de você digitar algo errado, e quando você tenta enviar para você, recebe uma mensagem informando que algo foi preenchido incorretamente, e o formulário é atualizado e fica vazio de novo. E por causa de um campo preenchido incorretamente, você terá que preenchê-lo novamente.
Então, como já falei, em caso de falha no preenchimento, o formulário permanece preenchido com os dados retirados do $_POST, e o usuário pode corrigir os dados incorretos e enviar o formulário novamente.
Estava tudo bem e tudo funcionou.
Mas aí enviei por redirecionamento e descobri que após clicar no botão “enviar”, caso o preenchimento não tivesse sucesso, o formulário era atualizado e os campos preenchidos não podiam mais permanecer nele, pois Anteriormente, eles eram preenchidos automaticamente a partir do array $_POST, mas agora, após ocorrer o redirecionamento, $_POST foi limpo como se nunca tivesse havido envio.
Mas também havia uma saída para este caso. Use sessões. Aqueles. Antes de chamar o cabeçalho, transfira os dados do POST para as variáveis ​​de sessão e só então opere com eles após o redirecionamento.
Como resultado, o código tornou-se significativamente mais complicado. A depuração tornou-se mais complicada porque Em geral, é difícil determinar o que acontece com as funções no momento em que ocorre o redirecionamento. Se você cometeu algum tipo de erro nos códigos (que aparece justamente no momento do envio), então ele nem será exibido, pois ocorrerá um redirecionamento e você nem verá a mensagem de erro.
Em geral, após implementar o header em meus códigos, ficou mais difícil trabalhar com minhas aplicações. O desenvolvimento/refinamento/busca de erros tornou-se mais complicado. Mas também não posso recusar isso.
E continuo a pensar: existem outras soluções mais elegantes?

Certa vez, fiquei intrigado com a questão de como proteger as páginas do site contra o envio repetido de dados do formulário durante a atualização da página (se houve um envio antes disso, é claro).
Todo webmaster e desenvolvedor provavelmente sabe que se você clicou no botão “enviar” de um site preenchendo algum formulário, após o envio, se você tentar atualizar a página, o navegador exibirá uma mensagem confirmando o reenvio.
Em alguns casos isto pode ser inaceitável. Por exemplo, no caso de um formulário de feedback elementar. Quando o usuário preencheu o formulário e enviou uma mensagem e, por algum motivo que só ele conhecia, atualizou a página, a carta foi enviada novamente. É claro que este pode não ser um caso tão fatal, apenas a título de exemplo. Tudo é muito mais doloroso, por exemplo, ao enviar um pedido para uma loja online.
Então, pensei em encontrar uma solução para esse problema e percebi que só havia uma solução: usar um redirecionamento após enviar o formulário de cabeçalho ('local: endereço'). Aqueles. É simples – após o envio, chamamos um redirecionamento (você pode até ir para a mesma página) e pronto! A atualização da página será limpa, sem POSTs e GETs concluídos.

Tudo ficaria bem, mas pessoalmente tive alguns problemas com isso. Eles são os seguintes. Anteriormente, sem utilizar redirecionamentos, o mecanismo de envio de dados em meus sites funcionava da seguinte forma:
O usuário preenche o formulário, clica em “enviar”, o script aceita os dados enviados, verifica sua exatidão (validade, preenchimento dos dados necessários, etc.) e dá uma resposta - ou a operação foi bem-sucedida ou ocorreu um erro e uma lista de erros (por exemplo: erro - O campo “nome” não está preenchido. E na página de envio é exibida a mensagem correspondente: o envio foi bem-sucedido ou não.
Caso o envio não seja bem-sucedido, o formulário permanece na tela e seus campos são preenchidos com os dados que o usuário inseriu. Aqueles. os dados são retirados da variável $_POST (se o método for POST) e colocados nos campos apropriados (ou seja, retornados do post para seus campos para não inseri-los novamente). Afinal, todo mundo fica irritado quando você preenche um formulário, e Deus me livre de você digitar algo errado, e quando você tenta enviar para você, recebe uma mensagem informando que algo foi preenchido incorretamente, e o formulário é atualizado e fica vazio de novo. E por causa de um campo preenchido incorretamente, você terá que preenchê-lo novamente.
Então, como já falei, em caso de falha no preenchimento, o formulário permanece preenchido com os dados retirados do $_POST, e o usuário pode corrigir os dados incorretos e enviar o formulário novamente.
Estava tudo bem e tudo funcionou.
Mas aí enviei por redirecionamento e descobri que após clicar no botão “enviar”, caso o preenchimento não tivesse sucesso, o formulário era atualizado e os campos preenchidos não podiam mais permanecer nele, pois Anteriormente, eles eram preenchidos automaticamente a partir do array $_POST, mas agora, após ocorrer o redirecionamento, $_POST foi limpo como se nunca tivesse havido envio.
Mas também havia uma saída para este caso. Use sessões. Aqueles. Antes de chamar o cabeçalho, transfira os dados do POST para as variáveis ​​de sessão e só então opere com eles após o redirecionamento.
Como resultado, o código tornou-se significativamente mais complicado. A depuração tornou-se mais complicada porque Em geral, é difícil determinar o que acontece com as funções no momento em que ocorre o redirecionamento. Se você cometeu algum tipo de erro nos códigos (que aparece justamente no momento do envio), então ele nem será exibido, pois ocorrerá um redirecionamento e você nem verá a mensagem de erro.
Em geral, após implementar o header em meus códigos, ficou mais difícil trabalhar com minhas aplicações. O desenvolvimento/refinamento/busca de erros tornou-se mais complicado. Mas também não posso recusar isso.
E continuo a pensar: existem outras soluções mais elegantes?

O processo de envio do formulário HTML pode levar vários segundos antes que o formulário seja enviado com êxito e a página de resposta seja exibida. Os usuários que não forem pacientes o suficiente podem clicar no botão Enviar várias vezes, fazendo com que o formulário seja reenviado. Geralmente isso não é um problema, mas em alguns casos você pode fazer algo para evitar que isso aconteça.
Abaixo você encontrará dois truques simples para evitar mensagens duplas. Você pode usar qualquer um deles ou uma combinação deles.

Evitando múltiplos envios com Javascript

Provavelmente usar Javascript para evitar que o formulário seja reenviado seja a maneira mais fácil. Quando o usuário enviar o formulário, você pode desativar o botão “Enviar” e alterar seu nome para algo mais claro: “Enviando, aguarde...”

O primeiro passo é definir um id único, por exemplo id="myButton":

A segunda (e última) etapa é especificar dois comandos Javascript no arquivo . O primeiro comando desativará o botão Enviar após o envio do formulário, e o segundo alterará o texto do botão para dar ao usuário uma ideia do que está acontecendo. O seguinte código precisa ser adicionado à tag:

A tag do formulário ficará assim:

Neste caso, o servidor receberá os dados, processará e ao invés de mostrar o resultado, enviará o cliente para uma página onde será mostrado esse resultado.

A desvantagem desse método é que o usuário pode clicar no botão Voltar e retornar à página redirecionada. Ela irá jogá-lo para frente novamente e assim o usuário dificilmente conseguirá retornar duas páginas ao formulário que preencheu originalmente.

Impedir reenvios de formulários usando um redirecionamento do lado do cliente

Um redirecionamento de cliente é chamado de redirecionamento de cliente porque ocorre no lado do cliente. Ou seja, no navegador. O redirecionamento do cliente pode ocorrer usando JavaScript e metatags.

JavaScript tem a vantagem de sobrescrever o histórico do navegador, de modo que, mesmo que o usuário pressione o botão Voltar do navegador, ele não retornará à página retornada pelo manipulador de formulário. Ou seja, a janela desaparecerá completamente. Mas algumas pessoas têm o JS desativado.

As META tags, por outro lado, têm a vantagem de serem universais. Eles redirecionam todo mundo, sempre.

Seria ideal combinar esses dois métodos. Como - Alexander Shurkayev descreveu o redirecionamento ideal em sua nota.

Usamos seu método da seguinte maneira.

Vamos tentar! Agora, como você pode ver, nenhuma janela aparece. O que nos fizemos? Nós checamos. Caso os dados tenham sido recebidos, exibimos tudo o que é necessário para o redirecionamento. Em princípio, depois disso você pode até sair, para não carregar o navegador com dados desnecessários que ninguém verá de qualquer maneira.

Muitas vezes recebo perguntas sobre o cancelamento de reenvios de formulários. Por exemplo, você criou um formulário para adicionar um comentário e adicionou um manipulador à mesma página. Então, ao adicionar um comentário, ele é adicionado com sucesso, mas assim que o usuário pressionar F5, o formulário será enviado novamente. E o usuário pode facilmente pressionar F5 se a página demorar para carregar. Como resultado, em vez de 1 comentário, haverá 2 ou até mais. Neste artigo vou mostrar como isso pode ser evitado.

Primeiro, vamos examinar o problema com mais detalhes usando este código como exemplo:









Ao clicar no botão “Quadrado”, você verá o resultado do script. Mas assim que o usuário pressionar F5 depois disso, o script será executado novamente. Nesse caso, isso não é tão crítico quanto adicionar um comentário; no entanto, por que você precisa de carga extra no servidor?

Agora vamos falar sobre maneiras de resolver esse problema. A primeira maneira é separar o script de processamento em um arquivo separado. Então, no atributo action da tag form, você precisa adicionar o caminho para este script. E o próprio script deve salvar em algum lugar o resultado de suas ações, ou as variáveis ​​​​que vieram para o script, e então redirecioná-lo de volta. Em geral, observe o código do script:

E o código da página com o formulário agora ficará assim:









A desvantagem dessa abordagem é óbvia - você precisa criar outro arquivo para um script tão simples. Portanto, estou falando sobre a segunda maneira de evitar o reenvio do formulário:









Aqui o processamento ocorre novamente no mesmo arquivo, mas a principal diferença é a presença de um redirecionamento para a mesma página no final. Como resultado, a página será recarregada após o envio do formulário e o navegador não solicitará que o usuário envie o formulário novamente ao pressionar F5.

Deixe-me resumir como cancelar o reenvio de um formulário:

  • Ou faça o processamento em um arquivo separado e redirecione de lá.
  • Ou faça o processamento no mesmo arquivo do formulário, mas após o processamento faça um redirecionamento para a mesma página.

É assim que isso é feito em scripts simples. E, nos complexos, em última análise, a mesma coisa é feita.