return $data;
}
+ /**
+ * Helper function to call validate on arrays
+ *
+ * @see validate
+ */
+ public static function validateAll($data, $type, $abort = TRUE) {
+ foreach ($data as $key => $value) {
+ $data[$key] = CRM_Utils_Type::validate($value, $type, $abort);
+ }
+ return $data;
+ }
+
/**
* Verify that a variable is of a given type, and apply a bit of processing.
*
case 'MysqlColumnNameLoose':
if (CRM_Utils_Rule::mysqlColumnNameLoose($data)) {
- return str_replace('`', '``', $data);
+ $parts = explode('.', str_replace('`', '``', $data));
+ $data = '`'.implode('`.`', $parts).'`';
+
+ return $data;
}
break;
case 'MysqlColumnName':
if (CRM_Utils_Rule::mysqlColumnName($data)) {
+ $parts = explode('.', $data);
+ $data = '`'.implode('`.`', $parts).'`';
+
return $data;
}
break;
case 'MysqlOrderByDirection':
if (CRM_Utils_Rule::mysqlOrderByDirection($data)) {
- return $data;
+ return strtolower($data);
+ }
+ break;
+
+ case 'MysqlOrderBy':
+ if (CRM_Utils_Rule::mysqlOrderBy($data)) {
+ $parts = explode(',', $data);
+ foreach ($parts as &$part) {
+ $part = preg_replace_callback('/(?:([\w_]+)(?:(?:\.)([\w_]+))?(?: (asc|desc))?)/i', array('CRM_Utils_Type', 'mysqlOrderByCallback'), trim($part));
+ }
+ return implode(', ', $parts);
}
break;
case 'MysqlOrderByDirection':
if (CRM_Utils_Rule::mysqlOrderByDirection($data)) {
- return $data;
+ return strtolower($data);
}
break;
return NULL;
}
+ /**
+ * preg_replace_callback for MysqlOrderBy escape.
+ */
+ public static function mysqlOrderByCallback($matches) {
+ $output = '';
+
+ // Column or table name.
+ if (isset($matches[1])) {
+ $output .= '`' . $matches[1] . '`';
+ }
+
+ // Column name in case there is a table.
+ if (isset($matches[2]) && $matches[2]) {
+ $output .= '.`' . $matches[2] . '`';
+ }
+
+ // Sort order.
+ if (isset($matches[3]) && $matches[3]) {
+ $output .= ' ' . $matches[3];
+ }
+
+ return $output;
+ }
+
}
array(-10, 'Positive', NULL),
array('-10', 'Positive', NULL),
array('-10foo', 'Positive', NULL),
+ array('civicrm_column_name', 'MysqlColumnName', 'civicrm_column_name'),
+ array('table.civicrm_column_name', 'MysqlColumnName', 'table.civicrm_column_name'),
+ array('table.civicrm_column_name.toomanydots', 'MysqlColumnName', NULL),
+ array('invalid-column-name', 'MysqlColumnName', NULL),
+ array('column_name, sleep(5)', 'MysqlColumnName', NULL),
+ array('asc', 'MysqlOrderByDirection', 'asc'),
+ array('DESC', 'MysqlOrderByDirection', 'desc'),
+ array('DESCc', 'MysqlOrderByDirection', NULL),
+ array('table.civicrm_column_name desc', 'MysqlOrderBy', 'table.civicrm_column_name desc'),
+ array('table.civicrm_column_name desc,other_column,another_column desc', 'MysqlOrderBy', 'table.civicrm_column_name desc, other_column, another_column desc'),
);
}
array('-3', 'ContactReference', NULL),
// Escape function is meant for sql, not xss
array('<p onclick="alert(\'xss\');">Hello</p>', 'Memo', '<p onclick=\\"alert(\\\'xss\\\');\\">Hello</p>'),
+ array('civicrm_column_name', 'MysqlColumnName', '`civicrm_column_name`'),
+ array('table.civicrm_column_name', 'MysqlColumnName', '`table`.`civicrm_column_name`'),
+ array('table.civicrm_column_name.toomanydots', 'MysqlColumnName', NULL),
+ array('invalid-column-name', 'MysqlColumnName', NULL),
+ array('column_name, sleep(5)', 'MysqlColumnName', NULL),
+ array('asc', 'MysqlOrderByDirection', 'asc'),
+ array('DESC', 'MysqlOrderByDirection', 'desc'),
+ array('DESCc', 'MysqlOrderByDirection', NULL),
+ array('table.civicrm_column_name desc', 'MysqlOrderBy', '`table`.`civicrm_column_name` desc'),
+ array('table.civicrm_column_name desc,other_column,another_column desc', 'MysqlOrderBy', '`table`.`civicrm_column_name` desc, `other_column`, `another_column` desc'),
);
}