Cómo evitar que se vuelva a enviar un formulario cuando se actualiza la página (F5 / CTRL + R)


Tengo un formulario simple que envía texto a mi tabla SQL. El problema es que después de que el usuario envía el texto, puede actualizar la página y los datos se envían de nuevo sin rellenar el formulario de nuevo. Podría redirigir al usuario a otra página después de enviar el texto, pero quiero que los usuarios permanezcan en la misma página.

Recuerdo haber leído algo sobre darle a cada usuario un id de sesión único y compararlo con otro valor que resolvió el problema que estoy teniendo, pero olvidé dónde lo es.

Author: Eugen Konkov, 2011-06-12

18 answers

Utilice el patrón Post/Redirect/Get. http://en.wikipedia.org/wiki/Post/Redirect/Get

Con mi sitio web, almacenaré un mensaje en una cookie o sesión, redirigiré después de la publicación, leeré la cookie/sesión y luego borraré el valor de esa variable de sesión o cookie.

 66
Author: Keverw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-24 04:58:07

También me gustaría señalar que puede usar un enfoque javascript, window.history.replaceState para evitar un reenvío en el botón actualizar y volver.

<script>
    if ( window.history.replaceState ) {
        window.history.replaceState( null, null, window.location.href );
    }
</script>

Prueba de concepto aquí: https://dtbaker.net/files/prevent-post-resubmit.php

Todavía recomendaría un enfoque Post/Redirect/Get, pero esta es una solución JS novedosa.

 17
Author: dtbaker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-13 02:46:07

Realmente deberías usar un patrón Post Redirect Get para manejar esto, pero si de alguna manera has terminado en una posición donde PRG no es viable (por ejemplo, el formulario en sí está en un include, evitando redirecciones) puedes hash algunos de los parámetros de la solicitud para hacer una cadena basada en el contenido y luego comprobar que no la has enviado ya.

//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!
    }
 16
Author: Moob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-29 11:02:21

Puedes permear la resubmisión de formularios a través de una variable de sesión Como

Primero tienes que establecer rand () en el cuadro de texto y $_SESSION['rand'] en la página del formulario

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

Después de comprobar value _SESSION['rand'] con el cuadro de texto value _POST['randcheck'] valor Como

         if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand'])
          {
         //Your Code here
         }
 12
Author: Savoo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-04 13:03:14
  1. Use el encabezado y redirija la página.

    header("Location:your_page.php"); Puede redirigir a la misma página o a una página diferente.

  2. Unset _ _POST después de insertarlo en la base de datos.

    unset($_POST);

 11
Author: Prasanth Bendra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-08 06:21:17

Cuando se procesa el formulario, se redirige a otra página:

... process complete....
header('Location: thankyou.php');

También puede redirigir a la misma página.

Si está haciendo algo como comentarios y desea que el usuario permanezca en la misma página, puede usar Ajax para manejar el envío del formulario

 10
Author: Ibu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-12 04:26:13

Una forma bastante segura es implementar un ID único en el post y almacenarlo en caché en el

<input type='hidden' name='post_id' value='".createPassword(64)."'>

Luego en tu código haz esto:

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;
}
 7
Author: Absolut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-21 06:49:41

Encontré la siguiente solución. Puede escapar de la redirección después de procesar la solicitud POST manipulando history objeto.

Así que tienes el formulario HTML:

<form method=POST action='/process.php'>
 <input type=submit value=OK>
</form>

Cuando procesa este formulario en su servidor, en lugar de redirigir al usuario a /the/result/page configurando el encabezado Location de la siguiente manera:

$cat process.php
<?php 
     process POST data here
     ... 
     header('Location: /the/result/page');
     exit();
?>

introduzca la descripción de la imagen aquí

Después de procesar los datos POST ed se hace pequeño <script> y el resultado /the/result/page

<?php 
     process POST data here
     render the <script>         // see below
     render `/the/result/page`   // OK
?>

El <script> usted debe render:

<script>
    window.onload = function() {
        history.replaceState("", "", "/the/result/page");
    }
</script>

El resultado es:

introduzca la descripción de la imagen aquí

Como puede ver, los datos del formulario son POSTed a process.php script.
Este script procesa POST datos y renderiza /the/result/page a la vez con:

  1. no hay redirección
  2. no hay datos rePOST al actualizar la página (F5)
  3. no re POST cuando navega a la página anterior/siguiente a través del historial del navegador

UPD

Como otra solución pido solicitud de característicael Mozilla FireFox equipo para permitir a los usuarios configurar NextPage encabezado que funcionará como Location encabezado y hacer post/redirect/get patrón obsoleto.

En resumen. Cuando el servidor procesa POST los datos con éxito:

  1. Configurar NextPage encabezado en lugar de Location
  2. Renderizar el resultado del procesamiento de los datos del formulario POST como lo haría para la solicitud GET en el patrón post/redirect/get

