diff --git a/src/Resources/contao/drivers/DC_Table.php b/src/Resources/contao/drivers/DC_Table.php index e8ebd67676..74e54b7111 100644 --- a/src/Resources/contao/drivers/DC_Table.php +++ b/src/Resources/contao/drivers/DC_Table.php @@ -438,7 +438,7 @@ public function show() foreach ((array) $value as $v) { - $objKey = $this->Database->prepare("SELECT " . $chunks[1] . " AS value FROM " . $chunks[0] . " WHERE id=?") + $objKey = $this->Database->prepare("SELECT " . \Database::quoteColumnName($chunks[1]) . " AS value FROM " . $chunks[0] . " WHERE id=?") ->limit(1) ->execute($v); @@ -3138,12 +3138,12 @@ protected function save($varValue) { if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 4) { - $this->Database->prepare("UPDATE " . $this->strTable . " SET " . $this->strField . "='' WHERE pid=?") + $this->Database->prepare("UPDATE " . $this->strTable . " SET " . \Database::quoteColumnName($this->strField) . "='' WHERE pid=?") ->execute($this->activeRecord->pid); } else { - $this->Database->execute("UPDATE " . $this->strTable . " SET " . $this->strField . "=''"); + $this->Database->execute("UPDATE " . $this->strTable . " SET " . \Database::quoteColumnName($this->strField) . "=''"); } } @@ -3156,7 +3156,7 @@ protected function save($varValue) $arrValues = $this->values; array_unshift($arrValues, $varValue); - $objUpdateStmt = $this->Database->prepare("UPDATE " . $this->strTable . " SET " . $this->strField . "=? WHERE " . implode(' AND ', $this->procedure)) + $objUpdateStmt = $this->Database->prepare("UPDATE " . $this->strTable . " SET " . \Database::quoteColumnName($this->strField) . "=? WHERE " . implode(' AND ', $this->procedure)) ->execute($arrValues); if ($objUpdateStmt->affectedRows) @@ -3877,7 +3877,7 @@ protected function generateTree($table, $id, $arrPrevNext, $blnHasSorting, $intM list($strKey, $strTable) = explode(':', $v); list($strTable, $strField) = explode('.', $strTable); - $objRef = $this->Database->prepare("SELECT " . $strField . " FROM " . $strTable . " WHERE id=?") + $objRef = $this->Database->prepare("SELECT " . \Database::quoteColumnName($strField) . " FROM " . $strTable . " WHERE id=?") ->limit(1) ->execute($objRow->$strKey); @@ -4187,7 +4187,7 @@ protected function parentView() { $arrForeignKey = explode('.', $GLOBALS['TL_DCA'][$this->ptable]['fields'][$v]['foreignKey'], 2); - $objLabel = $this->Database->prepare("SELECT " . $arrForeignKey[1] . " AS value FROM " . $arrForeignKey[0] . " WHERE id=?") + $objLabel = $this->Database->prepare("SELECT " . \Database::quoteColumnName($arrForeignKey[1]) . " AS value FROM " . $arrForeignKey[0] . " WHERE id=?") ->limit(1) ->execute($_v); @@ -4293,7 +4293,7 @@ protected function parentView() if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['foreignKey'])) { $key = explode('.', $GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['foreignKey'], 2); - $query = "SELECT *, (SELECT ". $key[1] ." FROM ". $key[0] ." WHERE ". $this->strTable .".". $firstOrderBy ."=". $key[0] .".id) AS foreignKey FROM " . $this->strTable; + $query = "SELECT *, (SELECT ". \Database::quoteColumnName($key[1]) ." FROM ". $key[0] ." WHERE ". $this->strTable .".". \Database::quoteColumnName($firstOrderBy) ."=". $key[0] .".id) AS foreignKey FROM " . $this->strTable; $orderBy[0] = 'foreignKey'; } } @@ -4668,7 +4668,7 @@ protected function listView() $firstOrderBy = 'pid'; $showFields = $GLOBALS['TL_DCA'][$table]['list']['label']['fields']; - $query .= " ORDER BY (SELECT " . $showFields[0] . " FROM " . $this->ptable . " WHERE " . $this->ptable . ".id=" . $this->strTable . ".pid), " . implode(', ', $orderBy); + $query .= " ORDER BY (SELECT " . \Database::quoteColumnName($showFields[0]) . " FROM " . $this->ptable . " WHERE " . $this->ptable . ".id=" . $this->strTable . ".pid), " . implode(', ', $orderBy); // Set the foreignKey so that the label is translated if ($GLOBALS['TL_DCA'][$table]['fields']['pid']['foreignKey'] == '') @@ -4805,7 +4805,7 @@ protected function listView() list($strKey, $strTable) = explode(':', $v); list($strTable, $strField) = explode('.', $strTable); - $objRef = $this->Database->prepare("SELECT " . $strField . " FROM " . $strTable . " WHERE id=?") + $objRef = $this->Database->prepare("SELECT " . \Database::quoteColumnName($strField) . " FROM " . $strTable . " WHERE id=?") ->limit(1) ->execute($row[$strKey]); @@ -5079,7 +5079,7 @@ protected function searchMenu() { try { - $this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE " . $strField . " REGEXP ?") + $this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE " . \Database::quoteColumnName($strField) . " REGEXP ?") ->limit(1) ->execute($strKeyword); } @@ -5110,12 +5110,12 @@ protected function searchMenu() if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$fld]['foreignKey'])) { list($t, $f) = explode('.', $GLOBALS['TL_DCA'][$this->strTable]['fields'][$fld]['foreignKey']); - $this->procedure[] = "(" . sprintf($strPattern, $fld) . " OR " . sprintf($strPattern, "(SELECT $f FROM $t WHERE $t.id={$this->strTable}.$fld)") . ")"; + $this->procedure[] = "(" . sprintf($strPattern, \Database::quoteColumnName($fld)) . " OR " . sprintf($strPattern, "(SELECT ".\Database::quoteColumnName($f)." FROM $t WHERE $t.id={$this->strTable}.".\Database::quoteColumnName($fld).")") . ")"; $this->values[] = $session['search'][$this->strTable]['value']; } else { - $this->procedure[] = sprintf($strPattern, $fld); + $this->procedure[] = sprintf($strPattern, \Database::quoteColumnName($fld)); } $this->values[] = $session['search'][$this->strTable]['value']; @@ -5718,7 +5718,7 @@ protected function filterMenu($intFilterPanel) { $key = explode('.', $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['foreignKey'], 2); - $objParent = $this->Database->prepare("SELECT " . $key[1] . " AS value FROM " . $key[0] . " WHERE id=?") + $objParent = $this->Database->prepare("SELECT " . \Database::quoteColumnName($key[1]) . " AS value FROM " . $key[0] . " WHERE id=?") ->limit(1) ->execute($vv); @@ -5745,7 +5745,7 @@ protected function filterMenu($intFilterPanel) $showFields[0] = 'id'; } - $objShowFields = $this->Database->prepare("SELECT " . $showFields[0] . " FROM ". $this->ptable . " WHERE id=?") + $objShowFields = $this->Database->prepare("SELECT " . \Database::quoteColumnName($showFields[0]) . " FROM ". $this->ptable . " WHERE id=?") ->limit(1) ->execute($vv); @@ -5871,7 +5871,7 @@ protected function formatCurrentValue($field, $value, $mode) { $key = explode('.', $GLOBALS['TL_DCA'][$this->strTable]['fields'][$field]['foreignKey'], 2); - $objParent = $this->Database->prepare("SELECT " . $key[1] . " AS value FROM " . $key[0] . " WHERE id=?") + $objParent = $this->Database->prepare("SELECT " . \Database::quoteColumnName($key[1]) . " AS value FROM " . $key[0] . " WHERE id=?") ->limit(1) ->execute($value); diff --git a/src/Resources/contao/library/Contao/Database.php b/src/Resources/contao/library/Contao/Database.php index 3fdd9e1bd3..edd86902d6 100644 --- a/src/Resources/contao/library/Contao/Database.php +++ b/src/Resources/contao/library/Contao/Database.php @@ -235,7 +235,7 @@ public function findInSet($strKey, $varSet, $blnIsField=false) $varSet = $this->resConnection->quote($varSet); } - return "FIND_IN_SET(" . $strKey . ", " . $varSet . ")"; + return "FIND_IN_SET(" . static::quoteColumnName($strKey) . ", " . $varSet . ")"; } @@ -490,7 +490,7 @@ public function getFieldNames($strTable, $blnNoCache=false) */ public function isUniqueValue($strTable, $strField, $varValue, $intId=null) { - $strQuery = "SELECT * FROM $strTable WHERE $strField=?"; + $strQuery = "SELECT * FROM $strTable WHERE " . static::quoteColumnName($strField) . "=?"; if ($intId !== null) { @@ -706,6 +706,32 @@ public function getUuid() } + /** + * Quote the column name if it is a reserved word + * + * @param string $strName + * + * @return string + */ + public static function quoteColumnName($strName) + { + return \System::getContainer()->get('database_connection')->getDatabasePlatform()->quoteSingleIdentifier($strName); + } + + + /** + * Quote a list of column names + * + * @param string[] $arrNames + * + * @return string[] + */ + public static function quoteColumnNames(array $arrNames) + { + return array_map(array(static::class, 'quoteColumnName'), $arrNames); + } + + /** * Execute a query and do not cache the result * diff --git a/src/Resources/contao/library/Contao/Database/Statement.php b/src/Resources/contao/library/Contao/Database/Statement.php index 290cc3080a..62c4afe5bd 100644 --- a/src/Resources/contao/library/Contao/Database/Statement.php +++ b/src/Resources/contao/library/Contao/Database/Statement.php @@ -182,7 +182,7 @@ public function set($arrParams) if (strncasecmp($this->strQuery, 'INSERT', 6) === 0) { $strQuery = sprintf('(%s) VALUES (%s)', - implode(', ', array_keys($arrParams)), + implode(', ', \Database::quoteColumnNames(array_keys($arrParams))), str_replace('%', '%%', implode(', ', array_values($arrParams)))); } @@ -193,7 +193,7 @@ public function set($arrParams) foreach ($arrParams as $k=>$v) { - $arrSet[] = $k . '=' . $v; + $arrSet[] = \Database::quoteColumnName($k) . '=' . $v; } $strQuery = 'SET ' . str_replace('%', '%%', implode(', ', $arrSet)); diff --git a/src/Resources/contao/library/Contao/Model.php b/src/Resources/contao/library/Contao/Model.php index 9acb79925d..f2f3f125c9 100644 --- a/src/Resources/contao/library/Contao/Model.php +++ b/src/Resources/contao/library/Contao/Model.php @@ -470,7 +470,7 @@ public function save() } // Update the row - $objDatabase->prepare("UPDATE " . static::$strTable . " %s WHERE " . static::$strPk . "=?") + $objDatabase->prepare("UPDATE " . static::$strTable . " %s WHERE " . \Database::quoteColumnName(static::$strPk) . "=?") ->set($arrSet) ->execute($intPk); @@ -563,7 +563,7 @@ public function delete() } // Delete the row - $intAffected = \Database::getInstance()->prepare("DELETE FROM " . static::$strTable . " WHERE " . static::$strPk . "=?") + $intAffected = \Database::getInstance()->prepare("DELETE FROM " . static::$strTable . " WHERE " . \Database::quoteColumnName(static::$strPk) . "=?") ->execute($intPk) ->affectedRows; @@ -624,7 +624,7 @@ public function getRelated($strKey, array $arrOptions=array()) elseif ($arrRelation['type'] == 'hasMany' || $arrRelation['type'] == 'belongsToMany') { $arrValues = \StringUtil::deserialize($this->$strKey, true); - $strField = $arrRelation['table'] . '.' . $arrRelation['field']; + $strField = $arrRelation['table'] . '.' . \Database::quoteColumnName($arrRelation['field']); // Handle UUIDs (see #6525) if ($strField == 'tl_files.uuid') @@ -668,7 +668,7 @@ public function refresh() } // Reload the database record - $res = \Database::getInstance()->prepare("SELECT * FROM " . static::$strTable . " WHERE " . static::$strPk . "=?") + $res = \Database::getInstance()->prepare("SELECT * FROM " . static::$strTable . " WHERE " . \Database::quoteColumnName(static::$strPk) . "=?") ->execute($intPk); $this->setRow($res->row()); diff --git a/src/Resources/contao/library/Contao/Model/QueryBuilder.php b/src/Resources/contao/library/Contao/Model/QueryBuilder.php index 7d02cd56aa..c3e4fffaee 100644 --- a/src/Resources/contao/library/Contao/Model/QueryBuilder.php +++ b/src/Resources/contao/library/Contao/Model/QueryBuilder.php @@ -53,10 +53,10 @@ public static function find(array $arrOptions) foreach (array_keys($objRelated->getFields()) as $strField) { - $arrFields[] = 'j' . $intCount . '.' . $strField . ' AS ' . $strKey . '__' . $strField; + $arrFields[] = 'j' . $intCount . '.' . \Database::quoteColumnName($strField) . ' AS ' . $strKey . '__' . $strField; } - $arrJoins[] = " LEFT JOIN " . $arrConfig['table'] . " j$intCount ON " . $arrOptions['table'] . "." . $strKey . "=j$intCount." . $arrConfig['field']; + $arrJoins[] = " LEFT JOIN " . $arrConfig['table'] . " j$intCount ON " . $arrOptions['table'] . "." . \Database::quoteColumnName($strKey) . "=j$intCount." . $arrConfig['field']; } } } @@ -68,7 +68,7 @@ public static function find(array $arrOptions) // Where condition if ($arrOptions['column'] !== null) { - $strQuery .= " WHERE " . (\is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . $arrOptions['column'] . "=?"); + $strQuery .= " WHERE " . (\is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . \Database::quoteColumnName($arrOptions['column']) . "=?"); } // Group by @@ -106,7 +106,7 @@ public static function count(array $arrOptions) if ($arrOptions['column'] !== null) { - $strQuery .= " WHERE " . (\is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . $arrOptions['column'] . "=?"); + $strQuery .= " WHERE " . (\is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . \Database::quoteColumnName($arrOptions['column']) . "=?"); } return $strQuery; diff --git a/src/Resources/contao/library/Contao/User.php b/src/Resources/contao/library/Contao/User.php index 213858e3d7..0be84f955f 100644 --- a/src/Resources/contao/library/Contao/User.php +++ b/src/Resources/contao/library/Contao/User.php @@ -555,7 +555,7 @@ protected function checkAccountStatus() */ public function findBy($strColumn, $varValue) { - $objResult = $this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE " . $strColumn . "=?") + $objResult = $this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE " . \Database::quoteColumnName($strColumn) . "=?") ->limit(1) ->execute($varValue); diff --git a/src/Resources/contao/widgets/FileSelector.php b/src/Resources/contao/widgets/FileSelector.php index d3cbb32bbc..19225b49f3 100644 --- a/src/Resources/contao/widgets/FileSelector.php +++ b/src/Resources/contao/widgets/FileSelector.php @@ -332,7 +332,7 @@ public function generateAjax($strFolder, $strField, $level, $mount=false) break; } - $objField = $this->Database->prepare("SELECT " . $this->strField . " FROM " . $this->strTable . " WHERE id=?") + $objField = $this->Database->prepare("SELECT " . \Database::quoteColumnName($this->strField) . " FROM " . $this->strTable . " WHERE id=?") ->limit(1) ->execute($this->strId); diff --git a/src/Resources/contao/widgets/FileTree.php b/src/Resources/contao/widgets/FileTree.php index b37c9e64c8..4b4322a434 100644 --- a/src/Resources/contao/widgets/FileTree.php +++ b/src/Resources/contao/widgets/FileTree.php @@ -70,7 +70,7 @@ public function __construct($arrAttributes=null) $this->strOrderName = $this->orderField . str_replace($this->strField, '', $this->strName); // Retrieve the order value - $objRow = $this->Database->prepare("SELECT {$this->orderField} FROM {$this->strTable} WHERE id=?") + $objRow = $this->Database->prepare("SELECT ".\Database::quoteColumnName($this->orderField)." FROM {$this->strTable} WHERE id=?") ->limit(1) ->execute($this->activeRecord->id); diff --git a/src/Resources/contao/widgets/PageSelector.php b/src/Resources/contao/widgets/PageSelector.php index 228b191794..ef6ab41395 100644 --- a/src/Resources/contao/widgets/PageSelector.php +++ b/src/Resources/contao/widgets/PageSelector.php @@ -292,7 +292,7 @@ public function generateAjax($id, $strField, $level) break; } - $objField = $this->Database->prepare("SELECT " . $this->strField . " FROM " . $this->strTable . " WHERE id=?") + $objField = $this->Database->prepare("SELECT " . \Database::quoteColumnName($this->strField) . " FROM " . $this->strTable . " WHERE id=?") ->limit(1) ->execute($this->strId); diff --git a/src/Resources/contao/widgets/PageTree.php b/src/Resources/contao/widgets/PageTree.php index fc006db39c..6ea6adaea1 100644 --- a/src/Resources/contao/widgets/PageTree.php +++ b/src/Resources/contao/widgets/PageTree.php @@ -66,7 +66,7 @@ public function __construct($arrAttributes=null) $this->strOrderName = $this->orderField . str_replace($this->strField, '', $this->strName); // Retrieve the order value - $objRow = $this->Database->prepare("SELECT {$this->orderField} FROM {$this->strTable} WHERE id=?") + $objRow = $this->Database->prepare("SELECT ".\Database::quoteColumnName($this->orderField)." FROM {$this->strTable} WHERE id=?") ->limit(1) ->execute($this->activeRecord->id);