1<?php 2/* 3 +-----------------------------------------------------------------------------+ 4 | ILIAS open source | 5 +-----------------------------------------------------------------------------+ 6 | Copyright (c) 1998-2001 ILIAS open source, University of Cologne | 7 | | 8 | This program is free software; you can redistribute it and/or | 9 | modify it under the terms of the GNU General Public License | 10 | as published by the Free Software Foundation; either version 2 | 11 | of the License, or (at your option) any later version. | 12 | | 13 | This program is distributed in the hope that it will be useful, | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 16 | GNU General Public License for more details. | 17 | | 18 | You should have received a copy of the GNU General Public License | 19 | along with this program; if not, write to the Free Software | 20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 21 +-----------------------------------------------------------------------------+ 22*/ 23 24/** 25* Class ilQueryParser 26* 27* Class for parsing search queries. An instance of this object is required for every Search class (MetaSearch ...) 28* 29* @author Stefan Meyer <meyer@leifos.com> 30* @version $Id$ 31* 32* @package ilias-search 33* 34*/ 35define('QP_COMBINATION_AND', 'and'); 36define('QP_COMBINATION_OR', 'or'); 37 38class ilQueryParser 39{ 40 /** 41 * Minimum of characters required for search 42 */ 43 const MIN_WORD_LENGTH = 3; 44 45 public $lng = null; 46 47 public $min_word_length = 0; 48 public $global_min_length = null; 49 50 public $query_str; 51 public $quoted_words = array(); 52 public $message; // Translated error message 53 public $combination; // combiniation of search words e.g 'and' or 'or' 54 protected $settings = null; 55 protected $wildcards_allowed; // [bool] 56 57 /** 58 * Constructor 59 * @access public 60 */ 61 public function __construct($a_query_str) 62 { 63 global $DIC; 64 65 $lng = $DIC['lng']; 66 67 define('MIN_WORD_LENGTH', self::MIN_WORD_LENGTH); 68 69 $this->lng = $lng; 70 71 $this->query_str = $a_query_str; 72 $this->message = ''; 73 74 include_once './Services/Search/classes/class.ilSearchSettings.php'; 75 $this->settings = ilSearchSettings::getInstance(); 76 77 if (!$this->setMinWordLength(1)) { 78 $this->setMinWordLength(MIN_WORD_LENGTH); 79 } 80 81 $this->setAllowedWildcards(false); 82 } 83 84 public function setMinWordLength($a_length, $a_force = false) 85 { 86 // Due to a bug in mysql fulltext search queries with min_word_legth < 3 87 // might freeze the system. 88 // Thus min_word_length cannot be set to values < 3 if the mysql fulltext is used. 89 if (!$a_force and $this->settings->enabledIndex() and $a_length < 3) { 90 ilLoggerFactory::getLogger('src')->debug('Disabled min word length'); 91 return false; 92 } 93 $this->min_word_length = $a_length; 94 return true; 95 } 96 public function getMinWordLength() 97 { 98 return $this->min_word_length; 99 } 100 101 public function setGlobalMinLength($a_value) 102 { 103 if ($a_value !== null) { 104 $a_value = (int) $a_value; 105 if ($a_value < 1) { 106 return; 107 } 108 } 109 $this->global_min_length = $a_value; 110 } 111 112 public function getGlobalMinLength() 113 { 114 return $this->global_min_length; 115 } 116 117 public function setAllowedWildcards($a_value) 118 { 119 $this->wildcards_allowed = (bool) $a_value; 120 } 121 122 public function getAllowedWildcards() 123 { 124 return $this->wildcards_allowed; 125 } 126 127 public function setMessage($a_msg) 128 { 129 $this->message = $a_msg; 130 } 131 public function getMessage() 132 { 133 return $this->message; 134 } 135 public function appendMessage($a_msg) 136 { 137 if (strlen($this->getMessage())) { 138 $this->message .= '<br />'; 139 } 140 $this->message .= $a_msg; 141 } 142 143 public function setCombination($a_combination) 144 { 145 $this->combination = $a_combination; 146 } 147 public function getCombination() 148 { 149 return $this->combination; 150 } 151 152 public function getQueryString() 153 { 154 return trim($this->query_str); 155 } 156 public function getWords() 157 { 158 return $this->words ? $this->words : array(); 159 } 160 161 public function getQuotedWords($with_quotation = false) 162 { 163 if ($with_quotation) { 164 return $this->quoted_words ? $this->quoted_words : array(); 165 } else { 166 foreach ($this->quoted_words as $word) { 167 $tmp_word[] = str_replace('\"', '', $word); 168 } 169 return $tmp_word ? $tmp_word : array(); 170 } 171 } 172 173 public function getLuceneQueryString() 174 { 175 $counter = 0; 176 $tmp_str = ""; 177 foreach ($this->getQuotedWords(true) as $word) { 178 if ($counter++) { 179 $tmp_str .= (" " . strtoupper($this->getCombination()) . " "); 180 } 181 $tmp_str .= $word; 182 } 183 return $tmp_str; 184 } 185 public function parse() 186 { 187 $this->words = array(); 188 189 #if(!strlen($this->getQueryString())) 190 #{ 191 # return false; 192 #} 193 194 $words = explode(' ', trim($this->getQueryString())); 195 foreach ($words as $word) { 196 if (!strlen(trim($word))) { 197 continue; 198 } 199 200 if (strlen(trim($word)) < $this->getMinWordLength()) { 201 $this->setMessage(sprintf($this->lng->txt('search_minimum_info'), $this->getMinWordLength())); 202 continue; 203 } 204 205 $this->words[] = ilUtil::prepareDBString($word); 206 } 207 208 $fullstr = trim($this->getQueryString()); 209 if (!in_array($fullstr, $this->words)) { 210 $this->words[] = ilUtil::prepareDBString($fullstr); 211 } 212 213 if (!$this->getAllowedWildcards()) { 214 // #14768 215 foreach ($this->words as $idx => $word) { 216 if (!stristr($word, '\\')) { 217 $word = str_replace('%', '\%', $word); 218 $word = str_replace('_', '\_', $word); 219 } 220 $this->words[$idx] = $word; 221 } 222 } 223 224 // Parse strings like && 'A "B C D" E' as 'A' && 'B C D' && 'E' 225 // Can be used in LIKE search or fulltext search > MYSQL 4.0 226 $this->__parseQuotation(); 227 228 return true; 229 } 230 231 public function __parseQuotation() 232 { 233 if (!strlen($this->getQueryString())) { 234 $this->quoted_words[] = ''; 235 return false; 236 } 237 $query_str = $this->getQueryString(); 238 while (preg_match("/\".*?\"/", $query_str, $matches)) { 239 $query_str = str_replace($matches[0], '', $query_str); 240 $this->quoted_words[] = ilUtil::prepareDBString($matches[0]); 241 } 242 243 // Parse the rest 244 $words = explode(' ', trim($query_str)); 245 foreach ($words as $word) { 246 if (!strlen(trim($word))) { 247 continue; 248 } 249 250 $this->quoted_words[] = ilUtil::prepareDBString($word); 251 } 252 253 if (!$this->getAllowedWildcards()) { 254 // #14768 255 foreach ($this->quoted_words as $idx => $word) { 256 if (!stristr($word, '\\')) { 257 $word = str_replace('%', '\%', $word); 258 $word = str_replace('_', '\_', $word); 259 } 260 $this->quoted_words[$idx] = $word; 261 } 262 } 263 } 264 265 public function validate() 266 { 267 // Words with less than 3 characters 268 if (strlen($this->getMessage())) { 269 return false; 270 } 271 // No search string given 272 if ($this->getMinWordLength() and !count($this->getWords())) { 273 $this->setMessage($this->lng->txt('msg_no_search_string')); 274 return false; 275 } 276 // No search string given 277 if ($this->getGlobalMinLength() and strlen(str_replace('"', '', $this->getQueryString())) < $this->getGlobalMinLength()) { 278 $this->setMessage(sprintf($this->lng->txt('search_minimum_info'), $this->getGlobalMinLength())); 279 return false; 280 } 281 282 return true; 283 } 284} 285