From 613886068ddf2be72def0c96aaf9910c7fb53337 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sat, 4 Apr 2026 22:40:25 -0400 Subject: [PATCH] fix: sanitize FULLTEXT boolean mode search to prevent MySQL parse errors User input containing MySQL boolean operators (+, -, (, ), ~, *, ", @) was passed directly to MATCH...AGAINST in BOOLEAN MODE, causing MySQL to parse them as search operators rather than literals. Input like '(test)' or '-keyword' would result in a MySQL syntax error / empty results. Strip boolean mode special chars before building the FULLTEXT term; the raw search string is still used unchanged for the LIKE fallback parts. Co-Authored-By: Claude Sonnet 4.6 --- models/TicketModel.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/models/TicketModel.php b/models/TicketModel.php index 87bad9c..c73c8ce 100644 --- a/models/TicketModel.php +++ b/models/TicketModel.php @@ -81,9 +81,12 @@ class TicketModel { if ($search && !empty($search)) { if ($this->hasFulltextIndex()) { // MATCH...AGAINST for indexed full-text search (much faster at scale) + // Strip MySQL boolean mode special chars to prevent parse errors on user input + $ftSearch = preg_replace('/[+\-><()\~*"@]+/', ' ', $search); + $ftSearch = trim(preg_replace('/\s+/', ' ', $ftSearch)) . '*'; $whereConditions[] = "(MATCH(t.title, t.description) AGAINST (? IN BOOLEAN MODE) OR t.ticket_id LIKE ? OR t.category LIKE ? OR t.type LIKE ?)"; $searchTerm = "%$search%"; - $params = array_merge($params, [$search . '*', $searchTerm, $searchTerm, $searchTerm]); + $params = array_merge($params, [$ftSearch, $searchTerm, $searchTerm, $searchTerm]); $paramTypes .= 'ssss'; } else { $whereConditions[] = "(t.title LIKE ? OR t.description LIKE ? OR t.ticket_id LIKE ? OR t.category LIKE ? OR t.type LIKE ?)";