Let's say we have a form such this:

function foo_form(&$form_state, $nid, $vid, $qty, $key) {

  $form['qty_' . $vid] = array(
    '#type' => 'textfield',
    '#title' => '',
    '#default_value' => $qty,
    '#size' => 2,
    '#maxlength' => 5,    
  );
  
  $form['key'] = array(
    '#type' => 'value',
    '#value' => $key,
  );
  
  $form['vid'] = array(
    '#type' => 'value',
    '#value' => $vid,
  );
  
  $form['nid'] = array(
    '#type' => 'value',
    '#value' => $nid,
  );
  
  $form['change'] = array(
    '#type' => 'submit',
    '#submit' => array('foo_change'),
    '#attributes' => array('class' => 'change'),
    '#name' => 'change',
  );
  
  $form['remove'] = array(
    '#type' => 'submit',
    '#submit' => array('foo_remove'),
    '#attributes' => array('class' => 'remove'),
    '#name' => 'remove',
  );

  return $form;
}

As you can see, there are two submit buttons each with different submit function. You can also see that these buttons doesn't have neither #value or #name properties set.

(IMO)By design, both submit buttons gets named "op" before submit. So now we have two items with the same name(read ID). Logically the items merge together into one item named "op" with value "value_of_the_last_item_named_op"(in this case foo_remove()).

What this mean? Practically, if you'll submit this form, every time the foo_remove() function is triggered no matter which button you've pushed, because it was the last value of item named "op".

To fix this bug we have to set the #value or #name of the submit buttons. These values have to be different of each other, because it would be the same like having those buttons without these values set, hence they would behave like identical items again.

Solutions are:
a) update forms documentation: submit button has to have #name OR #value property set(ie. required)
b) change API: if properties #name or #value of submit button are empty they would be set automatically by items ID($form['foo'])
c) change API: make submit properties #name and/or #value required
d) change API: don't assign submit buttons name "op" automatically, get if from its form item ID($form['foo'])
e) correct me if I'm wrong :)

Comments

Anonymous’s picture

correction: point b) $name is set automatically.

catch’s picture

Version: 6.14 » 7.x-dev

Just ran into this adding a 'remove' button to a multiple value field widget. Needs to be fixed in Drupal 7 first though.

sun’s picture

Patch that should resolve this issue but needs someone to complete the corresponding changes for all testing code can be found in #852520: Replace reliance on 'op' with 'triggering_element' to allow for identical submit button labels without having to manually specify a unique #name