Fixed bug #14021: Simplify the code to get nested GET Parameters with TS
[Packages/TYPO3.CMS.git] / typo3 / sysext / cms / tslib / class.tslib_search.php
old mode 100755 (executable)
new mode 100644 (file)
index f5aee55..92ff3e2
@@ -1,22 +1,22 @@
 <?php
 /***************************************************************
 *  Copyright notice
-*  
-*  (c) 1999-2004 Kasper Skaarhoj (kasper@typo3.com)
+*
+*  (c) 1999-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
-*  This script is part of the TYPO3 project. The TYPO3 project is 
+*  This script is part of the TYPO3 project. The TYPO3 project is
 *  free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
-* 
+*
 *  The GNU General Public License can be found at
 *  http://www.gnu.org/copyleft/gpl.html.
-*  A copy is found in the textfile GPL.txt and important notices to the license 
+*  A copy is found in the textfile GPL.txt and important notices to the license
 *  from the author is found in LICENSE.txt distributed with these scripts.
 *
-* 
+*
 *  This script is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -24,7 +24,7 @@
 *
 *  This copyright notice MUST APPEAR in all copies of the script!
 ***************************************************************/
-/** 
+/**
  * Searching in database tables, typ. "pages" and "tt_content"
  * Used to generate search queries for TypoScript.
  * The class is included from "class.tslib_pagegen.php" based on whether there has been detected content in the GPvar "sword"
@@ -32,7 +32,7 @@
  * $Id$
  * Revised for TYPO3 3.6 June/2003 by Kasper Skaarhoj
  *
- * @author     Kasper Skaarhoj <kasper@typo3.com>
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
  * @author     Rene Fritz      <r.fritz@colorcube.de>
  */
 /**
  *
  *
  *
- *   88: class tslib_search 
- *  130:     function register_tables_and_columns($requestedCols,$allowedCols) 
- *  171:     function explodeCols($in) 
- *  196:     function register_and_explode_search_string($sword)       
- *  229:     function split($origSword, $specchars='+-')       
- *  260:     function quotemeta($str)  
- *  274:     function build_search_query($endClause) 
- *  360:     function build_search_query_for_searchwords()     
- *  402:     function get_operator($operator)  
- *  425:     function count_query() 
- *  438:     function execute_query() 
- *  451:     function get_searchwords()        
- *  466:     function get_searchwordsArray()   
+ *   88: class tslib_search
+ *  127:     function register_tables_and_columns($requestedCols,$allowedCols)
+ *  168:     function explodeCols($in)
+ *  193:     function register_and_explode_search_string($sword)
+ *  226:     function split($origSword, $specchars='+-', $delchars='+.,-')
+ *  269:     function quotemeta($str)
+ *  285:     function build_search_query($endClause)
+ *  371:     function build_search_query_for_searchwords()
+ *  413:     function get_operator($operator)
+ *  436:     function count_query()
+ *  449:     function execute_query()
+ *  462:     function get_searchwords()
+ *  477:     function get_searchwordsArray()
  *
  * TOTAL FUNCTIONS: 12
  * (This index is automatically created/updated by the extension "extdeveval")
  */
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 /**
  * Search class used for the content object SEARCHRESULT
  *
- * @author     Kasper Skaarhoj <kasper@typo3.com>
+ * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
  * @package TYPO3
  * @subpackage tslib
  * @see        tslib_cObj::SEARCHRESULT()
@@ -90,18 +90,15 @@ class tslib_search {
 
        var $group_by = 'PRIMARY_KEY';                                                  // Alternatively 'PRIMARY_KEY'; sorting by primary key
        var $default_operator = 'AND';                                                  // Standard SQL-operator between words
-       var $operator_translate_table_caseinsensitive = '1';
+       var $operator_translate_table_caseinsensitive = TRUE;
        var $operator_translate_table = Array (                                 // case-sensitiv. Defineres the words, which will be operators between words
                Array ('+' , 'AND'),
+               Array ('|' , 'AND'),
                Array ('-' , 'AND NOT'),
                        // english
-               Array ('AND' , 'AND'),
-               Array ('OR' , 'OR'),
-               Array ('NOT' , 'AND NOT'),
-                       // danish
-               Array ('OG' , 'AND'),
-               Array ('ELLER' , 'OR'),
-               Array ('UDEN' , 'AND NOT')
+               Array ('and' , 'AND'),
+               Array ('or' , 'OR'),
+               Array ('not' , 'AND NOT'),
        );
 
        // Internal
@@ -114,9 +111,9 @@ class tslib_search {
        var $res_offset = 0;    // How many rows to offset from the beginning
        var $res_shows = 20;    // How many results to show (0 = no limit)
        var $res_count;                 // Intern: How many results, there was last time (with the exact same searchstring.
-       
+
        var $pageIdList='';             // List of pageIds.
-       
+
        var $listOfSearchFields ='';
 
        /**
@@ -130,7 +127,7 @@ class tslib_search {
        function register_tables_and_columns($requestedCols,$allowedCols)       {
                $rCols=$this->explodeCols($requestedCols);
                $aCols=$this->explodeCols($allowedCols);
-               
+
                foreach ($rCols as $k => $v)    {
                        $rCols[$k]=trim($v);
                        if (in_array($rCols[$k], $aCols))       {
@@ -219,46 +216,59 @@ class tslib_search {
 
        /**
         * Used to split a search-word line up into elements to search for. This function will detect boolean words like AND and OR, + and -, and even find sentences encapsulated in ""
-        * This function also has the charm of still containing some of the original comments - in danish!
         * This function could be re-written to be more clean and effective - yet it's not that important.
         *
         * @param       string          The raw sword string from outside
         * @param       string          Special chars which are used as operators (+- is default)
+        * @param       string          Special chars which are deleted if the append the searchword (+-., is default)
         * @return      mixed           Returns an ARRAY if there were search words, othervise the return value may be unset.
         */
