2010-01-25 38 views
29

Algunas veces el usuario puede presionar Enter dos veces, y la publicación se inserta dos veces.¿Cómo prevenir insertos múltiples al enviar un formulario en PHP?

¿Existe una solución para evitar esto aparte de comprobar si ya hay una publicación con el mismo title y content?

+0

¿Se puede desactivar el evento que se activa al presionar enter? –

+12

Golpéelos cada vez que lo hagan. Eventualmente aprenderán :) – Gordon

+4

Lo recomiendo usando las teclas de forma. Eche un vistazo a esto aquí: http: //net.tutsplus.com/tutorials/php/secure-your-forms-with-form-keys/ –

Respuesta

1

Deshabilite el botón enviar con Javascript una vez que se envía el formulario (onsubmit).

Tenga en cuenta que si el usuario ha deshabilitado Javascript, todavía pueden enviar dos veces. Si esto sucede con la suficiente frecuencia como para justificar también el control de su código (como sugirió en su pregunta) depende de usted.

0

deshabilite el botón enviar una vez que el usuario haya enviado el formulario, utilizando JavaScript. Eso es lo que, por ejemplo, StackOverflow usa cuando respondes una pregunta.

Por ejemplo

<input type="submit" onclick="this.disabled=true" /> 
0

Use un JavaScript para deshabilitar el botón tan pronto como se hace clic.

onclick="this.disabled=true;forms[0].submit();" 
+1

El controlador 'onclick' no se ejecutará si el formulario se envía mediante un golpe de teclado, p. Ej. el usuario pulsa la tecla Intro mientras se enfoca en el botón Enviar. Mejor uso 'onsubmit' como uno de los otros carteles sugeridos. – Asaph

+1

@Asaph: en realidad me gusta la idea del token sugerida @Mats. Pero si se quedara del lado del cliente, probablemente sería mejor tener un método que incorpore tanto el clic como el envío. Se pueden registrar 2 clics de mouse en IE antes de que se active el envío. Estúpido, pero lo he visto. –

0

presionar presentará dos veces bastante rara vez resulta en múltiples inserciones, pero si quieres un sollution-muertos simple, utilizar

onsubmit="document.getElementById('submit').disabled = true" 

en la etiqueta de formulario, siempre y cuando se dé a su botón de envío id="submit"

30

Utilice un token único con la publicación, de modo que cada publicación/devolución de datos solo se realice una vez.

Desactivar el botón de enviar no es una solución muy buena ya que las personas pueden tener Javascript desactivado o hacer otras cosas extrañas. La validación del lado del cliente es un buen comienzo, pero siempre debe respaldarse con el manejo del lado del servidor.

+2

+1: este es el método más común y no tiene dependencias del lado del cliente. ¿Por qué no se acepta esto como la respuesta? – Russell

+0

@Steve No es cierto. No se espera que POST sean idempotentes. – kaqqao

46

Hay varias soluciones a este problema:

  1. Uso Javascript para desactivar de forma botón de enviar cuando se remita. La desventaja de esto es que esto ABSOLUTAMENTE no es una forma infalible. Es muy fácil enviar formularios sin hacer clic en el botón, y esto tampoco funcionaría para los usuarios con JavaScript deshabilitado. Definitivamente no recomendaría este método.

    Ejemplo:

    <script language="javascript"> 
    <!-- 
        function disableSubmitButton() { 
         // you may fill in the blanks :) 
        } 
    --> 
    </script> 
    <form action="foo.php" method="post"> 
        <input type="text" name="bar" /> 
        <input type="submit" value="Save" onclick="disableSubmitButton();"> 
    </form> 
    
  2. Uso PHP sessions para establecer una variable de sesión (por ejemplo, $ _SESSION [ 'posttimer']) a la fecha y hora actual en el poste. Antes de procesar realmente el formulario en PHP, verifique si existe la variable $ _SESSION ['posttimer'] y verifique una cierta diferencia de marca de tiempo (IE: 2 segundos). De esta forma, puedes filtrar fácilmente los envíos dobles.

    Ejemplo:

    // form.html 
    <form action="foo.php" method="post"> 
        <input type="text" name="bar" /> 
        <input type="submit" value="Save"> 
    </form> 
    
    // foo.php 
    if (isset($_POST) && !empty($_POST)) 
    { 
        if (isset($_SESSION['posttimer'])) 
        { 
         if ((time() - $_SESSION['posttimer']) <= 2) 
         { 
          // less then 2 seconds since last post 
         } 
         else 
         { 
          // more than 2 seconds since last post 
         } 
        } 
        $_SESSION['posttimer'] = time(); 
    } 
    
  3. Incluir un token único en cada poste. En este caso, también debe establecer una variable de sesión para el token que desea incluir y luego mostrar el token en el formulario. Una vez que se envía el formulario, se vuelve a generar el token. Cuando el token enviado no coincide con el token en su sesión, el formulario ha sido reenviado y debe declararse no válido.

    Ejemplo:

    // form.php 
    <?php 
        // obviously this can be anything you want, as long as it is unique 
        $_SESSION['token'] = md5(session_id() . time()); 
    ?> 
    <form action="foo.php" method="post"> 
        <input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" /> 
        <input type="text" name="bar" /> 
        <input type="submit" value="Save" /> 
    </form> 
    
    // foo.php 
    if (isset($_SESSION['token'])) 
    { 
        if (isset($_POST['token'])) 
        { 
         if ($_POST['token'] != $_SESSION['token']) 
         { 
          // double submit 
         } 
        } 
    } 
    
