Empêcher les soumissions de formulaires multiples (côté serveur)

9

Je rencontre un problème où un utilisateur peut soumettre n'importe quel formulaire créé par l'API Form plusieurs fois (un clic rapide entraînant plusieurs demandes).

J'ai mis dans la solution de base côté client (javascript) de désactiver le bouton, mais je suis curieux de savoir quelle est la meilleure approche pour éviter cette situation côté serveur.

Existe-t-il un moyen recommandé d'utiliser le système de jetons de formulaire de Drupal pour gérer cela? Surtout une solution de formulaire globale (c'est-à-dire, ajouter un validateur personnalisé à chaque formulaire en utilisant hook_form_alter ()).

Jusqu'à présent, mon approche a été quelque chose comme ceci:

function mymodule_form_alter(&$form, &$form_state, $form_id) {
  $form['#validate'][] = 'mymodule_form_validate';
}

function mymodule_form_validate(&$form, &$form_state){
  //initialize form array
  if (!isset($_SESSION['submitted_forms'])){
    $_SESSION['submitted_forms'] = array();
  }

  $form_token = $form_state['values']['form_token'];
  if ( isset($_SESSION['submitted_forms'][$form_token]) && $_SESSION['submitted_forms'][$form_token] = TRUE ){
    form_set_error('name]', 'This form has already been submitted');
  }
  else{
    $_SESSION['submitted_forms'][$form_token] = TRUE;
  }
}

Je rencontre des problèmes lorsque le form_token n'est pas unique au formulaire - il semble rester le même quoi qu'il arrive. Je comprends probablement mal ce qu'est le jeton dans le grand schéma de la forme api.

Toute idée est appréciée!

PrairieHippo
la source
En guise de suivi, j'ai commencé à utiliser $ form_state ['form_build_id'] au lieu du jeton. Si je soumets le même identifiant de construction de formulaire deux fois, quelque part en cours de route, le formulaire est reconstruit et traité de toute façon.
PrairieHippo

Réponses:

8

J'ai eu exactement le même problème et j'ai réussi à le résoudre en utilisant les mécanismes de verrouillage de Drupal

Dans la fonction de validation que j'ai utilisée:

function mymodule_custom_form_validate($form, &$form_state){
  if (lock_acquire('your_custom_lock_name')) {
    // long operations here
  } else {
    form_set_error("", t("You submitted this form already."));
  }
}

Et dans la fonction de soumission, j'ai relâché le verrou:

function mymodule_custom_form_submit($form, &$form_state){
  // submit code
  lock_release('your_custom_lock_name');
}
Marius Ilie
la source
1

Ici, vous devez considérer le poids du module:

  1. Un module (laissez first_module) qui devrait avoir le poids de module valeur_négative maximale (peut être -2000) ici, il devrait implémenter hook_form_alter () avec le code suivant. Vous devez maintenant vérifier si le formulaire est déjà soumis ou non par votre code.
   function first_module_form_alter(&$form, &$form_state, $form_id)
    {
      $form['#validate'][] = 'mymodule_form_validate';
    }
function mymodule_form_validate(&$form, &$form_state){
  //a($form_state);
  //initialize form array
  if (!isset($_SESSION['submitted_forms'])){
    $_SESSION['submitted_forms'] = array();
  }

  $form_token = $form_state['values']['form_id'];
  if ( isset($_SESSION['submitted_forms'][$form_token]) && $_SESSION['submitted_forms'][$form_token] = TRUE ){
    form_set_error('name]', 'This form has already been submitted');
  }
  else{
    $_SESSION['submitted_forms'][$form_token] = TRUE;
  }
}
  1. Le second_module dont le poids a une valeur possiblement supérieure. Ici, vous devez annuler la session en ajoutant le rappel de soumission à un module

function second_module_form_alter (& $ form, & $ form_state, $ form_id) {$ form ['# submit'] [] = 'mymodule_form_submit'; }

function mymodule_form_submit(&$form, &$form_state){

  $form_token = $form_state['values']['form_id'];
  unset($_SESSION['submitted_forms'][$form_token]);

}
sathishkumar
la source
1

Si vous voulez cette fonctionnalité sur tous les formulaires et plus de contrôle sans codage, jetez un œil au module Hide Submit Button .

Fonctionnalités:

  1. Masquer ou désactiver le bouton d'envoi après avoir cliqué
  2. Afficher un message et / ou une image en attendant
Gokul NK
la source
5
Le module Hide Submt Button n'est pas une solution côté serveur. D'après la description du module: "Pour les navigateurs avec Javascript désactivé, ce module n'aura aucun effet." drupal.org/project/hide_submit
Blake Frederick
0
$form['submit'] = array(
  '#type' => 'submit',
  '#value' => t('Save'),
  '#attributes' => array(
    'onclick' => 'javascript:var s=this;setTimeout(function(){s.value="Saving...";s.disabled=true;},1);',
  ),
);

j'espère que cela vous aidera ..

ou vous pouvez vous référer Empêcher plusieurs clics sur le bouton de soumission et drupal a un module Masquer le bouton de soumission

Certains utilisateurs cliquent accidentellement sur le bouton Envoyer plus d'une fois en attendant que leur message soit enregistré. Dans certains cas, cela peut entraîner des publications en double ou des commandes de commerce électronique en double.

madhurjya
la source
-1

C'était aussi mon problème avant. Ma solution est de désactiver le bouton via JS.

.module:

/**
 * Implementation of hook_init().
 */
function myModule_init(){
if (arg(0) == 'node' && (arg(2) == 'edit' || arg(1) == 'add')) {
    //hide btn when clicked on article nodes
    drupal_add_js(drupal_get_path('module', myModule') . '/js/disable-submit.js');
}

JS:

Drupal.behaviors.module_disable_submit = function (context) {

/* 
 * Disable keypress on form fields.
 * Prevent browser to reload when pressing enter in input fields 
 */


$('.buttons input:submit').click(function() {
  $('.buttons input:submit').hide();
  $('#node-form .buttons').prepend('<input type="submit" style="margin:1px 0; box-shadow:0 1px 1px #DDDDDD; border-radius:3px 3px 3px 3px; background:url(/sites/all/themes/rubik/images/bleeds.png) repeat-x scroll 0 -41px #F4F4F4; border-color:#DDDDDD #DDDDDD #CCCCCC; border-style:solid; border-width:1px; color:#B8A98F; cursor:default; font-weight:normal; padding:2px 10px; text-align:center;" value="Saving..." name="op" onclick="return false;" />');
  if ('.buttons input:submit') {
    $('.buttons input:submit').keypress(function() {
      $('.buttons input:submit').parents("form").submit();
      $('.buttons input:submit').hide();
    });
  }
});
}
ninjascorner
la source