When you reload a webform submission for editing, and the webform contains a select-list with the 'Other...' field enabled, then the saved values are not properly re-loaded into the widget if the select-list option have numeric keys.

Steps to reproduce:

  • Create a webform containing a single select-component
  • Configure the select-component to permit multiple selections, and to allow the 'Or other...' option.
  • Configure the option-list for the select-component to have a list with numeric keys like:
    0|Foo
    1|Bar
    2|Zoom
    

    Note that this is what you get by default if you just enter text values into the edit-field on the form configuration page, but entering them manually will also trip this bug.

  • View your webform. Select all the options in the list AND the 'Other' option AND enter a value in the Other textfield. The complete selection is not necessary to trip the bug, but makes my example easier to explain.
  • Submit the completed webform, then go to the list of submissions and choose to edit it.

Expected result:

The webform is displayed in edit-mode, with the original selections loaded back into the checkboxes, and the 'other' text in the textfield.

ACTUAL result:

The first option in the list (the one that had a key of '0') is checked, and the 'other' checkbox is checked, but none of the remaining options are. The 'Other' textfield contains a comma-separated list of all the missing option-keys and the actual submitted 'other' text.

Investigating...

In the select_or_other_multi_array_key_exists function at line 724 of select_or_other.module, each saved value is compared with an option list key to determine if the value belongs to the option list:

function select_or_other_multi_array_key_exists($needle, $haystack) {
  foreach ($haystack as $key => $value) {
    if ($needle === $key) {
      return TRUE;
    }
    ...

Checking the types of the values being compared, the $needle value is always a string (fair enough, since the $needle was saved as the text-value of the select component, but the $key values are integers. Because this is a type-sensitive comparison, it will *always* fail, and so the numeric keys are never matched, and the saved key-values are always assumed to be part of the 'other' value.

In addition, the select_or_other_multi_array_key_exists function is never even called if the saved value is "0" (the index of the first entry in the list), because the check at line 130 of select_or_other.module (in the select_or_other_process function) excludes any saved value that evaluates as 'FALSE': so 0 or "0" will always be assumed to be valid options, never entries in the 'other' textfield. This is why the first checkbox is checked in the edit form, even though none of the other options are matched.

Workaround:

Edit your option lists to have keys which cannot be parsed as numbers. This bug is not triggered in that case.

Proposed fix:

  • Edit line 130 of select_or_other.module (in the select_or_other_process function) to remove the check for if ($val). So the code-block becomes:
        if (isset($element['select']['#options'])
            && is_array($element['select']['#options'])
            && !select_or_other_multi_array_key_exists($val, $element['select']['#options'])
            && !in_array($val, $element['select']['#options'])) {
          	// Not a valid option - add it to 'other'.
    	...
    

    This ensures that saved values of "0" do get checked for if they are valid option-list keys.

  • Edit line 724 of select_or_other.module (in the select_or_other_multi_array_key_exists function) to force a string-comparison rather than a type-sensitive comparison (as is currently used):
      foreach ($haystack as $key => $value) {
        if (strcmp($needle, $key) == 0) {
          return TRUE;
        }
        ....
    

    Note that if you just use "==" instead of "===", then PHP converts everything possible to numbers for the comparison, but comparing *any* string with the number 0 results in a positive match (by design, according to the PHP docs) so if the option-list has a valid '0' index, then that will also match all of the 'other' text values, which is not good either. Forcing the string-comparison works.

Comments

danielb’s picture

That's a very thorough bug report, but since webform integration is not implemented in this module, the effect of these changes would have to be studied on the functionality that this module does provide.

LittleRedHen’s picture

Yes - that's why I didn't attempt to build a proper patch or anything along those lines. This solution saved *my* project deadline, but I'm aware that it might break something I haven't found yet.

I did check back in the source code for older versions of this module, and found that it used to use the PHP array_key_exists function where the call to select_or_other_multi_array_key_exists is now. Since array_key_exists does properly match the numeric key values with the string equivalent, I am reasonably sure that that was intended at one point.

rellis’s picture

If $needle === $key is to keep 0 from matching option key '',
array_key_exists() should work for that too, and still
match 123 with "123"...

Attached is a possible patch.

Thanks.

danielb’s picture

Status: Needs work » Needs review
danielb’s picture

rellis has addressed the exact thing that concerned me about the original proposed fix, so I think I trust this patch.

danielb’s picture

Status: Needs review » Fixed

Committed to both 6.x and 7.x
Thanks guys.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

  • Commit 4cb9f43 on 7.x-2.x, 7.x-3.x, 8.x-3.x by danielb:
    Issue #1352168 by rellis, LittleRedHen, danielb: Properly match keys.