Como evitar a reapresentação do formulário quando a página é atualizada (F5 / CTRL+R)
Tenho um formulário simples que submete texto à minha tabela SQL. O problema é que depois que o usuário submete o texto, eles podem atualizar a página e os dados são enviados novamente sem preencher o formulário novamente. Eu poderia redirecionar o Usuário para outra página depois que o texto é submetido, mas eu quero que os usuários fiquem na mesma página.
Lembro-me de ler algo sobre dar a cada utilizador um id de sessão único e compará-lo com outro valor que resolveu o problema que estou a ter, mas Esqueci-me. onde está.18 answers
Usa o padrão Post/Redirect / Get. http://en.wikipedia.org/wiki/Post/Redirect/Get
Com o meu site, vou armazenar uma mensagem em um cookie ou sessão, redirecionar após o post, ler o cookie/sessão, e, em seguida, limpar o valor dessa sessão ou variável cookie.
Eu também gostaria de salientar que você pode usar uma abordagem javascript, window.history.replaceState
para evitar uma reapresentação no botão Actualizar e voltar.
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
</script>
Prova do conceito aqui: https://dtbaker.net/files/prevent-post-resubmit.php
Eu ainda recomendaria uma abordagem Post / Redirect / Get, mas esta é uma nova solução JS.
Você deve realmente usar um padrão de redirecionamento de Post para lidar com isso, mas se você de alguma forma acabou em uma posição onde o PRG não é viável (por exemplo, o formulário em si está em uma inclusão, impedindo redirecionamentos) você pode ajustar alguns dos parâmetros de pedido para fazer uma string com base no conteúdo e, em seguida, verificar que você não Enviou já.
//create digest of the form submission:
$messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']);
//and check it against the stored value:
$sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:'';
if($messageIdent!=$sessionMessageIdent){//if its different:
//save the session var:
$_SESSION['messageIdent'] = $messageIdent;
//and...
do_your_thang();
} else {
//you've sent this already!
}
Você pode perventar a apresentação do formulário através de uma variável de sessão como
Primeiro você tem que definir rand() na caixa de texto e $_SESSION ['rand'] na página do formulário
<form action="" method="post">
<?php
$rand=rand();
$_SESSION['rand']=$rand;
?>
<input type="hidden" value="<?php echo $rand; ?>" name="randcheck" />
Your Form's Other Field
<input type="submit" name="submitbtn" value="submit" />
</form>
Depois de verificar $_SESSION ['rand'] com o valor da caixa de texto $_POST['randcheck'] Tipo
if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
{
//Your Code here
}
-
Use o cabeçalho e redireccione a página.
header("Location:your_page.php");
você pode redirecionar para a mesma página ou página diferente. -
Desligue $_POST depois de O inserir na Base de dados.
unset($_POST);
Quando o formulário é processado, você redireciona para outra página:
... process complete....
header('Location: thankyou.php');
Você também pode redirecionar para a mesma página.
Se estiver a fazer algo como comentários e quiser que o utilizador fique na mesma página, pode usar o Ajax para lidar com o envio do formulário
Uma maneira bastante segura é implementar um ID único no post e guardá-lo no
<input type='hidden' name='post_id' value='".createPassword(64)."'>
Então no seu código faça isto:
if( ($_SESSION['post_id'] != $_POST['post_id']) )
{
$_SESSION['post_id'] = $_POST['post_id'];
//do post stuff
} else {
//normal display
}
function createPassword($length)
{
$chars = "abcdefghijkmnopqrstuvwxyz023456789";
srand((double)microtime()*1000000);
$i = 0;
$pass = '' ;
while ($i <= ($length - 1)) {
$num = rand() % 33;
$tmp = substr($chars, $num, 1);
$pass = $pass . $tmp;
$i++;
}
return $pass;
}
POST
pedido manipulando history
protesto.
Então você tem o formulário HTML:
<form method=POST action='/process.php'>
<input type=submit value=OK>
</form>
Quando processa este formulário no seu servidor, em vez de redireccionar o utilizador para /the/result/page
, Configurando o cabeçalho Location
assim:
$cat process.php
<?php
process POST data here
...
header('Location: /the/result/page');
exit();
?>
Após o tratamento POST
os dados são pequenos <script>
e o resultado /the/result/page
<?php
process POST data here
render the <script> // see below
render `/the/result/page` // OK
?>
O <script>
Você deve Desenho:
<script>
window.onload = function() {
history.replaceState("", "", "/the/result/page");
}
</script>
O resultado é:
Como você pode ver, os dados do formulário são POST
ed para process.php
script.
Este programa processa POST
Dados ed e renderização /the/result/page
de uma vez com:
- sem redireccionamento
- não existem dados relativos a
POST
quando actualizar a página (F5) - não há re
POST
Quando você navega para a Página Anterior / Seguinte através do histórico do navegador
UPD
Como outra solução, pergunto: pedido de funcionalidades a equipa Mozilla FireFox para permitir aos utilizadores configurarNextPage
o cabeçalho que irá funcionar como Location
o cabeçalho e tornar post/redirect/get
o padrão obsoleto.
Resumindo. Quando o formulário de processo do servidor POST
os dados são obtidos com sucesso:
- configuração
NextPage
cabeçalho em vez deLocation
- renderize o resultado do processamento
POST
de dados de forma como iria renderizar paraGET
pedido empost/redirect/get
padrão
O navegador por sua vez quando vê o NextPage
cabeçalho:
- Ajustar
window.location
comNextPage
valor - quando o utilizador actualizar a página, o navegador irá negociar
GET
o pedido paraNextPage
em vez de rePOST
os dados do formulário
=)
header('location:yourpage.php');
// Optionally Disable browser caching on "Back"
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' );
header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' );
$post_hash = md5( json_encode( $_POST ) );
if( session_start() )
{
$post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash;
$_SESSION[ 'post_hash' ] = $post_hash;
session_write_close();
}
else
{
$post_resubmitted = false;
}
if ( $post_resubmitted ) {
// POST was resubmitted
}
else
{
// POST was submitted normally
}
Depois de inseri-lo na base de dados, chame o método unset() para limpar os dados.
Desactivado ($_POST);
Para evitar a inserção de dados de atualização, faça um redirecionamento de página para a mesma página ou página diferente após a inserção de registro.
Cabeçalho ('Localização:'.$_SERVER ['PHP_ SELF']);
Basicamente, você precisa redirecionar para fora dessa página, mas ele ainda pode fazer um problema enquanto a sua internet lenta (redirecionar o cabeçalho do serverside)
Exemplo de cenário básico:Carregue no botão enviar duas vezes
Maneira de resolver
-
Lado do cliente
- desactivar o botão Enviar assim que o cliente carregar nele
- Se estiver a utilizar Jquery : Jquery.um
- padrão PRG
-
Servidor lado
- usando um intervalo de variação baseado na hashing quando o pedido foi enviado.
- Userequest tokens. Quando a carga principal para cima atribuir um pedido temporário tocken que, se repetido é ignorado.
Como prevenir a re-submissão do formulário php sem redireccionar. Se você estiver usando $_SESSION (após session_ start) e um formulário $_POST, você pode fazer algo assim:
if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
// do your stuff, save data into database, etc
}
No seu formulário html coloque isto:
<input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>">
<?php
if ( $_POST['act'] == $_SESSION['act'] ){
if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){
$_SESSION['act'] = 1;
} else {
$_SESSION['act'] = 2;
}
}
?>
Assim, cada vez que o formulário é submetido, um novo ato é gerado, armazenado em sessão e comparado com o post act.
Ps: Se você está usando um formulário Get, você pode facilmente mudar todo o POST com o GET e ele funciona também.
Uso Esta linha de javascript para bloquear o pop up a pedir uma nova apresentação do formulário quando o formulário for enviado.
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
Coloca esta linha no rodapé do teu ficheiro e vê a magia.
Usar o padrão Post/Redirect / Get a partir da resposta Keverw é uma boa ideia. No entanto, você não é capaz de ficar em sua página (e eu acho que era isso que você estava pedindo?) Além disso, pode por vezes falhar:
Se um Utilizador da web actualizar antes de a submissão inicial ter terminado devido ao atraso do servidor, resultando em uma solicitação de POST HTTP duplicado em alguns agentes utilizadores.
Outra opção seria armazenar numa sessão se o texto fosse escrito para a sua base de dados SQL como esta:
if($_SERVER['REQUEST_METHOD'] != 'POST')
{
$_SESSION['writeSQL'] = true;
}
else
{
if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL'])
{
$_SESSION['writeSQL'] = false;
/* save $_POST values into SQL */
}
}
Como outros já disseram, não é possível deixar de usar post/redirect/get. Mas, ao mesmo tempo, é muito fácil fazer o que você quer fazer do lado do servidor.
Na sua página de publicação, você simplesmente valida a entrada do utilizador, mas não aja nela, em vez disso copia-a para uma lista de sessões. Você então redireciona de volta para a página principal de Submissão novamente. A sua página de envio principal começa por verificar se a lista de sessões que está a usar existe e, se for o caso, copiá - la para uma lista local e desactivá-la ele. A partir daí podes agir.
Assim só fazes o teu trabalho principal uma vez, alcançando o que queres fazer.<!-- language: lang-php -->
<?php
// Very top of your code:
// Start session:
session_start();
// If Post Form Data send and no File Upload
if ( empty( $_FILES ) && ! empty( $_POST ) ) {
// Store Post Form Data in Session Variable
$_SESSION["POST"] = $_POST;
// Reload Page if there were no outputs
if ( ! headers_sent() ) {
// Build URL to reload with GET Parameters
// Change https to http if your site has no ssl
$location = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// Reload Page
header( "location: " . $location, true, 303 );
// Stop any further progress
die();
}
}
// Rebuilt POST Form Data from Session Variable
if ( isset( $_SESSION["POST"] ) ) {
$_POST = $_SESSION["POST"];
// Tell PHP that POST is sent
$_SERVER['REQUEST_METHOD'] = 'POST';
}
// Your code:
?><html>
<head>
<title>GET/POST Resubmit</title>
</head>
<body>
<h1>Forms:</h1>
<h2>GET Form:</h2>
<form action="index.php" method="get">
<input type="text" id="text_get" value="test text get" name="text_get"/>
<input type="submit" value="submit">
</form>
<h2>POST Form:</h2>
<form action="index.php" method="post">
<input type="text" id="text_post" value="test text post" name="text_post"/>
<input type="submit" value="submit">
</form>
<h2>POST Form with GET action:</h2>
<form action="index.php?text_get2=getwithpost" method="post">
<input type="text" id="text_post2" value="test text get post" name="text_post2"/>
<input type="submit" value="submit">
</form>
<h2>File Upload Form:</h2>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" id="file" name="file">
<input type="submit" value="submit">
</form>
<h1>Results:</h1>
<h2>GET Form Result:</h2>
<p>text_get: <?php echo $_GET["text_get"]; ?></p>
<h2>POST Form Result:</h2>
<p>text_post: <?php echo $_POST["text_post"]; ?></p>
<h2>POST Form with GET Result:</h2>
<p>text_get2: <?php echo $_GET["text_get2"]; ?></p>
<p>text_post2: <?php echo $_POST["text_post2"]; ?></p>
<h2>File Upload:</h2>
<p>file:
<pre><?php if ( ! empty( $_FILES ) ) {
echo print_r( $_FILES, true );
} ?></pre>
</p>
<p></p>
</body>
</html><?php
// Very Bottom of your code:
// Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice
unset( $_SESSION["POST"] );
Só funciona para evitar a apresentação de $ _POST, não $_GET. Mas este é o comportamento de que preciso. A questão do reenvio não funciona com uploads de ficheiros!
Porque não usar apenas a variável $_POST['submit']
como uma declaração lógica, a fim de salvar o que quer que esteja na forma. Você pode sempre redirecionar para a mesma página (caso eles refresquem, e quando eles carregam go back
no navegador, a variável enviar post não seria mais definida. Certifique-se apenas de que o botão enviar tem um name
e id
de submit
.