diff options
-rw-r--r-- | includes/common.inc | 4 | ||||
-rw-r--r-- | includes/form.inc | 9 | ||||
-rw-r--r-- | modules/simpletest/tests/form.test | 13 | ||||
-rw-r--r-- | modules/simpletest/tests/form_test.module | 37 |
4 files changed, 56 insertions, 7 deletions
diff --git a/includes/common.inc b/includes/common.inc index 211695c8e..a301f3404 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -2481,7 +2481,9 @@ function drupal_exit($destination = NULL) { * An associative array. */ function drupal_map_assoc($array, $function = NULL) { - $array = array_combine($array, $array); + // array_combine() fails with empty arrays: + // http://bugs.php.net/bug.php?id=34857. + $array = !empty($array) ? array_combine($array, $array) : array(); if (is_callable($function)) { $array = array_map($function, $array); } diff --git a/includes/form.inc b/includes/form.inc index c1ba70bf4..3cd6bca81 100644 --- a/includes/form.inc +++ b/includes/form.inc @@ -941,7 +941,7 @@ function _form_validate(&$elements, &$form_state, $form_id = NULL) { $options = $elements['#options']; } if (is_array($elements['#value'])) { - $value = $elements['#type'] == 'checkboxes' ? array_keys(array_filter($elements['#value'])) : $elements['#value']; + $value = $elements['#type'] == 'checkboxes' ? array_keys($elements['#value']) : $elements['#value']; foreach ($value as $v) { if (!isset($options[$v])) { form_error($elements, $t('An illegal choice has been detected. Please contact the site administrator.')); @@ -1804,11 +1804,8 @@ function form_type_checkboxes_value($element, $input = FALSE) { } return $value; } - // If the checkboxes are enabled, and NULL input is submitted, it means - // they're intentionally unchecked, so we need to return an empty array to - // prevent the default value from being used. - elseif (!isset($input) && empty($element['#disabled'])) { - return array(); + else { + return is_array($input) ? drupal_map_assoc($input) : array(); } } diff --git a/modules/simpletest/tests/form.test b/modules/simpletest/tests/form.test index 2cba9863a..fb46d94e5 100644 --- a/modules/simpletest/tests/form.test +++ b/modules/simpletest/tests/form.test @@ -207,6 +207,19 @@ class FormsTestCase extends DrupalWebTestCase { } } } + + /** + * Test Form API protections against input forgery. + * + * @see _form_test_input_forgery() + */ + function testInputForgery() { + $this->drupalGet('form-test/input-forgery'); + $checkbox = $this->xpath('//input[@name="checkboxes[two]"]'); + $checkbox[0]['value'] = 'FORGERY'; + $this->drupalPost(NULL, array('checkboxes[one]' => TRUE, 'checkboxes[two]' => TRUE), t('Submit')); + $this->assertText('An illegal choice has been detected.', t('Input forgery was detected.')); + } } /** diff --git a/modules/simpletest/tests/form_test.module b/modules/simpletest/tests/form_test.module index 94d10faee..6a1cb3258 100644 --- a/modules/simpletest/tests/form_test.module +++ b/modules/simpletest/tests/form_test.module @@ -101,6 +101,14 @@ function form_test_menu() { 'type' => MENU_CALLBACK, ); + $items['form-test/input-forgery'] = array( + 'title' => t('Form test'), + 'page callback' => 'drupal_get_form', + 'page arguments' => array('_form_test_input_forgery'), + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + $items['form-test/form-rebuild-preserve-values'] = array( 'title' => 'Form values preservation during rebuild test', 'page callback' => 'drupal_get_form', @@ -861,6 +869,35 @@ function _form_test_disabled_elements_submit($form, &$form_state) { } /** + * Build a form to test input forgery of enabled elements. + */ +function _form_test_input_forgery($form, &$form_state) { + // For testing that a user can't submit a value not matching one of the + // allowed options. + $form['checkboxes'] = array( + '#type' => 'checkboxes', + '#options' => array( + 'one' => 'One', + 'two' => 'Two', + ), + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + return $form; +} + +/** + * Return the form values via JSON. + */ +function _form_test_input_forgery_submit($form, &$form_state) { + drupal_json_output($form_state['values']); + exit(); +} + +/** * Form builder for testing preservation of values during a rebuild. */ function form_test_form_rebuild_preserve_values_form($form, &$form_state) { |