Last updated on
13 December 2016

Know about a security issue? Please alert the security team.

Whether you are writing a PHP snippet or an entire module, it is important to keep your code secure.

Use check functions on output to prevent cross site scripting attacks

No piece of user-submitted content should ever be placed as-is into HTML.

  • Use check_plain for plain text.
  • Use filter_xss for markup-containing text, or if the context is entered by an admin and should allow most markup, use filter_xss_admin. While it can also sanitize text, it's almost never correct to use check_markup in a theme or module except in the context of something like a text area with an associated text format.
  • Use the t() function with @ or % placeholders to construct safe, translatable strings.

See how to handle text in a secure fashion for more details.

Use the database abstraction layer to avoid SQL injection attacks

Use the database layer correctly. For example, never concatenate data directly into SQL queries, like this:

db_query('SELECT foo FROM {table} t WHERE t.name = '. $_GET['user']);

Instead, use proper argument substitution with db_query:

For Drupal 6 and before

db_query("SELECT foo FROM {table} t WHERE t.name = '%s' ", $_GET['user']);

If you have to accommodate a variable number of arguments in your SQL, create an array of placeholders. Do NOT do this:

db_query("SELECT t.s FROM {table} t WHERE t.field IN (%s)", $from_user);

Instead, do this:

$placeholders = implode(',', array_fill(0, count($from_user), "%d"));
db_query("SELECT t.s FROM {table} t WHERE t.field IN ($placeholders)", $from_user); 

For Drupal 7+

The DB layer works on top of PHP PDO and uses an array of named placholders:

db_query("SELECT foo FROM {table} t WHERE t.name = :name", array(':name' => $_GET['user']));

For a variable number of argument, use an array of arguments or use db_select():

db_query("SELECT t.s FROM {table} t WHERE t.field IN (:users)",  array(':users' => $from_user)); 


$result = db_select('table', 't')
  ->fields('t', array('s'))
  ->condition('t.field', $from_user, 'IN')

Use db_rewrite_sql() to respect node access restrictions.

Most SQL statements which refer to nodes or the {node} table should be wrapped in a db_rewrite_sql() function call:

$result = db_query(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n"));

Drupal's node access mechanism requires such calls. Without them, visitors may gain access to nodes that they don't have permission to view.