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