Skip to main content

Sanitizing Form Values in Drupal 7

Drupal

Today I'm going to share a bit of insight birthed in frustration. One of the Drupal 7 sites I've been working on has a great number of custom forms. On one of the forms, we were collecting a number. It turned out that it would be too inflexible to reject a value because of a comma at the thousands' mark. However, we needed to remove the comma before further validation of the number. The solution we turned to was to use our own validator to sanitize this field before the rest of the validation.

Let's setup some example code to show what we were doing. Let's call our custom form "my_custom_form" and our text field "number."


function my_custom_form($form, &$form_state) {
 $form['number'] = array(
  '#title' => t('Number feild'),
  '#type' => 'textfield',
  '#required' => TRUE,
 );
 $form['submit'] = array(
  '#value' => t('Submit'),
  '#type' => 'submit', 
 );
 return $form;
}

Now Drupal automatically appends a validation function to your form if you name it the same as your form and append "_validate" to the name.


function my_custom_form_validate($form, &$form_state) {
}

If you have any experience with Drupal's Form API, you'll know that you can get to the user's input by looking at $form_state['values']. The potentially misleading aspect to that, though, is that $form_state['values'] is read only in validation. If you want to change a user's input, you cannot simply change $form_state['values']. Instead, you have to use form_set_value($element, $value, &$form_state). We already have $element ($form['number']), we already have $value ($form_state['values']['number']), and we already have $form_state. We should be good to go, right? Wrong. If you read the details for $element on the API page, you'll see that if you're constructing $element yourself, which you are in this context, you need to manually construct $element['#parents']. Fortunately in our case, we don't have a tree to traverse in our form to get to our form element. We can simply add the element itself to the parents array.


$form['number']['#parents'] = array('number');

If we had a more complex form and used #tree = TRUE anywhere below our element, we would have had to include parent elements to our array, but we luck in this simple example. Putting together our custom sanitation to remove commas from our field, our validation function ends up looking like this.


function my_custom_form_validate($form, &$form_state) {
 $new_value = str_replace(',', '', $form_state['values']['number']);
 $form['number']['#parents'] = array('number');
 form_set_value($form['number'], $new_value, $form_state);
}