Avoid using data from $form_state['input']
Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites
In the Form API, using data from $form_state['input'], $_POST, and/or \Drupal::request()->request (Drupal 8) are a security risk.
$form_state['input'] and \Drupal::request()->request are actually copies of the raw, unsanitized data from PHP's $_POST superglobal, so the data it contains has not been type-checked.
Use data from $form_state['values'] (Drupal 7) or $form_state->values (Drupal 8) instead.
High-level overview of the problem
Essentially, the issue comes down to the way that browsers send form data, the way that PHP interprets GET and POST data, and the fact that certain built-in PHP functions, database drivers, Drupal functions, and library functions can accept both strings or arrays (and may act in ways you do not expect when passed data of a type you did not expect).
Specifically, you may have put a textfield on the page in your form, but the raw data returned for the textfield in $form_state['input'] might not be a string: it could be an uploaded file or an array.
A more detailed example
Recall that, when you submit HTML like the following...
<form action="/" method="post">
<input type="text" name="foo" value="bar" />
<input type="text" name="baz" value="qux" />
<input type="submit" value="Submit" />
</form>
... your browser will send an HTTP request that looks (roughly) like...
POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: example.com
foo=bar&baz=qux
PHP will automatically de-serialize this into the $_POST super-global as...
$_POST = array(
'foo' => 'bar',
'baz' => 'qux',
);
Note that the web browser does not pass any information about the type of form control, and that PHP doesn't know about the HTML that generated the response.
However, when you submit a form like the following...
<form action="/" method="post">
<input type="checkbox" name="foo[1]" value="bar" checked="checked" />
<input type="checkbox" name="foo[2]" value="qwe" checked="checked" />
<input type="text" name="baz" value="qux" />
<input type="submit" value="Submit" />
</form>
... that will result in an HTTP request like...
POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: example.com
foo%5B1%5D=bar&foo%5B2%5D=qwe&baz=qux
But PHP will interpret that a bit differently than you might expect...
$_POST = array(
'foo' => array(
1 => 'bar',
2 => 'qwe',
),
'baz' => 'qux',
);
Note that, in both examples, PHP's $_POST array contains an entry named foo, but in the first example it is a string, and in the second example, it is an array.
The security issue
This can cause unexpected behavior in your PHP code if it expects $_POST['foo'] to be a string but it is actually an array, and vice-versa.
Famously, attacks for SA-CORE-2014-005 leveraged a weakness in the form API input processing which has since been fixed, because the database driver would act differently if passed a string versus an array.
The solution
The Form API's drupal_validate_form() and _form_validate() functions take care of populating a safe set of data in $form_state['values'], using sanitized data from $form_state['input'].
Notes
- The Drupal Best Practice sniffs for PHPCodeSniffer will warn you if you use
$form_state['input'].
Help improve this page
You can:
- Log in, click Edit, and edit this page
- Log in, click Discuss, update the Page status value, and suggest an improvement
- Log in and create a Documentation issue with your suggestion
Still on Drupal 7? Security support for Drupal 7 ended on 5 January 2025. Please visit our Drupal 7 End of Life resources page to review all of your options.