From 2aabb56d2dc2dd92b588351671e96c7ff0e28e29 Mon Sep 17 00:00:00 2001 From: James Cole Date: Thu, 30 Oct 2025 20:46:43 +0100 Subject: [PATCH] Fix https://github.com/firefly-iii/firefly-iii/issues/11134 --- .../Search/QueryParser/QueryParser.php | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/app/Support/Search/QueryParser/QueryParser.php b/app/Support/Search/QueryParser/QueryParser.php index bef27a0ec9..08d1c34e09 100644 --- a/app/Support/Search/QueryParser/QueryParser.php +++ b/app/Support/Search/QueryParser/QueryParser.php @@ -52,13 +52,23 @@ class QueryParser implements QueryParserInterface $inQuotes = false; $fieldName = ''; $prohibited = false; - - while ($this->position < strlen($this->query)) { - $char = $this->query[$this->position]; + $chrArray = preg_split('//u', $this->query, -1, PREG_SPLIT_NO_EMPTY); + $count = count($chrArray); + while ($this->position < $count) { + $char = $chrArray[$this->position]; + $nextChar = $chrArray[$this->position + 1] ?? ''; // Log::debug(sprintf('Char #%d: %s', $this->position, $char)); // If we're in a quoted string, we treat all characters except another quote as ordinary characters if ($inQuotes) { + if ('\\' === $char && '"' === $nextChar) { + // Log::debug('BACKSLASH!'); + // escaped quote, pretend it's a normal char and continue two places (skipping the actual character). + $tokenUnderConstruction .= '\\' . $nextChar; + $this->position += 2; + + continue; + } if ('"' !== $char) { $tokenUnderConstruction .= $char; ++$this->position; @@ -67,11 +77,9 @@ class QueryParser implements QueryParserInterface } // char is " ++$this->position; + Log::debug(sprintf('Constructed token: %s', $tokenUnderConstruction)); - return new NodeResult( - $this->createNode($tokenUnderConstruction, $fieldName, $prohibited), - false - ); + return new NodeResult($this->createNode($tokenUnderConstruction, $fieldName, $prohibited), false); } switch ($char) { @@ -139,7 +147,7 @@ class QueryParser implements QueryParserInterface if ('' === $tokenUnderConstruction) { // In any other location, it's just a normal character $tokenUnderConstruction .= $char; - $skipNext = true; + $skipNext = true; } if ('' !== $tokenUnderConstruction && !$skipNext) { // @phpstan-ignore-line Log::debug(sprintf('Turns out that "%s" is a field name. Reset the token.', $tokenUnderConstruction)); @@ -171,7 +179,7 @@ class QueryParser implements QueryParserInterface ++$this->position; } - $finalNode = '' !== $tokenUnderConstruction || '' !== $fieldName + $finalNode = '' !== $tokenUnderConstruction || '' !== $fieldName ? $this->createNode($tokenUnderConstruction, $fieldName, $prohibited) : null; @@ -184,7 +192,7 @@ class QueryParser implements QueryParserInterface $nodeResult = $this->buildNextNode($isSubquery); while ($nodeResult->node instanceof Node) { - $nodes[] = $nodeResult->node; + $nodes[] = $nodeResult->node; if ($nodeResult->isSubqueryEnd) { break; } @@ -197,9 +205,13 @@ class QueryParser implements QueryParserInterface private function createNode(string $token, string $fieldName, bool $prohibited): Node { if ('' !== $fieldName) { - Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true))); + // OK dus hoe trim je \" correct? $token = ltrim($token, ':"'); - $token = rtrim($token, '"'); + if (!str_ends_with($token, '\\"')) { + $token = rtrim($token, '"'); + } + $token = str_replace('\\"', '"', $token); + Log::debug(sprintf('Create FieldNode %s:%s (%s)', $fieldName, $token, var_export($prohibited, true))); return new FieldNode(trim($fieldName), trim($token), $prohibited); }