00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00088 class tslib_search {
00089 var $tables = Array ();
00090
00091 var $group_by = 'PRIMARY_KEY';
00092 var $default_operator = 'AND';
00093 var $operator_translate_table_caseinsensitive = TRUE;
00094 var $operator_translate_table = Array (
00095 Array ('+' , 'AND'),
00096 Array ('|' , 'AND'),
00097 Array ('-' , 'AND NOT'),
00098
00099 Array ('and' , 'AND'),
00100 Array ('or' , 'OR'),
00101 Array ('not' , 'AND NOT'),
00102 );
00103
00104
00105 var $sword_array;
00106 var $queryParts;
00107
00108 var $other_where_clauses;
00109 var $fTable;
00110
00111 var $res_offset = 0;
00112 var $res_shows = 20;
00113 var $res_count;
00114
00115 var $pageIdList='';
00116
00117 var $listOfSearchFields ='';
00118
00127 function register_tables_and_columns($requestedCols,$allowedCols) {
00128 $rCols=$this->explodeCols($requestedCols);
00129 $aCols=$this->explodeCols($allowedCols);
00130
00131 foreach ($rCols as $k => $v) {
00132 $rCols[$k]=trim($v);
00133 if (in_array($rCols[$k], $aCols)) {
00134 $parts = explode('.',$rCols[$k]);
00135 $this->tables[$parts[0]]['searchfields'][] = $parts[1];
00136 }
00137 }
00138 $this->tables['pages']['primary_key'] = 'uid';
00139 $this->tables['pages']['resultfields'][] = 'uid';
00140 unset($this->tables['pages']['fkey']);
00141
00142 foreach ($aCols as $k => $v) {
00143 $aCols[$k]=trim($v);
00144 $parts = explode('.',$aCols[$k]);
00145 $this->tables[$parts[0]]['resultfields'][] = $parts[1].' AS '.str_replace('.','_',$aCols[$k]);
00146 $this->tables[$parts[0]]['fkey']='pid';
00147 }
00148
00149 $this->fTable='';
00150 foreach ($this->tables as $t => $v) {
00151 if ($t!='pages') {
00152 if (!$this->fTable) {
00153 $this->fTable = $t;
00154 } else {
00155 unset($this->tables[$t]);
00156 }
00157 }
00158 }
00159 }
00160
00168 function explodeCols($in) {
00169 $theArray = explode(':',$in);
00170 $out = Array();
00171 while(list(,$val)=each($theArray)) {
00172 $val=trim($val);
00173 $parts = explode('.',$val);
00174 if ($parts[0] && $parts[1]) {
00175 $subparts = explode('-',$parts[1]);
00176 while(list(,$piece)=each($subparts)) {
00177 $piece=trim($piece);
00178 if ($piece) $out[]=$parts[0].'.'.$piece;
00179 }
00180 }
00181 }
00182 return $out;
00183 }
00184
00193 function register_and_explode_search_string($sword) {
00194 $sword = trim($sword);
00195 if ($sword) {
00196 $components = $this->split($sword);
00197 $s_sword = '';
00198 if (is_array($components)) {
00199 $i=0;
00200 $lastoper = '';
00201 reset($components);
00202 while (list($key,$val) = each ($components)) {
00203 $operator=$this->get_operator($val);
00204 if ($operator) {
00205 $lastoper = $operator;
00206 } elseif (strlen($val)>1) {
00207 $this->sword_array[$i]['sword'] = $val;
00208 $this->sword_array[$i]['oper'] = ($lastoper) ? $lastoper : $this->default_operator;
00209 $lastoper = '';
00210 $i++;
00211 }
00212 }
00213 }
00214 }
00215 }
00216
00226 function split($origSword, $specchars='+-', $delchars='+.,-') {
00227 $sword = $origSword;
00228 $specs = '['.$this->quotemeta($specchars).']';
00229 $delchars = '['.$this->quotemeta($delchars).']';
00230
00231
00232 while ($sword) {
00233 if (ereg('^"',$sword)) { // There was a double-quote and we will then look for the ending quote.
00234 $sword = ereg_replace('^"','',$sword);
00235 ereg('^[^"]*',$sword,$reg); // Removes everything till next double-quote
00236 $value[] = $reg[0]; // reg[0] is the value, should not be trimmed
00237 $sword = ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword);
00238 $sword = trim(ereg_replace('^"','',$sword));
00239 } elseif (ereg('^'.$specs,$sword,$reg)) {
00240 $value[] = $reg[0];
00241 $sword = trim(ereg_replace('^'.$specs,'',$sword));
00242 } elseif (ereg('[\+\-]',$sword)) {
00243
00244
00245 $a_sword = explode(' ',$sword);
00246 $word = array_shift($a_sword);
00247 $word = ereg_replace($delchars.'$','',$word);
00248 $value[] = $word;
00249 $sword = implode(' ',$a_sword);
00250 } else {
00251
00252 ereg('^[^ '.$this->quotemeta($specchars).']*',$sword,$reg);
00253 $word = ereg_replace($delchars.'$','',trim($reg[0]));
00254 $value[] = $word;
00255 $sword = trim(ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword));
00256 }
00257 }
00258
00259 return $value;
00260 }
00261
00269 function quotemeta($str) {
00270 $str = str_replace('|','\|',quotemeta($str));
00271 #$str = str_replace('-','\-',$str); // Breaks "-" which should NOT have a slash before it inside of [ ] in a regex.
00272 return $str;
00273 }
00274
00285 function build_search_query($endClause) {
00286
00287 if (is_array($this->tables)) {
00288 $tables = $this->tables;
00289 $primary_table = '';
00290
00291
00292 foreach($tables as $key => $val) {
00293 if ($tables[$key]['primary_key']) {$primary_table = $key;}
00294 }
00295
00296 if ($primary_table) {
00297
00298
00299 $this->queryParts = array(
00300 'SELECT' => '',
00301 'FROM' => '',
00302 'WHERE' => '',
00303 'GROUPBY' => '',
00304 'ORDERBY' => '',
00305 'LIMIT' => '',
00306 );
00307
00308
00309 $fieldArray = array();
00310 $tableArray = array();
00311 foreach($tables as $key => $val) {
00312 $tableArray[] = $key;
00313 $resultfields = $tables[$key]['resultfields'];
00314 if (is_array($resultfields)) {
00315 foreach($resultfields as $key2 => $val2) {
00316 $fieldArray[] = $key.'.'.$val2;
00317 }
00318 }
00319 }
00320 $this->queryParts['SELECT'] = implode(',',$fieldArray);
00321 $this->queryParts['FROM'] = implode(',',$tableArray);
00322
00323
00324 $whereArray = array();
00325
00326 $primary_table_and_key = $primary_table.'.'.$tables[$primary_table]['primary_key'];
00327 $primKeys = Array();
00328 foreach($tables as $key => $val) {
00329 $fkey = $tables[$key]['fkey'];
00330 if ($fkey) {
00331 $primKeys[] = $key.'.'.$fkey.'='.$primary_table_and_key;
00332 }
00333 }
00334 if (count($primKeys)) {
00335 $whereArray[] = '('.implode(' OR ',$primKeys).')';
00336 }
00337
00338
00339 if (trim($endClause)) {
00340 $whereArray[] = trim($endClause);
00341 }
00342
00343
00344 $query_part = $this->build_search_query_for_searchwords();
00345 if (!$query_part) {
00346 $query_part = '(0!=0)';
00347 }
00348 $whereArray[] = '('.$query_part.')';
00349
00350
00351 $this->queryParts['WHERE'] = implode(' AND ',$whereArray);
00352
00353
00354 if ($this->group_by) {
00355 if ($this->group_by == 'PRIMARY_KEY') {
00356 $this->queryParts['GROUPBY'] = $primary_table_and_key;
00357 } else {
00358 $this->queryParts['GROUPBY'] = $this->group_by;
00359 }
00360 }
00361 }
00362 }
00363 }
00364
00371 function build_search_query_for_searchwords() {
00372
00373 if (is_array($this->sword_array)) {
00374 $main_query_part = array();
00375
00376 foreach($this->sword_array as $key => $val) {
00377 $s_sword = $this->sword_array[$key]['sword'];
00378
00379
00380 $sub_query_part = array();
00381
00382 $this->listOfSearchFields='';
00383 foreach($this->tables as $key3 => $val3) {
00384 $searchfields = $this->tables[$key3]['searchfields'];
00385 if (is_array($searchfields)) {
00386 foreach($searchfields as $key2 => $val2) {
00387 $this->listOfSearchFields.= $key3.'.'.$val2.',';
00388 $sub_query_part[] = $key3.'.'.$val2.' LIKE \'%'.$GLOBALS['TYPO3_DB']->quoteStr($s_sword, $key3).'%\'';
00389 }
00390 }
00391 }
00392
00393 if (count($sub_query_part)) {
00394 $main_query_part[] = $this->sword_array[$key]['oper'];
00395 $main_query_part[] = '('.implode(' OR ',$sub_query_part).')';
00396 }
00397 }
00398
00399 if (count($main_query_part)) {
00400 unset($main_query_part[0]);
00401 return implode(' ',$main_query_part);
00402 }
00403 }
00404 }
00405
00413 function get_operator($operator) {
00414 $operator = trim($operator);
00415 $op_array = $this->operator_translate_table;
00416 reset ($op_array);
00417 if ($this->operator_translate_table_caseinsensitive) {
00418 $operator = strtolower($operator);
00419 }
00420 while (list($key,$val) = each($op_array)) {
00421 $item = $op_array[$key][0];
00422 if ($this->operator_translate_table_caseinsensitive) {
00423 $item = strtolower($item);
00424 }
00425 if ($operator==$item) {
00426 return $op_array[$key][1];
00427 }
00428 }
00429 }
00430
00436 function count_query() {
00437 if (is_array($this->queryParts)) {
00438 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($this->queryParts['SELECT'], $this->queryParts['FROM'], $this->queryParts['WHERE'], $this->queryParts['GROUPBY']);
00439 $this->res_count = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
00440 return TRUE;
00441 }
00442 }
00443
00449 function execute_query() {
00450 if (is_array($this->queryParts)) {
00451 $this->result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($this->queryParts);
00452 return TRUE;
00453 }
00454 }
00455
00462 function get_searchwords() {
00463 $SWORD_PARAMS = '';
00464 if (is_array($this->sword_array)) {
00465 foreach($this->sword_array as $key => $val) {
00466 $SWORD_PARAMS.= '&sword_list[]='.rawurlencode($val['sword']);
00467 }
00468 }
00469 return $SWORD_PARAMS;
00470 }
00471
00477 function get_searchwordsArray() {
00478 if (is_array($this->sword_array)) {
00479 foreach($this->sword_array as $key => $val) {
00480 $swords[] = $val['sword'];
00481 }
00482 }
00483 return $swords;
00484 }
00485 }
00486
00487
00488
00489
00490 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_search.php']) {
00491 include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['tslib/class.tslib_search.php']);
00492 }
00493
00494 ?>