+3

+1 Excelente respuesta, pero me gustaría editar, así que su recomendación es lo primero, y luego sigue los métodos que no recomienda, lo que facilitaría la lectura. Dicho eso, debería ser la respuesta aceptada. –

+0

Para la solución de javascript, puede crear esa función para el evento de envío de formulario, no hacer clic en el botón de clic. Esa función se llamaría y desactivaría el botón de enviar. – machineaddict

+1

Se vio que el método Three es perfecto – yip

1

Alternativamente, utilizar las teclas de forma de una sola vez.

5

Genera una única clave de uso único para enviar con el formulario.

Confiar en Javascript es una mala idea porque puede haber sido deshabilitado en el cliente por el usuario. Con el esquema de clave, cuando el servidor recibe el envío, el envío para esa clave se puede bloquear. Puede responder a envíos duplicados de la forma que desee.

Para este enfoque de trabajo, las claves deben ser únicas y muy difíciles de predecir. De lo contrario, algunos formularios podrían bloquearse debido a colisiones de teclas. Por lo tanto, no es necesario que rastree las claves para cada envío de formularios y evite las colisiones. Las claves deben caducar con la sesión de ese usuario. Otra cosa a tener en cuenta es si los usuarios malintencionados pueden predecir la clave, su código puede ser vulnerable a algún tipo de secuestro o explotación de DOS.

+1

Este es el enfoque que uso. Genere un GUID siempre que se represente la página e inclúyalo en su base de datos cada vez que guarde un formulario. En su código de procesamiento de envío, asegúrese de que GUID aún no exista en el db antes de insertarlo. –

+1

¿Qué tipo de algoritmo de generación de GUID usa normalmente? –

1

utilizo este:

$form_token = $_SESSION['form_token'] = md5(uniqid()); 

enviar $ form_token con la forma, entonces ...

puedo comprobar el form_token:

if($_SESSION['form_token'] != $_POST['form_token']) { 
    echo 'Error'; 
} 
-1

Aron Rotteveel de Incluir un token único en cada POST funcionó para mí. Sin embargo, mi formulario aún se envía cuando un usuario actualiza la página (F5). Me las arreglé para resolver esto mediante la adición de un restablecimiento:

  // reset session token 
      $_SESSION['token'] = md5($_POST['token'] . time()); 

mis guiones finales dice así:

if (isset($_SESSION['token'])) { 
    if (isset($_POST['token'])) { 
     if ($_POST['token'] != $_SESSION['token']) { 
      echo '<h3>Oops! You already submitted this request.</h3>'; 
     } else { 
      // process form 
      // reset session token 
      $_SESSION['token'] = md5($_POST['token'] . time()); 
     } 
    } else { 
     echo 'post token not set'; 
     $_SESSION['token'] = md5($somevariable . time()); 
    } 
} 

oh! no se olvide de agregar session_start(); antes de <!DOCTYPE>

Soy un novato en PHP, por favor corríjanme si encuentra irregularidades.

+0

este es un código inútil. Simplemente haga una redirección HTTP después de enviar el formulario. –

+0

deseo hacerlo, pero mi formulario funciona en una sola página. Inicialmente deseo usar jquery unload() pero encuentro esto útil en ocasiones, el usuario presiona accidentalmente f5 (recargar página). ¿Tienes un enlace en esa redirección? Me encantaría reconsiderar – Pabile

+0

su razón no tiene sentido. también puedes hacer un redireccionamiento de HTTP en una página. –

-1

Uso de JavaScript para que deje de enviar

+1

Ejemplo/código de demo hacer de esto una respuesta potencialmente valiosa. – nickhar

0

Otra forma de crear una página de confirmación donde el usuario puede finalmente pulse el botón enviar. Puede reducir las posibilidades de este tipo.

Cuestiones relacionadas