Are $form_state values cleaned of malicious code even if #limit_validation_errors is set? I'm building a multi step form with a bunch of required fields on each step. The user has to be able to save the current step of the form, even if they haven't filled out all the required fields. 

I will then save it to a custom entity I've created. 

I'm using code like this: 

#limit_validation_errors =&gt; array(),
#submit =&gt; array()


to disable validation. So will Drupal's internal code still clean these values of malicious code when I trigger a submit/save them to the entity? Or do I have to do it myself? 

I'm using $this->set('key', $value); to save the data.
If you set #limit_validation_errors, only elements passed into the value are validated. Everything else is not validated. So for example with this:

#limit_validation_errors = array()


Nothing in the form is validated. And with this:

#limit_validation_errors = array('field_1', 'field_2')


Only field_1 and field_2 will be validated.

To continue on with this, only fields that are validated become part of $form_state['values'], and are then passed on to any submit functions. These values will be as safe as any values in a FAPI form submission, as they will be both sanitized and validated.

Any fields not included in the array passed to #limit_validation_errors will not be part of $form_state['values'], and therefore there is nothing to sanitize, nor any malicious code to validate. The element will simply be missing (or maybe empty, I can't remember off the top of my head) from $form_state['values'] in the submit functions.

For myself, the only use case I've ever found for #limit_validation_errors, is one I stopped using. I would use it on a back button for ajax forms, so that the user could step back a step, without getting errors for any fields on that step of the form. The problem however is that any partially filled fields are then lost on that step of the form when going back, since the submitted values are entirely ignored.

What I do instead, is in my validation function, I check to see if the 'next' button has been clicked before validating.

Example form definition (imagine this is step 2 of a multi-step form)

function some_form_step_2($form, &amp;$form_state)
{
  $form['some_field'] = array
  (
    '#type' =&gt; 'textarea',
    // See comments after code about why I did this:
    '#title' =&gt; t('Enter a value') . '&lt;span title="' . t('This field is required.') . '" class="form-required"&gt;*&lt;/span&gt;',
    '#default_value' =&gt; isset($form_state['values']['some_field']) ? $form_state['values']['some_field'] : '',
  );

  $form['actions'] = array
  (
    '#type' =&gt; 'actions',
  );

  $form['next'] = array
  (
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Next'),
  );

  $form['back'] = array
  (
    '#type' =&gt; 'submit',
    '#value' =&gt; t('back'),
  );

  return $form;
}

function some_form_step_2_validate($form, &amp;$form_state)
{
  // check to see if the clicked button was the 'next' button
  if($form_state['op'] == $form_state['next'])
  {
    // Ensure a value has been entered into some_field
    if(!strlen($form_state['values']['some_field']))
    {
      form_set_error('some_field', t('Please enter a value'));
    }
  }
}

function some_form_step_2_submit($form, &amp;$form_state)
{
  // Here, if the 'next' button was clicked, the value in
  // $form_state['values']['some_field'] will be sanitized
  // and validated

  // However, if the 'back' button was clicked, the value in
  // $form_state['values']['some_field'] will be sanitized,
  // but not validated, as the validation only needs to happen
  // when advancing to the next step, not stepping back to the
  // previous step
}


As you can see from the code, the validation only happens when the 'next' button is clicked. The field some_field is actually required, however, if #required is set on the field, it will always be validated when the back button is clicked. This can be prevented with:

$form['#limit_validation_errors'] = array();


However, if the user has entered a partial value into this field, #default_value will be empty if the user goes back to the first step, and then returns to this step, since the value will not be made part of $form_state['values']. The way I've built it, the 'required' asterisk (*) is included with the form field title to show the user it is required, but the validation of the required field only happens when advancing to the following step, not when going back to the previous step. This way the user can go back whether a value has been entered into the field or not.

Another added advantage of this method is that a custom error message can be shown for required fields. If #required = TRUE was set on the field above, instead of  using the method I did, the error message would be 'Please enter a value? is required' (or something close), which is not very clean English. With the code above, the message is instead 'Please enter a value', with the field highlighted.