-       function split($origSword, $specchars='+-')     {
+       function split($origSword, $specchars='+-', $delchars='+.,-')   {
                $sword = $origSword;
                $specs = '['.$this->quotemeta($specchars).']';
 
                        // As long as $sword is true (that means $sword MUST be reduced little by little until its empty inside the loop!)
                while ($sword)  {
-                       if (ereg('^"',$sword))  {               // There was a double-quote and we will then look for the ending quote.
-                               $sword = ereg_replace('^"','',$sword);          // Removes first double-quote
-                               ereg('^[^"]*',$sword,$reg);  // Removes everything till next double-quote
+                       if (preg_match('/^"/',$sword))  {               // There was a double-quote and we will then look for the ending quote.
+                               $sword = preg_replace('/^"/','',$sword);                // Removes first double-quote
+                               preg_match('/^[^"]*/',$sword,$reg);  // Removes everything till next double-quote
                                $value[] = $reg[0];  // reg[0] is the value, should not be trimmed
-                               $sword = ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword);
-                               $sword = trim(ereg_replace('^"','',$sword));            // Removes last double-quote
-                       } elseif (ereg('^'.$specs,$sword,$reg)) {
+                               $sword = preg_replace('/^'.$this->quotemeta($reg[0]).'/','',$sword);
+                               $sword = trim(preg_replace('/^"/','',$sword));          // Removes last double-quote
+                       } elseif (preg_match('/^'.$specs.'/',$sword,$reg)) {
                                $value[] = $reg[0];
-                               $sword = trim(ereg_replace('^'.$specs,'',$sword));              // Removes = sign
+                               $sword = trim(preg_replace('/^'.$specs.'/','',$sword));         // Removes = sign
+                       } elseif (preg_match('/[\+\-]/',$sword)) {      // Check if $sword contains + or -
+                                       // + and - shall only be interpreted as $specchars when there's whitespace before it
+                                       // otherwise it's included in the searchword (e.g. "know-how")
+                               $a_sword = explode(' ',$sword); // explode $sword to single words
+                               $word = array_shift($a_sword);  // get first word
+                               $word = rtrim($word, $delchars);                // Delete $delchars at end of string
+                               $value[] = $word;       // add searchword to values
+                               $sword = implode(' ',$a_sword); // re-build $sword
                        } else {
-                                       // There are no double-quotes around the value. Looking for next (space) ' ' or '>'
-                               ereg('^[^ '.$this->quotemeta($specchars).']*',$sword,$reg);
-                               $value[] = trim($reg[0]);
-                               $sword = trim(ereg_replace('^'.$this->quotemeta($reg[0]),'',$sword));
+                                       // There are no double-quotes around the value. Looking for next (space) or special char.
+                               preg_match('/^[^ '.$this->quotemeta($specchars).']*/',$sword,$reg);
+                               $word = rtrim(trim($reg[0]), $delchars);                // Delete $delchars at end of string
+                               $value[] = $word;
+                               $sword = trim(preg_replace('/^'.$this->quotemeta($reg[0]).'/','',$sword));
                        }
                }
+
                return $value;
        }
 
        /**
-        * Local version of quotemeta. This is the same as the PHP function but the vertical line, |, is also escaped with a slash.
+        * Local version of quotemeta. This is the same as the PHP function
+        * but the vertical line, |, and minus, -, is also escaped with a slash.
         *
         * @param       string          String to pass through quotemeta()
         * @return      string          Return value
         */
        function quotemeta($str)        {
-               return str_replace('|','\|',quotemeta($str));
+               $str = str_replace('|','\|',quotemeta($str));
+               #$str = str_replace('-','\-',$str);             // Breaks "-" which should NOT have a slash before it inside of [ ] in a regex.
+               return $str;
        }
 
        /**
@@ -272,7 +282,7 @@ class tslib_search {
         * @see tslib_cObj::SEARCHRESULT()
         */
        function build_search_query($endClause) {
-                       
+
                if (is_array($this->tables))    {
                        $tables = $this->tables;
                        $primary_table = '';
@@ -293,7 +303,7 @@ class tslib_search {
                                        'ORDERBY' => '',
                                        'LIMIT' => '',
                                );
-                       
+
                                        // Find tables / field names to select:
                                $fieldArray = array();
                                $tableArray = array();
@@ -308,16 +318,16 @@ class tslib_search {
                                }
                                $this->queryParts['SELECT'] = implode(',',$fieldArray);
                                $this->queryParts['FROM'] = implode(',',$tableArray);
-                               
+
                                        // Set join WHERE parts:
                                $whereArray = array();
-                               
+
                                $primary_table_and_key = $primary_table.'.'.$tables[$primary_table]['primary_key'];
-                               $primKeys=Array();
+                               $primKeys = Array();
                                foreach($tables as $key => $val)        {
                                        $fkey = $tables[$key]['fkey'];
                                        if ($fkey)      {
-                                                $primKeys[]=$key.'.'.$fkey.'='.$primary_table_and_key;
+                                                $primKeys[] = $key.'.'.$fkey.'='.$primary_table_and_key;
                                        }
                                }
                                if (count($primKeys))   {
@@ -332,13 +342,13 @@ class tslib_search {
                                        // Add search word where clause:
                                $query_part = $this->build_search_query_for_searchwords();
                                if (!$query_part)       {
-                                       $query_part='(0!=0)';
+                                       $query_part = '(0!=0)';
                                }
                                $whereArray[] = '('.$query_part.')';
-                               
+
                                        // Implode where clauses:
                                $this->queryParts['WHERE'] = implode(' AND ',$whereArray);
-                               
+
                                        // Group by settings:
                                if ($this->group_by)    {
                                        if ($this->group_by == 'PRIMARY_KEY')   {
@@ -361,7 +371,7 @@ class tslib_search {
 
                if (is_array($this->sword_array))       {
                        $main_query_part = array();
-                       
+
                        foreach($this->sword_array as $key => $val)     {
                                $s_sword = $this->sword_array[$key]['sword'];
 
@@ -374,7 +384,7 @@ class tslib_search {
                                        if (is_array($searchfields))    {
                                                foreach($searchfields as $key2 => $val2)        {
                                                        $this->listOfSearchFields.= $key3.'.'.$val2.',';
-                                                       $sub_query_part[] = $key3.'.'.$val2.' LIKE "%'.$GLOBALS['TYPO3_DB']->quoteStr($s_sword, $key3).'%"';
+                                                       $sub_query_part[] = $key3.'.'.$val2.' LIKE \'%'.$GLOBALS['TYPO3_DB']->quoteStr($s_sword, $key3).'%\'';
                                                }
                                        }
                                }
@@ -384,7 +394,7 @@ class tslib_search {
                                        $main_query_part[] = '('.implode(' OR ',$sub_query_part).')';
                                }
                        }
-                       
+
                        if (count($main_query_part))    {
                                unset($main_query_part[0]);     // Remove first part anyways.
                                return implode(' ',$main_query_part);
@@ -404,12 +414,12 @@ class tslib_search {
                $op_array = $this->operator_translate_table;
                reset ($op_array);
                if ($this->operator_translate_table_caseinsensitive)    {
-                       $operator = strtoupper($operator);
+                       $operator = strtolower($operator);      // case-conversion is charset insensitive, but it doesn't spoil anything if input string AND operator table is already converted
                }
                while (list($key,$val) = each($op_array))       {
                        $item = $op_array[$key][0];
                        if ($this->operator_translate_table_caseinsensitive)    {
-                               $item = strtoupper($item);
+                               $item = strtolower($item);      // See note above.
                        }
                        if ($operator==$item)   {
                                return $op_array[$key][1];
@@ -449,10 +459,10 @@ class tslib_search {
         * @return      string          URL-parameters with the searchwords
         */
        function get_searchwords()      {
-               $SWORD_PARAMS='';
+               $SWORD_PARAMS = '';
                if (is_array($this->sword_array))       {
                        foreach($this->sword_array as $key => $val)     {
-                               $SWORD_PARAMS.='&sword_list[]='.rawurlencode($val['sword']);
+                               $SWORD_PARAMS.= '&sword_list[]='.rawurlencode($val['sword']);
                        }
                }
                return $SWORD_PARAMS;
@@ -466,12 +476,12 @@ class tslib_search {
        function get_searchwordsArray() {
                if (is_array($this->sword_array))       {
                        foreach($this->sword_array as $key => $val)     {
-                               $swords[]=$val['sword'];
+                               $swords[] = $val['sword'];
                        }
                }
                return $swords;
        }
-}         
+}