From 74192097b99bfec094adb0f3f496045737213412 Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Wed, 19 Aug 2015 08:47:33 -0500
Subject: [PATCH] search: Fix query crash for multiple operators

The system would encode 'access -related' as 'access+-related' when changing
the sorting preference and would crash the query. This patch fixes the
search engine code to avoid a BOOLEAN MODE search when improper operators
are used in the query terms, and it fixes the sorting preference system to
properly decode the '+' to a space when rewriting the URL.
---
 include/class.search.php      | 14 +++++---------
 include/staff/tickets.inc.php |  2 +-
 scp/js/scp.js                 |  2 +-
 3 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/include/class.search.php b/include/class.search.php
index 8965f2e45..74dc48638 100644
--- a/include/class.search.php
+++ b/include/class.search.php
@@ -330,16 +330,15 @@ class MysqlSearchBackend extends SearchBackend {
         $criteria = clone $criteria;
 
         $mode = ' IN NATURAL LANGUAGE MODE';
-        // If using boolean operators, search in boolean mode
-        if (preg_match('/["+<>(~-]\w|\w["*)]/u', $query, $T = array()))
+        // If using boolean operators, search in boolean mode. This regex
+        // will ensure proper placement of operators, whitespace, and quotes
+        // in an effort to avoid crashing the query at MySQL
+        if (preg_match('/^(?:[(+<>~-]*(\w+[*]?|"[^"]+")[)]?(\s+|$))+$/u', $query, $T = array()))
             $mode = ' IN BOOLEAN MODE';
-        #if (count(explode(' ', $query)) == 1)
+        #elseif (count(explode(' ', $query)) == 1)
         #    $mode = ' WITH QUERY EXPANSION';
         $query = $this->quote($query);
         $search = 'MATCH (Z1.title, Z1.content) AGAINST ('.db_input($query).$mode.')';
-        $tables = array();
-        $P = TABLE_PREFIX;
-        $sort = '';
 
         switch ($criteria->model) {
         case false:
@@ -353,10 +352,7 @@ class MysqlSearchBackend extends SearchBackend {
                         "(SELECT COALESCE(Z3.`object_id`, Z5.`ticket_id`) as `ticket_id`, {} AS `relevance` FROM `:_search` Z1 LEFT JOIN `:thread_entry` Z2 ON (Z1.`object_type` = 'H' AND Z1.`object_id` = Z2.`id`) LEFT JOIN `:thread` Z3 ON (Z2.`thread_id` = Z3.`id` AND Z3.`object_type` = 'T') LEFT JOIN `:ticket` Z5 ON (Z1.`object_type` = 'T' AND Z1.`object_id` = Z5.`ticket_id`) WHERE {}) Z1"),
                 )
             ));
-            // XXX: This is extremely ugly
             $criteria->filter(array('ticket_id'=>new SqlCode('Z1.`ticket_id`')))->distinct('ticket_id');
-
-            // TODO: Consider sorting preferences
         }
 
         // TODO: Ensure search table exists;
diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php
index 7b7cddd23..8438ac2d4 100644
--- a/include/staff/tickets.inc.php
+++ b/include/staff/tickets.inc.php
@@ -340,7 +340,7 @@ return false;">
     <input type="hidden" name="search-type" value=""/>
     <div class="attached input">
       <input type="text" class="basic-search" data-url="ajax.php/tickets/lookup" name="query"
-        autofocus size="30" value="<?php echo Format::htmlchars(urldecode($_REQUEST['query']), true); ?>"
+        autofocus size="30" value="<?php echo Format::htmlchars($_REQUEST['query'], true); ?>"
         autocomplete="off" autocorrect="off" autocapitalize="off">
       <button type="submit" class="attached button"><i class="icon-search"></i>
       </button>
diff --git a/scp/js/scp.js b/scp/js/scp.js
index a47af3361..fe090490a 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -1173,7 +1173,7 @@ function __(s) {
 
 // Thanks, http://stackoverflow.com/a/487049
 function addSearchParam(data) {
-    var kvp = document.location.search.substr(1).split('&');
+    var kvp = document.location.search.substr(1).replace('+', ' ').split('&');
     var i=kvp.length, x, params = {};
     while (i--) {
         x = kvp[i].split('=');
-- 
GitLab