From 7d059540531e82c12b0aec2ad50e38a6788657cc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Thu, 17 Dec 2020 09:27:26 +0100 Subject: [PATCH] Remove AbstractSearchEngine::parseSearchQuery() Resolves #3815 --- .../search/AbstractSearchEngine.class.php | 92 +------------------ .../search/mysql/MysqlSearchEngine.class.php | 91 ++++++++++++++++++ 2 files changed, 94 insertions(+), 89 deletions(-) diff --git a/wcfsetup/install/files/lib/system/search/AbstractSearchEngine.class.php b/wcfsetup/install/files/lib/system/search/AbstractSearchEngine.class.php index 4283eb8f99..d9855a7346 100644 --- a/wcfsetup/install/files/lib/system/search/AbstractSearchEngine.class.php +++ b/wcfsetup/install/files/lib/system/search/AbstractSearchEngine.class.php @@ -2,7 +2,6 @@ namespace wcf\system\search; use wcf\system\database\util\PreparedStatementConditionBuilder; use wcf\system\SingletonFactory; -use wcf\util\StringUtil; /** * Default implementation for search engines, this class should be extended by @@ -34,99 +33,14 @@ abstract class AbstractSearchEngine extends SingletonFactory implements ISearchE } /** - * Manipulates the search term (< and > used as quotation marks): - * - * - becomes <+test* +foo*> - * - becomes <+test* -foo* +bar*> - * - becomes <+test* +"foo bar"> - * - * @see http://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html - * - * @param string $query - * @return string + * @deprecated 5.4 - This method is dangerous. See https://github.com/WoltLab/WCF/issues/3815. */ protected function parseSearchQuery($query) { - $query = StringUtil::trim($query); - - // expand search terms with a * unless they're encapsulated with quotes - $inQuotes = false; - $previousChar = $tmp = ''; - $controlCharacterOrSpace = false; - $chars = ['+', '-', '*']; - $ftMinWordLen = $this->getFulltextMinimumWordLength(); - for ($i = 0, $length = mb_strlen($query); $i < $length; $i++) { - $char = mb_substr($query, $i, 1); - - if ($inQuotes) { - if ($char == '"') { - $inQuotes = false; - } - } - else { - if ($char == '"') { - $inQuotes = true; - } - else { - if ($char == ' ' && !$controlCharacterOrSpace) { - $controlCharacterOrSpace = true; - $tmp .= '*'; - } - else if (in_array($char, $chars)) { - $controlCharacterOrSpace = true; - } - else { - $controlCharacterOrSpace = false; - } - } - } - - /* - * prepend a plus sign (logical AND) if ALL these conditions are given: - * - * 1) previous character: - * - is empty (start of string) - * - is a space (MySQL uses spaces to separate words) - * - * 2) not within quotation marks - * - * 3) current char: - * - is NOT +, - or * - */ - if (($previousChar == '' || $previousChar == ' ') && !$inQuotes && !in_array($char, $chars)) { - // check if the term is shorter than the minimum fulltext word length - if ($i + $ftMinWordLen <= $length) { - $term = '';// $char; - for ($j = $i, $innerLength = $ftMinWordLen + $i; $j < $innerLength; $j++) { - $currentChar = mb_substr($query, $j, 1); - if ($currentChar == '"' || $currentChar == ' ' || in_array($currentChar, $chars)) { - break; - } - - $term .= $currentChar; - } - - if (mb_strlen($term) == $ftMinWordLen) { - $tmp .= '+'; - } - } - } - - $tmp .= $char; - $previousChar = $char; - } - - // handle last char - if (!$inQuotes && !$controlCharacterOrSpace) { - $tmp .= '*'; - } - - return $tmp; + throw new \BadMethodCallException('Using the generic `parseSearchQuery()` method is dangerous. See WoltLab/WCF#3815 (https://github.com/WoltLab/WCF/issues/3815).'); } /** - * Returns minimum word length for fulltext indices. - * - * @return integer + * @deprecated 5.4 - This method was required for use in parseSearchQuery(). */ abstract protected function getFulltextMinimumWordLength(); diff --git a/wcfsetup/install/files/lib/system/search/mysql/MysqlSearchEngine.class.php b/wcfsetup/install/files/lib/system/search/mysql/MysqlSearchEngine.class.php index b460646775..c0899a4911 100644 --- a/wcfsetup/install/files/lib/system/search/mysql/MysqlSearchEngine.class.php +++ b/wcfsetup/install/files/lib/system/search/mysql/MysqlSearchEngine.class.php @@ -7,6 +7,7 @@ use wcf\system\search\AbstractSearchEngine; use wcf\system\search\SearchEngine; use wcf\system\search\SearchIndexManager; use wcf\system\WCF; +use wcf\util\StringUtil; /** * Search engine using MySQL's FULLTEXT index. @@ -124,6 +125,96 @@ class MysqlSearchEngine extends AbstractSearchEngine { ]; } + /** + * Manipulates the search term (< and > used as quotation marks): + * + * - becomes <+test* +foo*> + * - becomes <+test* -foo* +bar*> + * - becomes <+test* +"foo bar"> + * + * @see http://dev.mysql.com/doc/refman/5.5/en/fulltext-boolean.html + * + * @param string $query + * @return string + */ + protected function parseSearchQuery($query) { + $query = StringUtil::trim($query); + + // expand search terms with a * unless they're encapsulated with quotes + $inQuotes = false; + $previousChar = $tmp = ''; + $controlCharacterOrSpace = false; + $chars = ['+', '-', '*']; + $ftMinWordLen = $this->getFulltextMinimumWordLength(); + for ($i = 0, $length = mb_strlen($query); $i < $length; $i++) { + $char = mb_substr($query, $i, 1); + + if ($inQuotes) { + if ($char == '"') { + $inQuotes = false; + } + } + else { + if ($char == '"') { + $inQuotes = true; + } + else { + if ($char == ' ' && !$controlCharacterOrSpace) { + $controlCharacterOrSpace = true; + $tmp .= '*'; + } + else if (in_array($char, $chars)) { + $controlCharacterOrSpace = true; + } + else { + $controlCharacterOrSpace = false; + } + } + } + + /* + * prepend a plus sign (logical AND) if ALL these conditions are given: + * + * 1) previous character: + * - is empty (start of string) + * - is a space (MySQL uses spaces to separate words) + * + * 2) not within quotation marks + * + * 3) current char: + * - is NOT +, - or * + */ + if (($previousChar == '' || $previousChar == ' ') && !$inQuotes && !in_array($char, $chars)) { + // check if the term is shorter than the minimum fulltext word length + if ($i + $ftMinWordLen <= $length) { + $term = '';// $char; + for ($j = $i, $innerLength = $ftMinWordLen + $i; $j < $innerLength; $j++) { + $currentChar = mb_substr($query, $j, 1); + if ($currentChar == '"' || $currentChar == ' ' || in_array($currentChar, $chars)) { + break; + } + + $term .= $currentChar; + } + + if (mb_strlen($term) == $ftMinWordLen) { + $tmp .= '+'; + } + } + } + + $tmp .= $char; + $previousChar = $char; + } + + // handle last char + if (!$inQuotes && !$controlCharacterOrSpace) { + $tmp .= '*'; + } + + return $tmp; + } + /** * @inheritDoc */ -- 2.20.1