複数のフォーム送信を防ぐ(サーバー側)


9

ユーザーがForm APIによって作成されたフォームを複数回送信できるという問題が発生しています(高速クリックすると複数のリクエストが発生します)。

ボタンを無効にする基本的なクライアントサイド(JavaScript)ソリューションを導入しましたが、この状況を防ぐ最善の方法はサーバーサイドにあるのかどうか知りたいです。

Drupalのフォームトークンシステムを使用してこれを処理するための推奨される方法はありますか?特にグローバルフォームソリューション(つまり、hook_form_alter()を使用してすべてのフォームにカスタムバリデーターを追加する)。

これまでの私のアプローチは次のようなものでした:

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

form_tokenがフォームに固有ではないという問題が発生しています。何が起こっても同じままであるようです。フォームapiのグランドスキームのトークンが何であるか私はおそらく誤解しているでしょう。

どんな洞察も感謝しています!


フォローアップとして、トークンの代わりに$ form_state ['form_build_id']を使い始めました。同じフォームのビルドIDを2回送信した場合、フォームが再構築されて処理される途中のどこかで。
PrairieHippo

回答:


8

私はまったく同じ問題を抱えており、Drupalのロックメカニズムを使用してなんとか修正できました

私が使用した検証機能では:

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

そして送信機能でロックを解除しました:

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

1

ここでは、モジュールの重量を考慮する必要があります。

  1. モジュールの重みが負のmaximum_value(-2000の可能性があります)が必要な1つのモジュール(first_moduleを使用)は、次のコードでhook_form_alter()を実装する必要があります。ここで、フォームがコードによって既に送信されているかどうかを確認する必要があります。
   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. 正の高い値の重みを持つsecond_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]);

}

1

すべてのフォームでこの機能を使用し、コーディングなしでより詳細に制御したい場合は、[ 送信ボタンの非表示] モジュールをご覧ください。

特徴:

  1. クリックした後、送信ボタンを非表示または無効にする
  2. 待機中にメッセージや画像を表示する

5
Hide Submt Buttonモジュールはサーバー側のソリューションではありません。モジュールの説明から:「JavaScriptが無効になっているブラウザの場合、このモジュールはまったく効果がありません。」drupal.org/project/hide_submit
ブレイクフレデリック

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);',
  ),
);

これがお役に立てば幸いです。

または、送信ボタンの複数クリックの防止とdrupalに1つのモジュール[送信ボタンを隠す]を参照することもできます。

一部のユーザーは、投稿が保存されるのを待っている間に誤って送信ボタンを2回以上クリックします。これにより、転記が重複したり、eコマース注文が重複したりする場合があります。


-1

これは以前にも私の問題でした。これに対する私の解決策は、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();
    });
  }
});
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.