Search code examples
drupal-7

Drupal 7 how to prevent multiple form submissions (server side)


Here is the working module code I am testing with:

/**
 * @file myform.module
 */

 /**
 * Implements hook_menu().
 */
 function myform_menu() {
   $items['myform'] = array(
     'title' => 'myform',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('myform'),
     'access callback' => true,
     'type' => MENU_NORMAL_ITEM
   );
   return $items;
 }

 /**
 * Form
 */
 function myform() {
   $form['Value'] = array(
     '#title' => t('Value'),
     '#type' => 'textfield',
     '#description' => t('You may not enter the same value twice. (unless you hit enter really fast).'),
     '#required' => true,
   );
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Submit')
   );
   return $form;
 }

 /**
 * Validate
 */
 function myform_validate($form, &$form_state) {
   if (isset($form_state['values']['Value']) && trim($form_state['values']['Value'])!=''){
     // prevent duplicates
     db_set_active('test');
     $r = db_query("SELECT id FROM test WHERE value = '".$form_state['values']['Value']."'");
     $n = $r->rowCount();
     if ($n) {
       form_set_error('Value', t('This value has already been submitted.'));
     }
     db_set_active();
   }
 }

 /**
 * Submit
 */
 function myform_submit($form, &$form_state) {

   for ($i=0; $i<=10000000; $i++) {
     // do nothing
   }

   db_set_active('test');
   db_insert('test')->fields(array('value'=>$form_state['values']['Value']))->execute();
   db_set_active();
 }

The validation hook prevents duplicate values from being inserted, unless I hit the enter key or submit button really fast in which case the same value is inserted into the database multiple times.

How do I prevent duplicate values from being inserted?


Solution

  • I had the exact same problem and managed to fix it using the Locking mechanisms from Drupal

    In the validate function I used:

    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."));
      }
    }
    

    And in the submit function I released the lock:

    function mymodule_custom_form_submit($form, &$form_state){
      // submit code
      lock_release('your_custom_lock_name');
    }