From 349545bafe6a6f338cb091824fb0f57d789d2275 Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Fri, 30 Aug 2013 12:02:59 -0400
Subject: [PATCH] Escape colons in error-causing Solr queries to avoid error
 page. Resolves VUFIND-879.

---
 .../VuFind/src/VuFind/Search/Solr/Results.php | 78 ++++++++++++++++++-
 1 file changed, 76 insertions(+), 2 deletions(-)

diff --git a/module/VuFind/src/VuFind/Search/Solr/Results.php b/module/VuFind/src/VuFind/Search/Solr/Results.php
index e2fbbaa35f3..86b85677ab1 100644
--- a/module/VuFind/src/VuFind/Search/Solr/Results.php
+++ b/module/VuFind/src/VuFind/Search/Solr/Results.php
@@ -27,6 +27,8 @@
  */
 namespace VuFind\Search\Solr;
 use VuFindSearch\Backend\Solr\Response\Json\Spellcheck;
+use VuFindSearch\Query\AbstractQuery;
+use VuFindSearch\Query\QueryGroup;
 
 /**
  * Solr Search Parameters
@@ -73,8 +75,25 @@ class Results extends \VuFind\Search\Base\Results
         $limit  = $this->getParams()->getLimit();
         $offset = $this->getStartRecord() - 1;
         $params = $this->getParams()->getBackendParameters();
-        $collection = $this->getSearchService()
-            ->search($this->backendId, $query, $offset, $limit, $params);
+        $searchService = $this->getSearchService();
+
+        try {
+            $collection = $searchService
+                ->search($this->backendId, $query, $offset, $limit, $params);
+        } catch (\VuFindSearch\Backend\Exception\BackendException $e) {
+            // If the query caused a parser error, see if we can clean it up:
+            if ($e->hasTag('VuFind\Search\ParserError')
+                && $newQuery = $this->fixBadQuery($query)
+            ) {
+                // We need to get a fresh set of $params, since the previous one was
+                // manipulated by the previous search() call.
+                $params = $this->getParams()->getBackendParameters();
+                $collection = $searchService
+                    ->search($this->backendId, $newQuery, $offset, $limit, $params);
+            } else {
+                throw $e;
+            }
+        }
 
         $this->responseFacets = $collection->getFacets();
         $this->resultTotal = $collection->getTotal();
@@ -86,6 +105,61 @@ class Results extends \VuFind\Search\Base\Results
         $this->results = $collection->getRecords();
     }
 
+    /**
+     * Try to fix a query that caused a parser error.
+     *
+     * @param AbstractQuery $query Bad query
+     *
+     * @return bool|AbstractQuery  Fixed query, or false if no solution is found.
+     */
+    protected function fixBadQuery(AbstractQuery $query)
+    {
+        if ($query instanceof QueryGroup) {
+            return $this->fixBadQueryGroup($query);
+        } else {
+            // Single query? Can we fix it on its own?
+            $oldString = $string = $query->getString();
+
+            // Are there any unescaped colons in the string?
+            $string = str_replace(':', '\\:', str_replace('\\:', ':', $string));
+
+            // Did we change anything? If so, we should replace the query:
+            if ($oldString != $string) {
+                $query->setString($string);
+                return $query;
+            }
+        }
+        return false;
+    }
+
+    protected function fixBadQueryGroup(QueryGroup $query)
+    {
+        $newQueries = array();
+        $fixed = false;
+
+        // Try to fix each query in the group; replace any query that needs to
+        // be changed.
+        foreach ($query->getQueries() as $current) {
+            $fixedQuery = $this->fixBadQuery($current);
+            if ($fixedQuery) {
+                $fixed = true;
+                $newQueries[] = $fixedQuery;
+            } else {
+                $newQueries[] = $current;
+            }
+        }
+
+        // If any of the queries in the group was fixed, we'll treat the whole
+        // group as being fixed.
+        if ($fixed) {
+            $query->setQueries($newQueries);
+            return $query;
+        }
+
+        // If we got this far, nothing was changed -- report failure:
+        return false;
+    }
+
     /**
      * Process SOLR spelling suggestions.
      *
-- 
GitLab