Fix for double escaping of custom field values
authorEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 6 Apr 2023 23:04:07 +0000 (11:04 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Fri, 7 Apr 2023 01:39:34 +0000 (13:39 +1200)
CRM/Contact/BAO/Query.php
CRM/Core/BAO/CustomQuery.php

index 86c6ae86fc5da2b59de8b9bae030e5d36733e14c..5e4a381a294e777e397c71b953f3f08e679eb1d4 100644 (file)
@@ -5621,12 +5621,18 @@ civicrm_relationship.start_date > {$today}
    *   Value.
    * @param string $dataType
    *   Data type of the field.
+   * @param bool $isAlreadyEscaped
+   *   Ideally we would be consistent about whether we escape
+   *   before calling this or after, but the code is a fearsome beast
+   *   and poking the sleeping dragon could throw a cat among the
+   *   can of worms. Hence we just schmooze this parameter in
+   *   to prevent double escaping where it is known to occur.
    *
    * @return string
    *   Where clause for the query.
    * @throws \CRM_Core_Exception
    */
-  public static function buildClause($field, $op, $value = NULL, $dataType = NULL) {
+  public static function buildClause($field, $op, $value = NULL, $dataType = 'String', $isAlreadyEscaped = FALSE): string {
     $op = trim($op);
     $clause = "$field $op";
 
@@ -5636,12 +5642,11 @@ civicrm_relationship.start_date > {$today}
         return $clause;
 
       case 'IS EMPTY':
-        $clause = ($dataType == 'Date') ? " $field IS NULL " : " (NULLIF($field, '') IS NULL) ";
+        $clause = ($dataType === 'Date') ? " $field IS NULL " : " (NULLIF($field, '') IS NULL) ";
         return $clause;
 
       case 'IS NOT EMPTY':
-        $clause = ($dataType == 'Date') ? " $field IS NOT NULL " : " (NULLIF($field, '') IS NOT NULL) ";
-        return $clause;
+        return ($dataType === 'Date') ? " $field IS NOT NULL " : " (NULLIF($field, '') IS NOT NULL) ";
 
       case 'RLIKE':
         return " CAST({$field} AS BINARY) RLIKE BINARY '{$value}' ";
@@ -5677,9 +5682,9 @@ civicrm_relationship.start_date > {$today}
         if ($emojiWhere === '0 = 1') {
           $value = $emojiWhere;
         }
-        $value = CRM_Utils_Type::escape($value, $dataType);
+        $value = $isAlreadyEscaped ? $value : CRM_Utils_Type::escape($value, $dataType);
         // if we don't have a dataType we should assume
-        if ($dataType == 'String' || $dataType == 'Text') {
+        if ($dataType === 'String' || $dataType === 'Text') {
           $value = "'" . $value . "'";
         }
         return "$clause $value";
index 98d8d68bc0931afd9b4fd063355479bd9daaaab4..002f5fba267eb5ece7627fac650f7b90941aee16 100644 (file)
@@ -195,8 +195,8 @@ class CRM_Core_BAO_CustomQuery {
         // fix $value here to escape sql injection attacks
         $qillValue = NULL;
         if (!is_array($value)) {
-          $value = CRM_Core_DAO::escapeString(trim($value));
-          $qillValue = CRM_Core_BAO_CustomField::displayValue($value, $id);
+          $escapedValue = CRM_Core_DAO::escapeString(trim($value));
+          $qillValue = CRM_Core_BAO_CustomField::displayValue($escapedValue, $id);
         }
         elseif (count($value) && in_array(key($value), CRM_Core_DAO::acceptedSQLOperators(), TRUE)) {
           $op = key($value);
@@ -273,7 +273,7 @@ class CRM_Core_BAO_CustomQuery {
               }
               else {
                 //FIX for custom data query fired against no value(NULL/NOT NULL)
-                $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String');
+                $this->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($fieldName, $op, $value, 'String', TRUE);
               }
               $this->_qill[$grouping][] = $field['label'] . " $qillOp $qillValue";
             }