El navegador a su vez cuando vea el NextPage cabecera:

  1. Ajustar window.location con NextPage valor
  2. Cuando el usuario actualice la página, el navegador negociará GET la solicitud a NextPage en lugar de re POST los datos del formulario

Creo que esto sería excelente si se implementara, ¿no? =)

 7
Author: Eugen Konkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-15 09:41:11

Simplemente redireccionarlo a la misma página después de hacer el uso de los datos del formulario, y funciona. Lo he intentado.

header('location:yourpage.php');
 4
Author: krsoni,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-10 16:37:57

Una versión refinada del post de Moob. Cree un hash de la PUBLICACIÓN, guárdelo como una cookie de sesión y compare los hash de cada sesión.

// 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
}
 3
Author: skibulk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-29 11:45:58

Después de insertarlo en la base de datos, llame al método unset() para borrar los datos.

Unset ($_POST);

Para evitar la inserción de datos de actualización, realice una redirección de página a la misma página o a una página diferente después de insertar el registro.

Header ('Location:'.$_SERVER ['PHP_SELF']);

 2
Author: Thinesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-01 16:16:19

Básicamente, es necesario redirigir fuera de esa página, pero todavía puede hacer un problema mientras que su Internet lento (Redirigir encabezado desde servidor)

Ejemplo de escenario básico :

Haga clic en el botón enviar dos veces

Forma de resolver

  • Lado del cliente

    • Desactivar el botón enviar una vez que el cliente haga clic en él
    • Si utiliza Jquery : Jquery.uno
    • Patrón PRG
  • Servidor side

    • Usando marca de tiempo / marca de tiempo de hashing basado en diferencias cuando se envió la solicitud.
    • Userequest tokens. Cuando se carga la principal asignar una solicitud temporal tocken que si se repite se ignora.
 2
Author: ZenithS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-08 01:28:31

Cómo evitar la reenvío de formularios php sin redireccionamiento. Si está usando s _SESSION (después de session_start) y un formulario $_POST, puede hacer algo como esto:

if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) {
  // do your stuff, save data into database, etc
}

En tu formulario html pon esto:

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

Por lo tanto, cada vez que se envía el formulario, se genera un nuevo acto, se almacena en sesión y se compara con el acto post.

Pd: si está utilizando un formulario Get, puede cambiar fácilmente todas las publicaciones con GET y también funciona.

 1
Author: Rômulo Z. C. Cunha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-22 14:26:02

Utilizo esta línea de javascript para bloquear la ventana emergente que pide que se vuelva a enviar el formulario al actualizar una vez que se envía el formulario.

if ( window.history.replaceState ) {
  window.history.replaceState( null, null, window.location.href );
}

Simplemente coloque esta línea en el pie de página de su archivo y vea la magia

 1
Author: Mo'men Mohamed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-23 08:33:34

Usar el patrón Post/Redirect/Get de la respuesta de Keverw es una buena idea. Sin embargo, usted no es capaz de permanecer en su página (y creo que esto era lo que estaba pidiendo?) Además, a veces puede fallar :

Si un usuario web se actualiza antes de que se haya completado el envío inicial debido al retraso del servidor, lo que resulta en una solicitud HTTP POST duplicada en ciertos agentes de usuario.

Otra opción sería almacenar en una sesión si el texto se debe escribir a su Base de datos 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 */
  }
}
 0
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-22 14:58:34

Como otros han dicho, no es posible salir de usar post/redirect/get. Pero al mismo tiempo, es bastante fácil hacer lo que desea hacer del lado del servidor.

En su página de POST simplemente valida la entrada del usuario pero no actúa sobre ella, en su lugar la copia en una matriz de SESIÓN. Luego redirige de nuevo a la página principal de envío. Su página principal de envío comienza comprobando si existe el array de SESIÓN que está utilizando, y si es así, cópielo en un array local y desajustelo. A partir de ahí se puede actuar en él.

De esta manera solo haces todo tu trabajo principal una vez, logrando lo que quieres hacer.

 0
Author: Stu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-20 21:42:46

He buscado una solución para evitar el reenvío en un gran proyecto después. El código funciona altamente con $_GET y $_POST y no puedo cambiar el comportamiento de los elementos del formulario sin el riesgo de errores imprevistos. Entonces, aquí está mi código:

<!-- 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"] );

Solo funciona para evitar el reenvío de $_POST, no $_GET. Pero este es el comportamiento que necesito. El problema de reenvío no funciona con la carga de archivos!

 0
Author: Andreas Rex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-24 08:20:18

¿Por qué no usar la variable $_POST['submit'] como una instrucción lógica para guardar lo que esté en el formulario? Siempre puede redirigir a la misma página (En caso de que se actualicen, y cuando golpeen go back en el navegador, la variable enviar mensaje ya no se establecería. Solo asegúrate de que tu botón de envío tenga name y id de submit.

 -2
Author: Brant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-30 06:20:20