"Fossies" - the Fresh Open Source Software Archive

Member "Help/HTML/search.php" (29 Aug 2023, 114899 Bytes) of package /windows/misc/memtest86-usb.zip:


The requested HTML page contains a <FORM> tag that is unusable on "Fossies" in "automatic" (rendered) mode so that page is shown as HTML source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    1 <?php
    2 // ----------------------------------------------------------------------------
    3 // Zoom Search Engine 7.0 (14/July/2014)
    4 // PHP search script
    5 // A fast custom website search engine using pre-indexed data files.
    6 // Copyright (C) Wrensoft 2000 - 2014
    7 //
    8 // This script is designed for PHP 4.2+ only.
    9 //
   10 // NOTE: YOU SHOULD NOT NEED TO MODIFY THIS SCRIPT. If you wish to customize
   11 // the appearance of the search page, you should change the contents of the
   12 // "search_template.html" file. See chapter 6 of the Users Guide for more
   13 // details: http://www.wrensoft.com/zoom/usersguide.html
   14 // 
   15 // IF YOU NEED TO ADD PHP TO THE SEARCH PAGE, see this FAQ:
   16 // http://www.wrensoft.com/zoom/support/faq_ssi.html
   17 //
   18 // zoom@wrensoft.com
   19 // http://www.wrensoft.com
   20 // ----------------------------------------------------------------------------
   21 
   22 if(strcmp('4.2.0', phpversion()) > 0)
   23     die("This version of the Zoom search script requires PHP 4.2.0 or higher.<br />You are currently using: PHP " . phpversion() . "<br />");
   24 
   25 $SETTINGSFILE = dirname(__FILE__)."/settings.php";
   26 $WORDMAPFILE = dirname(__FILE__)."/zoom_wordmap.zdat";
   27 $DICTIONARYFILE = dirname(__FILE__)."/zoom_dictionary.zdat";
   28 $PAGEDATAFILE = dirname(__FILE__)."/zoom_pagedata.zdat";
   29 $SPELLINGFILE = dirname(__FILE__)."/zoom_spelling.zdat";
   30 $PAGETEXTFILE = dirname(__FILE__)."/zoom_pagetext.zdat";
   31 $PAGEINFOFILE = dirname(__FILE__)."/zoom_pageinfo.zdat";
   32 $RECOMMENDEDFILE = dirname(__FILE__)."/zoom_recommended.zdat";
   33 $AUTOCOMPLETEFILE = dirname(__FILE__)."/zoom_autocomplete.zdat";
   34 $AUTOCOMPLETE_JSFILE = dirname(__FILE__)."/zoom_autocomplete.js";
   35 $AUTOCOMPLETE_CSSFILE = dirname(__FILE__)."/zoom_autocomplete.css";
   36 $DATEPICKER_JSFILE = dirname(__FILE__)."/zoom_datepicker.js";
   37 
   38 // Check for dependent files
   39 if (!file_exists($SETTINGSFILE) || !file_exists($WORDMAPFILE) || !file_exists($DICTIONARYFILE))
   40 {
   41     print("<b>Zoom files missing error:</b> Zoom is missing one or more of the required index data files.<br />Please make sure the generated index files are uploaded to the same path as this search script.<br />");
   42     return;
   43 }
   44 
   45 require($SETTINGSFILE);
   46 
   47 if ($Spelling == 1 && !file_exists($SPELLINGFILE))
   48     print("<b>Zoom files missing error:</b> Zoom is missing the 'zoom_spelling.zdat' file required for the Spelling Suggestion feature which has been enabled.<br />");
   49 
   50 // ----------------------------------------------------------------------------
   51 // Settings
   52 // ----------------------------------------------------------------------------
   53 
   54 // The options available in the dropdown menu for number of results
   55 // per page
   56 $PerPageOptions = array(10, 20, 50, 100);
   57 
   58 /*
   59 // For foreign language support, setlocale may be required on the server for
   60 // wildcards and highlighting to work. Uncomment the following lines and specify
   61 // the appropriate locale information
   62 //if (setlocale(LC_ALL, "ru_RU.cp1251") == false) // for russian
   63 //  print("Failed to change locale setting or locale setting invalid");
   64 */
   65 
   66 // Index format information
   67 $PAGEDATA_URL = 0;
   68 $PAGEDATA_TITLE = 1;
   69 $PAGEDATA_DESC = 2;
   70 $PAGEDATA_IMG = 3;
   71 
   72 $MaxPageDataLineLen = 5178;
   73 
   74 $METAFIELD_TYPE = 0;
   75 $METAFIELD_NAME = 1;
   76 $METAFIELD_SHOW = 2;
   77 $METAFIELD_FORM = 3;
   78 $METAFIELD_METHOD = 4;
   79 $METAFIELD_DROPDOWN = 5;
   80 
   81 $METAFIELD_TYPE_NUMERIC = 0;
   82 $METAFIELD_TYPE_TEXT = 1;
   83 $METAFIELD_TYPE_DROPDOWN = 2;
   84 $METAFIELD_TYPE_MULTI = 3;
   85 $METAFIELD_TYPE_MONEY = 4;
   86 
   87 $METAFIELD_METHOD_EXACT = 0;
   88 $METAFIELD_METHOD_LESSTHAN = 1;
   89 $METAFIELD_METHOD_LESSTHANORE = 2;
   90 $METAFIELD_METHOD_GREATERTHAN = 3;
   91 $METAFIELD_METHOD_GREATERTHANORE = 4;
   92 $METAFIELD_METHOD_SUBSTRING = 5;
   93 
   94 $METAFIELD_NOVALUE_MARKER = 4294967295;
   95 
   96 
   97 // ----------------------------------------------------------------------------
   98 // Parameter initialisation
   99 // ----------------------------------------------------------------------------
  100 
  101 // Send HTTP header to define meta charset
  102 if (isset($Charset) && $NoCharset == 0)
  103     header("Content-Type: text/html; charset=" . $Charset);
  104 
  105 // For versions of PHP before 4.1.0
  106 // we will emulate the superglobals by creating references
  107 // NOTE: references created are NOT superglobals
  108 if (!isset($_SERVER) && isset($HTTP_SERVER_VARS))
  109     $_SERVER = &$HTTP_SERVER_VARS;
  110 if (!isset($_GET) && isset($HTTP_GET_VARS))
  111     $_GET = &$HTTP_GET_VARS;
  112 if (!isset($_POST) && isset($HTTP_POST_VARS))
  113     $_POST = &$HTTP_POST_VARS;
  114 
  115 // fix get/post variables if magic quotes are enabled
  116 if (get_magic_quotes_gpc() == 1)
  117 {
  118     if (isset($_GET))
  119         while (list($key, $value) = each($_GET))
  120         {
  121             if (!is_array($value))
  122                 $_GET["$key"] = stripslashes($value);
  123         }
  124     if (isset($_POST))
  125         while (list($key, $value) = each($_POST))
  126             $_POST["$key"] = stripslashes($value);
  127 }
  128 
  129 // check magic_quotes for runtime stuff (reading from files, etc)
  130 if (get_magic_quotes_runtime() == 1)
  131     set_magic_quotes_runtime(0);
  132 
  133 // we use the method=GET and 'query' parameter now (for sub-result pages etc)
  134 $IsZoomQuery = 0;
  135 if (isset($_GET['zoom_query']))
  136 {
  137     $query = $_GET['zoom_query'];
  138     $IsZoomQuery = 1;
  139 }
  140 else
  141     $query = "";
  142 
  143 // number of results per page, defaults to 10 if not specified
  144 if (isset($_GET['zoom_per_page']))
  145 {
  146     $per_page = intval($_GET['zoom_per_page']);
  147     if ($per_page < 1)
  148         $per_page = 1;
  149 }
  150 else
  151     $per_page = 10;
  152 
  153 // current result page number, defaults to the first page if not specified
  154 $NewSearch = 0;
  155 if (isset($_GET['zoom_page']))
  156 {
  157     $page = intval($_GET['zoom_page']);
  158     if ($page < 1)
  159         $page = 1;
  160 }
  161 else
  162 {
  163     $page = 1;
  164     $NewSearch = 1;
  165 }
  166 
  167 // Check for autocomplete query
  168 $IsZoomAC = 0;
  169 if (isset($_GET['zoom_ac']))
  170 {
  171     $IsZoomAC = intval($_GET['zoom_ac']);
  172     $ZoomACOutput = "";
  173     if ($IsZoomAC == 1)
  174         $SearchAsSubstring = 1;
  175 }
  176 
  177 // AND operator.
  178 // 1 if we are searching for ALL terms
  179 // 0 if we are searching for ANY terms (default)
  180 if (isset($_GET['zoom_and']))
  181     $and = intval($_GET['zoom_and']);
  182 elseif (isset($DefaultToAnd) && $DefaultToAnd == 1)
  183     $and = 1;
  184 else
  185     $and = 0;
  186 
  187 // for category support
  188 if ($UseCats == 1)
  189 {
  190     if (isset($_GET['zoom_cat']))
  191     {
  192         if (is_array($_GET['zoom_cat']))
  193             $cat = $_GET['zoom_cat'];
  194         else
  195             $cat = array($_GET['zoom_cat']);
  196         $cat = array_filter($cat, "is_numeric");
  197     }
  198     else
  199         $cat = array(-1);  // default to search all categories
  200 
  201     $num_zoom_cats = count($cat);
  202     if ($num_zoom_cats == 0)
  203         $cat = array(-1);  // default to search all categories
  204 }
  205 
  206 // for sorting options
  207 // zero is default (relevance)
  208 // 1 is sort by date (if Date/Time is available)
  209 if (isset($_GET['zoom_sort']))
  210     $sort = intval($_GET['zoom_sort']);
  211 else
  212     $sort = $DefaultSort;
  213     
  214 // date range 
  215 if ($DateRangeSearch == 1)
  216 {
  217     if (isset($_GET['zoom_datefrom']))
  218         $date_from = $_GET['zoom_datefrom'];
  219     else
  220         $date_from = "";
  221     if (isset($_GET['zoom_dateto']))
  222         $date_to = $_GET['zoom_dateto'];
  223     else
  224         $date_to = "";
  225 }
  226 
  227 $LinkBackJoinChar = "?";
  228 if (isset($LinkBackURL) == false || strlen($LinkBackURL) < 1)
  229     $SelfURL = htmlspecialchars($_SERVER['PHP_SELF'], ENT_COMPAT, $Charset);
  230 else
  231 {
  232     $SelfURL = $LinkBackURL;
  233 }
  234 
  235 if (strchr($SelfURL, '?'))
  236     $LinkBackJoinChar = "&amp;";
  237 
  238 // init. link target string
  239 $zoom_target = "";
  240 if ($UseLinkTarget == 1 && isset($LinkTarget))
  241     $zoom_target = " target=\"" . $LinkTarget . "\" ";
  242 
  243 $UseMBFunctions = 0;
  244 if ($UseUTF8 == 1)
  245 {
  246     if (function_exists('mb_strtolower'))
  247         $UseMBFunctions = 1;
  248 }
  249 
  250 if ($UseStemming == 1)
  251 {
  252     $porterStemmer = new PorterStemmer();
  253 }   
  254 
  255 // ----------------------------------------------------------------------------
  256 // Template buffers
  257 // ----------------------------------------------------------------------------
  258 
  259 // defines for output elements
  260 $OUTPUT_FORM_START = 0;
  261 $OUTPUT_FORM_END = 1;
  262 $OUTPUT_FORM_SEARCHBOX = 2;
  263 $OUTPUT_FORM_SEARCHBUTTON = 3;
  264 $OUTPUT_FORM_RESULTSPERPAGE = 4;
  265 $OUTPUT_FORM_MATCH = 5;
  266 $OUTPUT_FORM_CATEGORIES = 6;
  267 $OUTPUT_FORM_CUSTOMMETA = 7;
  268 
  269 $OUTPUT_HEADING = 8;
  270 $OUTPUT_SUMMARY = 9;
  271 $OUTPUT_SUGGESTION = 10;
  272 $OUTPUT_PAGESCOUNT = 11;
  273 $OUTPUT_SORTING = 12;
  274 $OUTPUT_SEARCHTIME = 13;
  275 $OUTPUT_RECOMMENDED = 14;
  276 $OUTPUT_PAGENUMBERS = 15;
  277 $OUTPUT_CATSUMMARY = 16;
  278 $OUTPUT_FORM_DATERANGE = 17;
  279 
  280 $OUTPUT_TAG_COUNT = 18;
  281 
  282 $OutputBuffers = array_fill(0, $OUTPUT_TAG_COUNT, "");
  283 $OutputResultsBuffer = "";
  284 
  285 $TemplateShowTags = array(
  286 "<!--ZOOM_SHOW_FORMSTART-->",
  287 "<!--ZOOM_SHOW_FORMEND-->",
  288 "<!--ZOOM_SHOW_SEARCHBOX-->",
  289 "<!--ZOOM_SHOW_SEARCHBUTTON-->",
  290 "<!--ZOOM_SHOW_RESULTSPERPAGE-->",
  291 "<!--ZOOM_SHOW_MATCHOPTIONS-->",
  292 "<!--ZOOM_SHOW_CATEGORIES-->",
  293 "<!--ZOOM_SHOW_CUSTOMMETAOPTIONS-->",
  294 "<!--ZOOM_SHOW_HEADING-->",
  295 "<!--ZOOM_SHOW_SUMMARY-->",
  296 "<!--ZOOM_SHOW_SUGGESTION-->",
  297 "<!--ZOOM_SHOW_PAGESCOUNT-->",
  298 "<!--ZOOM_SHOW_SORTING-->",
  299 "<!--ZOOM_SHOW_SEARCHTIME-->",
  300 "<!--ZOOM_SHOW_RECOMMENDED-->",
  301 "<!--ZOOM_SHOW_PAGENUMBERS-->",
  302 "<!--ZOOM_SHOW_CATSUMMARY-->",
  303 "<!--ZOOM_SHOW_JAVASCRIPTS-->",
  304 "<!--ZOOM_SHOW_DATERANGE-->"
  305 );
  306 
  307 $TemplateDefaultTag = "<!--ZOOMSEARCH-->";
  308 $TemplateDefaultTagLen = strlen($TemplateDefaultTag);
  309 $TemplateSearchFormTag = "<!--ZOOM_SHOW_SEARCHFORM-->";
  310 $TemplateSearchFormTagLen = strlen($TemplateSearchFormTag);
  311 $TemplateResultsTag = "<!--ZOOM_SHOW_RESULTS-->";
  312 $TemplateResultsTagLen = strlen($TemplateResultsTag);
  313 $TemplateQueryTag = "<!--ZOOM_SHOW_QUERY-->";
  314 $TemplateQueryTagLen = strlen($TemplateQueryTag);
  315 
  316 $OutputBuffers[$OUTPUT_FORM_START] = "<form method=\"get\" action=\"".$SelfURL."\" target=\"_self\" class=\"zoom_searchform\">";
  317 $OutputBuffers[$OUTPUT_FORM_END] = "</form>";
  318 
  319 // Indexes for dict structure
  320 $DICT_WORD = 0;
  321 $DICT_PTR = 1;
  322 $DICT_VARCOUNT = 2;
  323 $DICT_VARIANTS = 3;
  324 
  325 // ----------------------------------------------------------------------------
  326 // Functions
  327 // ----------------------------------------------------------------------------
  328 function ShowDefaultForm()
  329 {
  330     global $OutputBuffers;
  331     global $OUTPUT_FORM_SEARCHBOX, $OUTPUT_FORM_SEARCHBUTTON, $OUTPUT_FORM_RESULTSPERPAGE;
  332     global $OUTPUT_FORM_MATCH, $OUTPUT_FORM_CATEGORIES, $OUTPUT_FORM_CUSTOMMETA;
  333     global $OUTPUT_FORM_START, $OUTPUT_FORM_END, $OUTPUT_FORM_DATERANGE;
  334     
  335     print($OutputBuffers[$OUTPUT_FORM_START]);
  336     print($OutputBuffers[$OUTPUT_FORM_SEARCHBOX]);
  337     print($OutputBuffers[$OUTPUT_FORM_SEARCHBUTTON]);
  338     print($OutputBuffers[$OUTPUT_FORM_RESULTSPERPAGE]);
  339     print($OutputBuffers[$OUTPUT_FORM_MATCH]);
  340     print($OutputBuffers[$OUTPUT_FORM_CATEGORIES]);
  341     print($OutputBuffers[$OUTPUT_FORM_CUSTOMMETA]);
  342     print($OutputBuffers[$OUTPUT_FORM_DATERANGE]);
  343     print($OutputBuffers[$OUTPUT_FORM_END]);
  344 }
  345 
  346 function ShowDefaultSearchPage()
  347 {
  348     global $OutputResultsBuffer;
  349     global $OutputBuffers;
  350     global $OUTPUT_HEADING, $OUTPUT_SUMMARY, $OUTPUT_SUGGESTION, $OUTPUT_PAGESCOUNT;
  351     global $OUTPUT_RECOMMENDED, $OUTPUT_SORTING, $OUTPUT_PAGENUMBERS, $OUTPUT_SEARCHTIME;
  352     global $OUTPUT_CATSUMMARY;
  353 
  354     ShowDefaultForm();
  355     // now show the default results layout
  356     print($OutputBuffers[$OUTPUT_HEADING]);
  357     print($OutputBuffers[$OUTPUT_SUMMARY]);
  358     print($OutputBuffers[$OUTPUT_CATSUMMARY]);
  359     print($OutputBuffers[$OUTPUT_SUGGESTION]);
  360     print($OutputBuffers[$OUTPUT_PAGESCOUNT]);
  361     print($OutputBuffers[$OUTPUT_RECOMMENDED]);
  362     print($OutputBuffers[$OUTPUT_SORTING]);
  363     print($OutputResultsBuffer);
  364     print($OutputBuffers[$OUTPUT_PAGENUMBERS]);
  365     print($OutputBuffers[$OUTPUT_SEARCHTIME]);
  366 }
  367 
  368 function IncludeAdditionalJS()
  369 {
  370     global $UseAutoComplete, $DateRangeSearch;
  371     global $AUTOCOMPLETE_JSFILE, $AUTOCOMPLETE_CSSFILE, $DATEPICKER_JSFILE;
  372     global $SelfURL, $LinkBackJoinChar;
  373     global $onloadFunctionStr;
  374     
  375     if ($UseAutoComplete == 1)
  376     {
  377         print("<script language=\"javascript\" type=\"text/javascript\">\n");
  378         //print("var ZoomAutoComplete_URL = \"".$SelfURL.$LinkBackJoinChar."zoom_ac=1\";\n");
  379         print("var ZoomAutoComplete_URL = \"search.php".$LinkBackJoinChar."zoom_ac=1\";\n");
  380         include($AUTOCOMPLETE_JSFILE);
  381         $onloadFunctionStr = "function() { ZoomAutoComplete_OnLoad('zoom_searchbox');}";
  382         print("if (window.addEventListener) window.addEventListener('load', " . $onloadFunctionStr . ", false);");
  383         print(" else if (window.attachEvent) window.attachEvent('onload', " . $onloadFunctionStr . ");");
  384         print(" else window['onload'] = " . $onloadFunctionStr);
  385         print("</script>\n");
  386         print("<style>\n");
  387         include($AUTOCOMPLETE_CSSFILE);
  388         print("</style>\n");
  389     }
  390             
  391     if ($DateRangeSearch == 1)
  392     {
  393         print("<script language=\"javascript\" type=\"text/javascript\">\n");
  394         include($DATEPICKER_JSFILE);
  395         print("</script>\n");
  396     }   
  397 }
  398 
  399 function ShowTemplate()
  400 {
  401     global $ZoomInfo;
  402     global $OutputBuffers;
  403     global $TemplateShowTags;
  404     global $OUTPUT_TAG_COUNT;
  405     global $TemplateSearchFormTag, $TemplateSearchFormTagLen;
  406     global $TemplateDefaultTag, $TemplateDefaultTagLen;
  407     global $TemplateResultsTag, $TemplateResultsTagLen;
  408     global $OutputResultsBuffer;
  409     global $TemplateQueryTag, $TemplateQueryTagLen, $queryForHTML;
  410     global $UseAutoComplete, $DateRangeSearch;
  411     global $AUTOCOMPLETE_JSFILE, $AUTOCOMPLETE_CSSFILE, $DATEPICKER_JSFILE;
  412     global $SelfURL, $LinkBackJoinChar;
  413 
  414     // DO NOT MODIFY THE TEMPLATE FILENAME BELOW:
  415     $TemplateFilename = "search_template.html";
  416     // Note that there is no practical need to change the TemplateFilename. This file
  417     // is not visible to the end user. The search link on your website should point to
  418     // "search.php", and not the template file.
  419     //
  420     // Note also that you cannot change the filename to a PHP or ASP file.
  421     // The template file will only be treated as a static HTML page and changing the
  422     // extension will not alter this behaviour. Please see this FAQ support page
  423     // for a solution: http://www.wrensoft.com/zoom/support/faq_ssi.html
  424 
  425     //Open and print start of result page template
  426     $TemplateFilename = dirname(__FILE__) . "/" . $TemplateFilename;
  427     $template = file ($TemplateFilename);
  428     $numtlines = count($template); //Number of lines in the template
  429     $template_line = 0;
  430     $templatePtr = $template[$template_line];
  431     $IncludedJS = false;
  432         
  433     $NeedJS = false;
  434     if ($UseAutoComplete == 1 || $DateRangeSearch == 1)
  435         $NeedJS = true;
  436 
  437     while ($template_line < $numtlines && $templatePtr != "")
  438     {
  439         if ($NeedJS == true && $IncludedJS == false && stristr($templatePtr, "</head>") !== FALSE)
  440         {
  441             IncludeAdditionalJS();
  442             $IncludedJS = true;
  443     }
  444         
  445         $tagPos = strpos($templatePtr, "<!--ZOOM");
  446         if ($tagPos === FALSE)
  447             $tagPtr = "";
  448         else
  449         {
  450             if ($tagPos == 0)
  451                 $tagPtr = $templatePtr;
  452             else
  453             {
  454                 print(substr($templatePtr,0, $tagPos));
  455                 $tagPtr = substr($templatePtr, $tagPos);
  456             }
  457         }
  458 
  459         if ($tagPtr == "")
  460         {
  461             print($templatePtr);
  462             $templatePtr = "";
  463         }
  464         else if (strncasecmp($tagPtr, $TemplateDefaultTag, $TemplateDefaultTagLen) == 0)
  465         {
  466             ShowDefaultSearchPage();
  467             $templatePtr = substr($tagPtr, $TemplateDefaultTagLen);
  468         }
  469         else if (strncasecmp($tagPtr, $TemplateSearchFormTag, $TemplateSearchFormTagLen) == 0)
  470         {
  471             ShowDefaultForm();
  472             $templatePtr = substr($tagPtr, $TemplateSearchFormTagLen);
  473         }
  474         else if (strncasecmp($tagPtr, $TemplateResultsTag, $TemplateResultsTagLen) == 0)
  475         {
  476             print($OutputResultsBuffer);
  477             $templatePtr = substr($tagPtr, $TemplateResultsTagLen);
  478         }
  479         else if (strncasecmp($tagPtr, $TemplateQueryTag, $TemplateQueryTagLen) == 0)
  480         {
  481             if (strlen($queryForHTML) > 0)
  482                 print($queryForHTML);
  483             $templatePtr = substr($tagPtr, $TemplateQueryTagLen);
  484         }       
  485         else
  486         {
  487             for ($tagnum = 0; $tagnum < $OUTPUT_TAG_COUNT; $tagnum++)
  488             {
  489                 $tagLen = strlen($TemplateShowTags[$tagnum]);
  490                 if (strncasecmp($tagPtr, $TemplateShowTags[$tagnum], $tagLen) == 0)
  491                 {
  492                     print($OutputBuffers[$tagnum]);
  493                     $templatePtr = substr($tagPtr, $tagLen);
  494                     break;
  495                 }
  496             }
  497             if ($tagnum == $OUTPUT_TAG_COUNT)
  498             {
  499                 print($tagPtr);
  500                 $templatePtr = "";
  501             }
  502         }
  503 
  504         if (strlen(trim($templatePtr)) == 0)
  505         {
  506             $template_line++;
  507             if ($template_line < $numtlines)
  508                 $templatePtr = $template[$template_line];
  509         }
  510     }
  511     
  512     // Last check if we didn't add the JS (because of a lack of </head>, we will insert it before end of file
  513     if ($NeedJS == true && $IncludedJS == false)
  514     {
  515         IncludeAdditionalJS();
  516         $IncludedJS = true;
  517   }
  518 }
  519 
  520 function PrintHighlightDescription($line)
  521 {
  522     global $Highlighting;
  523     global $HighlightColor;
  524     global $RegExpSearchWords;
  525     global $NumSearchWords;
  526     global $SearchAsSubstring;
  527 
  528     if ($Highlighting == 0)
  529     {
  530         return $line;
  531     }
  532 
  533     $res = $line;
  534 
  535     for ($i = 0; $i < $NumSearchWords; $i++)
  536     {
  537         if (strlen($RegExpSearchWords[$i]) < 1)
  538             continue;
  539 
  540         // replace with marker text, assumes [;:] and [:;] is not the search text...
  541         if ($SearchAsSubstring == 1)
  542             $res = preg_replace("/(" .$RegExpSearchWords[$i] . ")/i", "[;:]$1[:;]", $res);
  543         else
  544             $res = preg_replace("/(\W|\A|\b)(" .$RegExpSearchWords[$i] . ")(\W|\Z|\b)/i", "$1[;:]$2[:;]$3", $res);
  545     }
  546     // replace the marker text with the html text
  547     // this is to avoid finding previous <span>'ed text.
  548     $res = str_replace("[;:]", "<span class=\"highlight\">", $res);
  549     $res = str_replace("[:;]", "</span>", $res);
  550     return $res;
  551 }
  552 
  553 
  554 function GetDictionaryWord($word_id, $variant_index)
  555 {
  556     global $dict, $DICT_VARIANTS, $DICT_WORD, $DICT_VARCOUNT;
  557 
  558     if ($variant_index > 0 && $variant_index <= $dict[$word_id][$DICT_VARCOUNT])
  559         return $dict[$word_id][$DICT_VARIANTS][$variant_index-1];
  560     else
  561         return $dict[$word_id][$DICT_WORD];
  562 }
  563 
  564 function GetSpellingWord($word_id)
  565 {
  566     global $dict, $DICT_VARIANTS, $DICT_WORD, $DICT_VARCOUNT;
  567 
  568     if ($dict[$word_id][$DICT_VARCOUNT] > 0)
  569         return $dict[$word_id][$DICT_VARIANTS][0];
  570     else
  571         return $dict[$word_id][$DICT_WORD];
  572 }
  573 
  574 
  575 $HIGHLIGHT_NONE = 0;
  576 $HIGHLIGHT_SINGLE = 1;
  577 $HIGHLIGHT_START = 2;
  578 $HIGHLIGHT_END = 3;
  579 
  580 function HighlightContextArray($context_word_count)
  581 {
  582     global $highlightArray;
  583     global $contextArray;
  584     global $NumSearchWords;
  585     global $SearchWords, $UseWildCards, $RegExpSearchWords;
  586     global $phrase_terms_ids, $search_terms_ids;
  587     global $HIGHLIGHT_NONE, $HIGHLIGHT_SINGLE, $HIGHLIGHT_START, $HIGHLIGHT_END;
  588     global $SearchAsSubstring, $DictReservedLimit;
  589 
  590     for ($i = 0; $i < $context_word_count; $i++)
  591     {
  592         if ($contextArray[$i] == 0)
  593             continue;
  594 
  595         $word_id = $contextArray[$i][0];
  596         $variant_index = $contextArray[$i][1];
  597 
  598         for ($sw = 0; $sw < $NumSearchWords; $sw++)
  599         {
  600             if (strpos($SearchWords[$sw], " ") !== false)
  601             {
  602                 // this is an exact phrase and has its phrase terms stored in SearchPhrases[sw]
  603                 $termNum = $i;
  604                 $pterm = 0;
  605                 while ($phrase_terms_ids[$sw][$pterm] != 0 && $termNum < $context_word_count)
  606                 {
  607                     // only compare this word in the context if it is NOT a punctuation word
  608                     // or if it is the first word we are looking at in this phrase
  609                     if ($termNum == $i || $contextArray[$termNum][0] > $DictReservedLimit)
  610                     {
  611                         if ($phrase_terms_ids[$sw][$pterm] != $contextArray[$termNum][0])
  612                             break;  // we break out of looking at each term of the phrase if we don't match
  613                         $pterm++;
  614                     }
  615                     $termNum++;
  616                 }
  617 
  618                 if ($pterm > 0 && $phrase_terms_ids[$sw][$pterm] == 0)
  619                 {
  620                     $highlightArray[$i] = $HIGHLIGHT_START;
  621                     $highlightArray[$termNum-1] = $HIGHLIGHT_END;
  622                 }
  623             }
  624             else
  625             {
  626                 $res = 0;
  627                 if ($UseWildCards[$sw] == 1)
  628                 {
  629                     $res = preg_match("/\A(".$RegExpSearchWords[$sw].")\Z/i", GetDictionaryWord($word_id, 0));
  630                 }
  631                 else
  632                 {
  633                     if ($search_terms_ids[$sw] == $word_id)
  634                         $res = 1;
  635                 }
  636                 if ($res > 0)
  637                 {
  638                     if ($highlightArray[$i] == $HIGHLIGHT_NONE)
  639                         $highlightArray[$i] = $HIGHLIGHT_SINGLE;
  640                 }
  641             }
  642         }
  643     }
  644 }
  645 
  646 function PrintNumResults($num)
  647 {
  648     global $STR_NO_RESULTS, $STR_RESULT, $STR_RESULTS;
  649     global $IsMaxLimitExceeded, $STR_MORETHAN;
  650     if ($num == 0)
  651         return $STR_NO_RESULTS;
  652     else if ($num == 1)
  653         return $num . " " . $STR_RESULT;
  654     else
  655     {
  656         if ($IsMaxLimitExceeded)
  657             return $STR_MORETHAN . " " . $num . " " . $STR_RESULTS;
  658         return $num . " " . $STR_RESULTS;
  659     }
  660 }
  661 
  662 function RecLinkAddParamToURL($url, $paramStr)
  663 {
  664     // add GET parameters to URL depending on
  665     // whether there are any existing parameters
  666     if (strpos($url, "?") !== false)
  667         return $url . "&amp;" . $paramStr;
  668     else
  669     {               
  670         $hashPos = strpos($url, "#");
  671         if ($hashPos !== false)
  672             return substr($url, 0, $hashPos) . "?" . $paramStr . substr($url, $hashPos);
  673         else
  674             return $url . "?" . $paramStr;
  675     }
  676 }
  677 
  678 function AddParamToURL($url, $paramStr)
  679 {
  680     // add GET parameters to URL depending on
  681     // whether there are any existing parameters
  682     // Note: we don't need to worry about hash anchors here like RecLinkAddParamToURL
  683     // because they are stripped for non-recommended link.
  684     if (strpos($url, "?") !== false)
  685         return $url . "&amp;" . $paramStr;
  686     else
  687         return $url . "?" . $paramStr;
  688 }
  689 
  690 
  691 // ----------------------------------------------------------------------------
  692 // Compares the two values, used for sorting output results
  693 // Results that match all search terms are put first, highest score
  694 // ----------------------------------------------------------------------------
  695 function SortCompare ($a, $b)
  696 {
  697     if ($a[2] < $b[2])
  698         return 1;
  699     else
  700     if ($a[2] > $b[2])
  701         return -1;
  702     else
  703     {
  704         if ($a[1] < $b[1])
  705             return 1;
  706         else
  707         if ($a[1] > $b[1])
  708             return -1;
  709         else
  710             return 0;
  711     }
  712 }
  713 
  714 function SortByDate ($a, $b)
  715 {
  716     global $pageinfo;
  717     if ($pageinfo[$a[0]]["datetime"] < $pageinfo[$b[0]]["datetime"])
  718         return 1;
  719     else
  720     if ($pageinfo[$a[0]]["datetime"] > $pageinfo[$b[0]]["datetime"])
  721         return -1;
  722     else
  723     {
  724         // if equal dates/time, return based on sw matched and score
  725         return SortCompare($a, $b);
  726     }
  727 }
  728 
  729 function SortByDateAsc ($a, $b)
  730 {
  731     global $pageinfo;
  732     if ($pageinfo[$a[0]]["datetime"] > $pageinfo[$b[0]]["datetime"])
  733         return 1;
  734     else
  735     if ($pageinfo[$a[0]]["datetime"] < $pageinfo[$b[0]]["datetime"])
  736         return -1;
  737     else
  738     {
  739         // if equal dates/time, return based on sw matched and score
  740         return SortCompare($a, $b);
  741     }
  742 }
  743 
  744 function sw_compare ($a, $b)
  745 {
  746     if ($a[0] == '-')
  747         return 1;
  748 
  749     if ($b[0] == '-')
  750         return -1;
  751 
  752     return 0;
  753 }
  754 
  755 
  756 // ----------------------------------------------------------------------------
  757 // Translates a typical shell wildcard pattern ("zoo*" => "zoom" etc.)
  758 // to a regular expression pattern. Supports only '*' and '?' characters.
  759 // ----------------------------------------------------------------------------
  760 function pattern2regexp($pattern)
  761 {
  762     $i = 0;
  763     $len = strlen($pattern);
  764 
  765     if (strpos($pattern, "$") !== false)
  766         str_replace($pattern, "$", "\$");
  767     if (strpos($pattern, "#") !== false)
  768         str_replace($pattern, "#", "\#");
  769 
  770     $res = "";
  771 
  772     while ($i < $len) {
  773         $c = $pattern[$i];
  774         if ($c == '*')
  775             $res = $res . "[\d\S]*";
  776         else
  777         if ($c == '?')
  778             $res = $res . ".";
  779         else
  780         if ($c == '.')
  781             $res = $res . "\.";
  782         else
  783             $res = $res . preg_quote($c, '/');
  784         $i++;
  785     }
  786     return $res;
  787 }
  788 
  789 function wordcasecmp($word1, $word2)
  790 {
  791     global $UseUTF8;
  792     global $UseMBFunctions;
  793     global $ToLowerSearchWords;
  794     
  795     if ($ToLowerSearchWords == 0)
  796         return strcmp($word1, $word2);
  797 
  798     if ($UseUTF8 == 1 && $UseMBFunctions == 1)
  799     {
  800         // string length compare for speed reasons, only use mb_strtolower when absolutely necessary
  801         // assumes that the lowercase variant of multibyte characters are same length as their uppercase variant
  802         if (strlen($word1) == strlen($word2))
  803         {
  804             if (preg_match('/^[\x80-\xff]/', $word1) || preg_match('/^[\x80-\xff]/', $word2))
  805                 return strcmp(mb_strtolower($word1, "UTF-8"), mb_strtolower($word2, "UTF-8"));
  806             else
  807                 return strcasecmp($word1, $word2);
  808         }
  809         else
  810             return 1;
  811     }
  812     else
  813         return strcasecmp($word1, $word2);
  814 }
  815 
  816 function mystristr($word1, $word2)
  817 {
  818     global $UseUTF8;
  819     global $UseMBFunctions;
  820 
  821     if ($UseUTF8 == 1 && $UseMBFunctions == 1)
  822     {
  823         if (preg_match('/^[\x80-\xff]/', $word1) || preg_match('/^[\x80-\xff]/', $word2))
  824             return strstr(mb_strtolower($word1, "UTF-8"), mb_strtolower($word2, "UTF-8"));
  825     }
  826     
  827     return stristr($word1, $word2);
  828 }
  829 
  830 
  831 // This function is unable to return any values larger than a signed int
  832 // is capable of holding, due to PHP's bitwise operators only working
  833 // with signed ints.
  834 function GetBytes($binfile, $numbytes)
  835 {
  836     global $METAFIELD_NOVALUE_MARKER;
  837 
  838     $ffcount = 0;
  839     $ret = 0;
  840     $bytes_buffer = fread($binfile, $numbytes);
  841     for ($k = 0; $k < $numbytes; $k++)
  842     {
  843         if ($bytes_buffer[$k] == chr(0xFF))
  844             $ffcount++;
  845         $ret = $ret | ord($bytes_buffer[$k])<<(8*$k);
  846     }
  847     if ($ffcount == $numbytes)
  848         $ret = (float) $METAFIELD_NOVALUE_MARKER;
  849     return $ret;
  850 }
  851 
  852 function GetDictID($word)
  853 {
  854     global $dict;
  855     global $dict_count;
  856     for ($i = 0; $i < $dict_count; $i++) {
  857         if (wordcasecmp($dict[$i][0], $word) == 0)
  858             return $i;
  859     }
  860     return -1;  // not found
  861 }
  862 
  863 function GetNextDictWord($fp_pagetext)
  864 {
  865     global $DictIDLen;
  866     $dict_id = 0;
  867     $variant_index = 0;
  868 
  869     $bytes_buffer = fread($fp_pagetext, $DictIDLen);
  870     if ($bytes_buffer != "")
  871     {
  872         for ($i = 0; $i < $DictIDLen-1; $i++)
  873         {
  874             $dict_id = $dict_id | ord($bytes_buffer[$i])<<(8*$i);
  875         }
  876         $variant_index = ord($bytes_buffer[$DictIDLen-1]);
  877     }
  878     else
  879     {
  880         $dict_id = 0;
  881         $variant_index = 0;
  882     }
  883 
  884     return array($dict_id,$variant_index);
  885 }
  886 
  887 function CheckBitInByteArray($bitnum, $byteArray)
  888 {
  889     global $NumCatBytes;
  890     
  891     $bytenum = 0;
  892     $newBitnum = 0;
  893     
  894     $bytenum = ceil(($bitnum+1) / 8.0);
  895 
  896     if ($bytenum > 1)
  897     {
  898         $newBitnum = $bitnum - (($bytenum-1)*8);
  899         $bytenum = $bytenum - 1;
  900     }
  901     else
  902     {
  903         $newBitnum = $bitnum;
  904         $bytenum = 0;
  905     }
  906 
  907     if ($bytenum >= $NumCatBytes)
  908     {           
  909         exit("Error: Category number is invalid. Incorrect settings file used?");
  910     }
  911 
  912     return ($byteArray[$bytenum] & (1 << $newBitnum));
  913 }
  914 
  915 function SkipSearchWord($sw)
  916 {
  917     global $SearchWords;
  918     global $SkippedWords;
  919     global $SkippedOutputStr;
  920     global $RegExpSearchWords;
  921     global $Highlighting;
  922     global $UseWildCards;
  923     if ($SearchWords[$sw] != "")
  924     {
  925         if ($SkippedWords > 0)
  926             $SkippedOutputStr .= ", ";
  927         $SkippedOutputStr .= "\"<b>" . $SearchWords[$sw] . "</b>\"";
  928         $SearchWords[$sw] = "";
  929         if ($Highlighting == 1 || $UseWildCards[$sw] == 1)
  930             $RegExpSearchWords[$sw] = "";
  931     }
  932     $SkippedWords++;
  933 }
  934 
  935 function GetSPCode($word)
  936 {
  937     $Vowels = "AEIOU";
  938     $FrontV = "EIY";
  939     $VarSound = "CSPTG";
  940     $Dbl = ".";
  941 
  942     $metalen = 6;
  943 
  944     $tmpword = strtoupper($word);
  945 
  946     $wordlen = strlen($tmpword);
  947     if ($wordlen < 1)
  948         return "";
  949 
  950     // if ae, gn, kn, pn, wr then drop the first letter
  951     $strPtr = substr($tmpword, 0, 2);
  952     if ($strPtr == "AE" || $strPtr == "GN" || $strPtr == "KN" || $strPtr == "PN" || $strPtr == "WR")
  953         $tmpword = substr($tmpword, 1);
  954 
  955     // change x to s
  956     if ($tmpword{0} == "X")
  957         $tmpword = "S" . substr($tmpword, 1);
  958 
  959     // get rid of the 'h' in "wh"
  960     if (substr($tmpword, 0, 2) == "WH")
  961         $tmpword = "W" . substr($tmpword, 2);
  962 
  963     // update the word length
  964     $wordlen = strlen($tmpword);
  965     $lastChar = $wordlen-1;
  966 
  967     // remove an 's' from the end of the string
  968     if ($tmpword{$lastChar} == "S")
  969     {
  970         $tmpword = substr($tmpword, 0, $wordlen-1);
  971         $wordlen = strlen($tmpword);
  972         $lastChar = $wordlen-1;
  973     }
  974 
  975     $metaph = "";
  976     $Continue = false;
  977 
  978     for ($i = 0; strlen($metaph) < $metalen && $i < $wordlen; $i++)
  979     {
  980         $char = $tmpword{$i};
  981         $vowelBefore = false;
  982         $continue = false;
  983         if ($i > 0)
  984         {
  985             $prevChar = $tmpword{$i-1};
  986             if (strpos($Vowels, $prevChar) !== FALSE)
  987                 $vowelBefore = true;
  988         }
  989         else
  990         {
  991             $prevChar = " ";
  992             if (strpos($Vowels, $char) !== FALSE)
  993             {
  994                 $metaph  .= $tmpword{0};
  995                 continue;
  996             }
  997         }
  998 
  999         $vowelAfter = false;
 1000         $frontvAfter = false;
 1001         $nextChar = " ";
 1002         if ($i < $lastChar)
 1003         {
 1004             $nextChar = $tmpword{$i+1};
 1005             if (strpos($Vowels, $nextChar) !== FALSE)
 1006                 $vowelAfter = true;
 1007             if (strpos($FrontV, $nextChar) !== FALSE)
 1008                 $frontvAfter = true;
 1009         }
 1010 
 1011         // skip double letters except ones in list
 1012         if ($char == $nextChar && $nextChar != $Dbl)
 1013             continue;
 1014 
 1015         $nextChar2 = " ";
 1016         if ($i < ($lastChar-1))
 1017             $nextChar2 = $tmpword{$i+2};
 1018 
 1019         $nextChar3 = " ";
 1020         if ($i < ($lastChar-2))
 1021             $nextChar3 = $tmpword{$i+3};
 1022 
 1023         switch ($char)
 1024         {
 1025         case "B":
 1026             $silent = false;
 1027             if ($i == $lastChar && $prevChar == "M")
 1028                 $silent = true;
 1029             if ($silent == false)
 1030                 $metaph .= $char;
 1031             break;
 1032         case "C":
 1033             if (!($i > 1 && $prevChar == "S" && $frontvAfter))
 1034             {
 1035                 if ($i > 0 && $nextChar == "I" && $nextChar2 == "A")
 1036                     $metaph .= "X";
 1037                 elseif ($frontvAfter)
 1038                     $metaph .= "S";
 1039                 elseif ($i > 1 && $prevChar == "S" && $nextChar == "H")
 1040                     $metaph .= "K";
 1041                 elseif ($nextChar == "H")
 1042                 {
 1043                     if ($i == 0 && strpos($Vowels, $nextChar2) === FALSE)
 1044                         $metaph .= "K";
 1045                     else
 1046                         $metaph .= "X";
 1047                 }
 1048                 elseif ($prevChar == "C")
 1049                     $metaph .= "C";
 1050                 else
 1051                     $metaph .= "K";
 1052             }
 1053             break;
 1054         case "D":
 1055             if ($nextChar == "G" && strpos($FrontV, $nextChar2) !== FALSE)
 1056                 $metaph .= "J";
 1057             else
 1058                 $metaph .= "T";
 1059             break;
 1060         case "G":
 1061             $silent = false;
 1062             if ( ($i < ($lastChar-1) && $nextChar == "H") &&
 1063                  (strpos($Vowels, $nextChar2) == FALSE))
 1064                  $silent = true;
 1065 
 1066             if ( ($i == ($lastChar-3)) && $nextChar == "N" && $nextChar == "E" && $nextChar == "D")
 1067                 $silent = true;
 1068             elseif ( ($i == ($lastChar-1)) && $nextChar == "N")
 1069                 $silent = true;
 1070 
 1071             if ($prevChar == "D" && $frontvAfter)
 1072                 $silent = true;
 1073 
 1074             if ($prevChar == "G")
 1075                 $hard = true;
 1076             else
 1077                 $hard = false;
 1078 
 1079             if (!$silent)
 1080             {
 1081                 if ($frontvAfter && (!$hard))
 1082                     $metaph .= "J";
 1083                 else
 1084                     $metaph .= "K";
 1085             }
 1086             break;
 1087         case "H":
 1088             $silent = false;
 1089             if (strpos($VarSound, $prevChar) !== FALSE)
 1090                 $silent = true;
 1091             if ($vowelBefore && !$vowelAfter)
 1092                 $silent = true;
 1093             if (!$silent)
 1094                 $metaph .= $char;
 1095             break;
 1096         case "F":
 1097         case "J":
 1098         case "L":
 1099         case "M":
 1100         case "N":
 1101         case "R":
 1102             $metaph .= $char;
 1103             break;
 1104         case "K":
 1105             if ($prevChar != "C")
 1106                 $metaph .= $char;
 1107             break;
 1108         case "P":
 1109             if ($nextChar == "H")
 1110                 $metaph .= "F";
 1111             else
 1112                 $metaph .= "P";
 1113             break;
 1114         case "Q":
 1115             $metaph .= "K";
 1116             break;
 1117         case "S":
 1118             if ($i > 1 && $nextChar == "I" && ($nextChar2 == "O" || $nextChar2 == "A"))
 1119                 $metaph .= "X";
 1120             elseif ($nextChar == "H")
 1121                 $metaph .= "X";
 1122             else
 1123                 $metaph .= "S";
 1124             break;
 1125         case "T":
 1126             if ($i > 1 && $nextChar == "I" && ($nextChar2 == "O" || $nextChar2 == "A"))
 1127                 $metaph .= "X";
 1128             elseif ($nextChar == "H")
 1129             {
 1130                 if ($i > 0 || (strpos($Vowels, $nextChar2) !== FALSE))
 1131                     $metaph .= "0";
 1132                 else
 1133                     $metaph .= "T";
 1134             }
 1135             elseif (!($i < ($lastChar-2) && $nextChar == "C" && $nextChar2 == "H"))
 1136                 $metaph .= "T";
 1137             break;
 1138         case "V":
 1139             $metaph .= "F";
 1140             break;
 1141         case "W":
 1142         case "Y":
 1143             if ($i < $lastChar && $vowelAfter)
 1144                 $metaph .= $char;
 1145             break;
 1146         case "X":
 1147             $metaph .= "KS";
 1148             break;
 1149         case "Z":
 1150             $metaph .= "S";
 1151             break;
 1152         }
 1153     }
 1154     if (strlen($metaph) == 0)
 1155         return "";
 1156     return $metaph;
 1157 }
 1158 
 1159 function GetPageData($index)
 1160 {
 1161     global $fp_pagedata, $pageinfo, $MaxPageDataLineLen;
 1162     fseek($fp_pagedata, intval($pageinfo[$index]["dataoffset"]));
 1163     $pgdata = fgets($fp_pagedata, $MaxPageDataLineLen);
 1164     return explode("|", $pgdata);
 1165 }
 1166 
 1167 function GetUrlFromPageData($index)
 1168 {
 1169     global $fp_pagedata, $pageinfo, $MaxPageDataLineLen;
 1170     fseek($fp_pagedata, intval($pageinfo[$index]["dataoffset"]));
 1171     $pgdata = fgets($fp_pagedata, $MaxPageDataLineLen);
 1172     $pipePos = strpos($pgdata, '|');
 1173     if ($pipePos !== FALSE)
 1174     {
 1175         return substr($pgdata, 0, $pipePos);
 1176     }
 1177     return "";
 1178 }
 1179 
 1180 
 1181 function QueryEntities($query)
 1182 {
 1183     $query = str_replace("&", "&#38;", $query);
 1184     $query = str_replace("<", "&#60;", $query);
 1185     $query = str_replace(">", "&#62;", $query);
 1186     return $query;
 1187 }
 1188 
 1189 function uniord($u)
 1190 {
 1191     $k = mb_convert_encoding($u, 'UCS-2LE', 'UTF-8');
 1192     $k1 = ord(substr($k, 0, 1));
 1193     $k2 = ord(substr($k, 1, 1));
 1194     return $k2 * 256 + $k1;
 1195 }
 1196 
 1197 function FixQueryForAsianWords($query)
 1198 {
 1199     // check if the multibyte functions we need to use are available
 1200     if (!function_exists('mb_convert_encoding') ||
 1201         !function_exists('mb_strlen') ||
 1202         !function_exists('mb_substr'))
 1203         return $query;
 1204 
 1205     $currCharType = 0;
 1206     $lastCharType = 0;  // 0 is normal, 1 is hiragana, 2 is katakana, 3 is "han"
 1207 
 1208     // check for hiragan/katakana splitting required
 1209     $newquery = "";
 1210     $query_len = mb_strlen($query, "UTF-8");
 1211     for ($i = 0; $i < $query_len; $i++)
 1212     {
 1213         $ch = mb_substr($query, $i, 1, "UTF-8");
 1214         $chVal = uniord($ch);
 1215 
 1216         if ($chVal >= 12352 && $chVal <= 12447)
 1217             $currCharType = 1;
 1218         else if ($chVal >= 12448 && $chVal <= 12543)
 1219             $currCharType = 2;
 1220         else if ($chVal >= 13312 && $chVal <= 44031)
 1221             $currCharType = 3;
 1222         else
 1223             $currCharType = 0;
 1224 
 1225         if ($lastCharType != $currCharType && $ch != " ")
 1226             $newquery .= " ";
 1227         $lastCharType = $currCharType;
 1228         $newquery .= $ch;
 1229     }
 1230     return $newquery;
 1231 }
 1232 
 1233 $LastRecLinkIdx = 0;
 1234 
 1235 // matches the recommended link word against the user search query
 1236 function RecLinkWordMatch($rec_word, $rec_idx)
 1237 {
 1238     global $NumSearchWords, $queryForSearch, $queryForURL, $query, $num_rec_words;
 1239     global $SearchWords, $UseWildCards, $SearchAsSubstring, $ToLowerSearchWords;
 1240     global $OutputBuffers, $OUTPUT_RECOMMENDED;
 1241     global $PAGEDATA_URL, $PAGEDATA_TITLE, $PAGEDATA_DESC, $PAGEDATA_IMG, $UseZoomImage;
 1242     global $zoom_target, $GotoHighlight, $PdfHighlight;
 1243     global $num_recs_found;
 1244     global $STR_RECOMMENDED;
 1245     global $LastRecLinkIdx, $IsNoKeywordQuery;
 1246 
 1247     $bRecLinkFound = false;
 1248     
 1249     if ($LastRecLinkIdx == $rec_idx)
 1250         return false;   // we've already matched one for this page
 1251 
 1252     for ($sw = 0; $sw <= $NumSearchWords; $sw++)
 1253     {
 1254         // if finished with last search word, check the full search query
 1255         $result = 1;
 1256         if ($sw == $NumSearchWords)
 1257             $result = wordcasecmp($queryForSearch, $rec_word);
 1258         else if (strlen($SearchWords[$sw]) > 0)
 1259         {
 1260             if ($UseWildCards[$sw] == 1)
 1261             {
 1262                 $pattern = "/";
 1263 
 1264                 // match entire word
 1265                 if ($SearchAsSubstring == 0)
 1266                     $pattern = $pattern . "\A";
 1267 
 1268                 $pattern = $pattern . $RegExpSearchWords[$sw];
 1269 
 1270                 if ($SearchAsSubstring == 0)
 1271                     $pattern = $pattern . "\Z";
 1272 
 1273                 if ($ToLowerSearchWords != 0)
 1274                     $pattern = $pattern . "/i";
 1275                 else
 1276                     $pattern = $pattern . "/";
 1277 
 1278                 $result = !(preg_match($pattern, $rec_word));
 1279             }
 1280             else if ($SearchAsSubstring == 0)
 1281             {
 1282                 $result = wordcasecmp($SearchWords[$sw], $rec_word);
 1283             }
 1284             else
 1285             {
 1286                 if (mystristr($rec_word, $SearchWords[$sw]) == FALSE)
 1287                     $result = 1;    // not matched
 1288                 else
 1289                     $result = 0;    // matched
 1290             }
 1291 
 1292             if ($result != 0)
 1293             {
 1294                 // if not matched, we check if the word is a wildcard
 1295                 if (strpos($rec_word, "*") !== false || strpos($rec_word, "?") !== false)
 1296                 {
 1297                     $RecWordRegExp = "/\A" . pattern2regexp($rec_word) . "\Z/i";
 1298                     $result = !(preg_match($RecWordRegExp, $SearchWords[$sw]));
 1299                 }
 1300             }
 1301         }
 1302 
 1303         if ($result == 0)
 1304         {
 1305             $bRecLinkFound = true;
 1306             if ($num_recs_found == 0)
 1307             {
 1308                 $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<div class=\"recommended\">\n";
 1309                 $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<div class=\"recommended_heading\">$STR_RECOMMENDED</div>\n";
 1310             }
 1311             $pgdata = GetPageData($rec_idx);
 1312             $LastRecLinkIdx = $rec_idx;
 1313             
 1314             $url = $pgdata[$PAGEDATA_URL];
 1315             $title = $pgdata[$PAGEDATA_TITLE];
 1316             $description = $pgdata[$PAGEDATA_DESC];
 1317             if ($UseZoomImage)
 1318                 $image = $pgdata[$PAGEDATA_IMG];
 1319 
 1320             $urlLink = $url;
 1321             //$urlLink = rtrim($urls[$rec_idx]);
 1322 
 1323             if ($GotoHighlight == 1)
 1324             {
 1325                 if ($SearchAsSubstring == 1)
 1326                     $urlLink = RecLinkAddParamToURL($urlLink, "zoom_highlightsub=".$queryForURL);
 1327                 else
 1328                     $urlLink = RecLinkAddParamToURL($urlLink, "zoom_highlight=".$queryForURL);
 1329             }
 1330             if ($PdfHighlight == 1 && $IsNoKeywordQuery == false)
 1331             {
 1332                 if (stristr($urlLink, ".pdf") != FALSE)
 1333                     $urlLink = $urlLink."#search=%22".str_replace("\"", "", $query)."%22";
 1334             }
 1335             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<div class=\"recommend_block\">\n";
 1336             if ($UseZoomImage)
 1337             {
 1338                 if (strlen($image) > 0)
 1339                 {
 1340                     $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<div class=\"recommend_image\">";
 1341                     $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<a href=\"".$urlLink."\"" . $zoom_target . "><img src=\"$image\" alt=\"\" class=\"recommend_image\"></a>";
 1342                     $OutputBuffers[$OUTPUT_RECOMMENDED] .= "</div>";
 1343                 }
 1344             }
 1345             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<div class=\"recommend_title\">";
 1346             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<a href=\"".$urlLink."\"" . $zoom_target . ">";
 1347             if (strlen($title) > 1)
 1348                 $OutputBuffers[$OUTPUT_RECOMMENDED] .= PrintHighlightDescription($title);
 1349             else
 1350                 $OutputBuffers[$OUTPUT_RECOMMENDED] .= PrintHighlightDescription($pgdata[$PAGEDATA_URL]);
 1351             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "</a></div>\n";
 1352             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<div class=\"recommend_description\">";
 1353             $OutputBuffers[$OUTPUT_RECOMMENDED] .= PrintHighlightDescription($description);
 1354             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "</div>\n";
 1355             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "<div class=\"recommend_infoline\">$url</div>\n";
 1356             $OutputBuffers[$OUTPUT_RECOMMENDED] .= "</div>";
 1357             $num_recs_found++;
 1358             break;
 1359         }
 1360     }
 1361     return $bRecLinkFound;
 1362 }
 1363 
 1364 // ----------------------------------------------------------------------------
 1365 // Starts here
 1366 // ----------------------------------------------------------------------------
 1367 
 1368 $mtime = explode(" ", microtime());
 1369 $starttime = doubleval($mtime[1]) + doubleval($mtime[0]);
 1370 
 1371 // Read in the metafields query
 1372 if ($UseMetaFields == 1)
 1373 {
 1374     for ($fieldnum = 0; $fieldnum < $NumMetaFields; $fieldnum++)
 1375     {
 1376         if (isset($_GET[$metafields[$fieldnum][$METAFIELD_NAME]]))
 1377         {
 1378             $meta_query[$fieldnum] = $_GET[$metafields[$fieldnum][$METAFIELD_NAME]];
 1379 
 1380             if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MULTI)
 1381             {
 1382                 if (!is_array($meta_query[$fieldnum]))
 1383                     $meta_query[$fieldnum] = array($meta_query[$fieldnum]);
 1384                 $meta_query[$fieldnum] = array_filter($meta_query[$fieldnum], "is_numeric");
 1385             }
 1386             /*
 1387             if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_DROPDOWN)
 1388             {
 1389                 $ddi = 0;
 1390                 foreach ($metafields[$fieldnum][$METAFIELD_DROPDOWN] as $ddv)
 1391                 {
 1392                     // replace the query value string with the numeric index for faster matching
 1393                     if (strcasecmp($meta_query[$fieldnum], $ddv) == 0)
 1394                         $meta_query[$fieldnum] = $ddi;
 1395                     $ddi++;
 1396                 }
 1397             }
 1398             */
 1399         }
 1400         else
 1401             $meta_query[$fieldnum] = "";
 1402     }
 1403 }
 1404 
 1405 $OutputResultsBuffer .= "<!--Zoom Search Engine ".$Version."-->\n";
 1406 
 1407 // Replace the key text <!--ZOOMSEARCH--> with the following
 1408 if ($FormFormat > 0)
 1409 {
 1410     // Insert the form
 1411     $OutputBuffers[$OUTPUT_FORM_SEARCHBOX] = "<label for=\"zoom_searchbox\" id=\"zoom_searchbox_label\">$STR_FORM_SEARCHFOR</label>\n";
 1412     $OutputBuffers[$OUTPUT_FORM_SEARCHBOX] .= "<input type=\"text\" name=\"zoom_query\" size=\"15\" value=\"".htmlspecialchars($query, ENT_COMPAT, $Charset)."\" id=\"zoom_searchbox\" class=\"zoom_searchbox\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" />\n";
 1413     $OutputBuffers[$OUTPUT_FORM_SEARCHBUTTON] = "<input type=\"submit\" value=\"" . $STR_FORM_SUBMIT_BUTTON . "\" class=\"zoom_button\" />\n";
 1414     if ($FormFormat == 2)
 1415     {
 1416         $OutputBuffers[$OUTPUT_FORM_RESULTSPERPAGE] = "<span class=\"zoom_results_per_page\"><label for=\"zoom_per_page\">" . $STR_FORM_RESULTS_PER_PAGE . "</label>\n";
 1417         $OutputBuffers[$OUTPUT_FORM_RESULTSPERPAGE] .= "<select name=\"zoom_per_page\" id=\"zoom_per_page\">\n";
 1418         reset($PerPageOptions);
 1419         foreach ($PerPageOptions as $ppo)
 1420         {
 1421             $OutputBuffers[$OUTPUT_FORM_RESULTSPERPAGE] .= "<option";
 1422             if ($ppo == $per_page)
 1423                 $OutputBuffers[$OUTPUT_FORM_RESULTSPERPAGE] .= " selected=\"selected\"";
 1424             $OutputBuffers[$OUTPUT_FORM_RESULTSPERPAGE] .= ">". $ppo ."</option>\n";
 1425         }
 1426         $OutputBuffers[$OUTPUT_FORM_RESULTSPERPAGE] .= "</select><br /><br /></span>\n";
 1427         if ($UseCats)
 1428         {
 1429             $OutputBuffers[$OUTPUT_FORM_CATEGORIES] = "<span class=\"zoom_categories\"><label for=\"zoom_cat\">" . $STR_FORM_CATEGORY . "</label>";
 1430             if ($SearchMultiCats)
 1431             {
 1432                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "<ul>\n";
 1433                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "<li><input type=\"checkbox\" name=\"zoom_cat[]\" value=\"-1\" id=\"zoom_cat-1\"";
 1434                 if ($cat[0] == -1)
 1435                     $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= " checked=\"checked\"";
 1436                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= " /><label for=\"zoom_cat-1\">$STR_FORM_CATEGORY_ALL</label></li>\n";
 1437                 for ($i = 0; $i < $NumCats; $i++)
 1438                 {
 1439                     $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "<li><input type=\"checkbox\" name=\"zoom_cat[]\" value=\"$i\" id=\"zoom_cat".$i."\"";
 1440                     if ($cat[0] != -1)
 1441                     {
 1442                         for ($catit = 0; $catit < $num_zoom_cats; $catit++)
 1443                         {
 1444                             if ($i == $cat[$catit])
 1445                             {
 1446                                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= " checked=\"checked\"";
 1447                                 break;
 1448                             }
 1449                         }
 1450                     }
 1451                     $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= " /><label for=\"zoom_cat".$i."\">$catnames[$i]</label></li>\n";
 1452                 }
 1453                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "</ul><br /><br /></span>\n";
 1454             }
 1455             else
 1456             {
 1457                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "<select name=\"zoom_cat[]\" id=\"zoom_cat\">";
 1458                 // 'all cats option
 1459                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "<option value=\"-1\">" . $STR_FORM_CATEGORY_ALL . "</option>";
 1460                 for($i = 0; $i < $NumCats; $i++) {
 1461                     $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "<option value=\"". $i . "\"";
 1462                     if ($i == $cat[0])
 1463                         $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= " selected=\"selected\"";
 1464                     $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= ">". $catnames[$i] . "</option>";
 1465                 }
 1466                 $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "</select>&nbsp;&nbsp;\n";
 1467             }
 1468             $OutputBuffers[$OUTPUT_FORM_CATEGORIES] .= "</span>\n";
 1469         }
 1470         if ($UseMetaFields)
 1471         {
 1472             $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] = "<span class=\"zoom_metaform\">\n";
 1473             for ($fieldnum = 0; $fieldnum < $NumMetaFields; $fieldnum++)
 1474             {
 1475                 $labelID = "zoom_metaform_".$metafields[$fieldnum][$METAFIELD_NAME];
 1476                 if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_NUMERIC)
 1477                 {
 1478                     // TODO: sensible label for names without clashing with common html stuff
 1479                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<label for=\"".$labelID."\">" . $metafields[$fieldnum][$METAFIELD_FORM] . ": </label>";
 1480                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<input type=\"text\" id=\"".$labelID."\" name=\"".$metafields[$fieldnum][$METAFIELD_NAME]."\" size=\"20\" value=\"".$meta_query[$fieldnum]."\" class=\"zoom_metaform_numeric\" />\n";
 1481                 }
 1482                 else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_DROPDOWN)
 1483                 {
 1484                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<label for=\"".$labelID."\">" . $metafields[$fieldnum][$METAFIELD_FORM] . ": </label>";
 1485                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<select id=\"".$labelID."\" name=\"".$metafields[$fieldnum][$METAFIELD_NAME]."\" class=\"zoom_metaform_dropdown\">\n";
 1486                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<option value=\"-1\">" . $STR_FORM_CATEGORY_ALL . "</option>";
 1487                     $ddi = 0;
 1488                     foreach ($metafields[$fieldnum][$METAFIELD_DROPDOWN] as $ddv)
 1489                     {
 1490                         $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<option value=\"" . $ddi . "\"";
 1491                         if ($ddi == floatval($meta_query[$fieldnum]))
 1492                             $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= " selected=\"selected\"";
 1493                         $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= ">". $ddv ."</option>\n";
 1494                         $ddi++;
 1495                     }
 1496                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "</select>\n";
 1497                 }
 1498                 else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MULTI)
 1499                 {
 1500                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<label for=\"".$labelID."\">" . $metafields[$fieldnum][$METAFIELD_FORM] . ": </label>";
 1501                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<select multiple id=\"".$labelID."\" name=\"".$metafields[$fieldnum][$METAFIELD_NAME]."[]\" class=\"zoom_metaform_multi\">\n";
 1502                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<option value=\"-1\">" . $STR_FORM_CATEGORY_ALL . "</option>";
 1503                     $ddi = 0;
 1504                     $num_multi_query = 0;
 1505                     if (is_array($meta_query[$fieldnum]))
 1506                         $num_multi_query = count($meta_query[$fieldnum]);
 1507                     foreach ($metafields[$fieldnum][$METAFIELD_DROPDOWN] as $ddv)
 1508                     {
 1509                         $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<option value=\"" . $ddi . "\"";
 1510                         for ($mqi = 0; $mqi < $num_multi_query; $mqi++)
 1511                         {
 1512                             if ($ddi == intval($meta_query[$fieldnum][$mqi]))
 1513                                 $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= " selected=\"selected\"";
 1514                         }
 1515                         $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= ">". $ddv ."</option>\n";
 1516                         $ddi++;
 1517                     }
 1518                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "</select>\n";
 1519                 }
 1520                 else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MONEY)
 1521                 {
 1522                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<label for=\"".$labelID."\">" . $metafields[$fieldnum][$METAFIELD_FORM] . ": </label>";
 1523                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= $MetaMoneyCurrency . "<input type=\"text\" id=\"".$labelID."\" name=\"".$metafields[$fieldnum][$METAFIELD_NAME]."\" size=\"7\" value=\"".$meta_query[$fieldnum]."\" class=\"zoom_metaform_money\" />\n";
 1524                 }
 1525                 else
 1526                 {
 1527                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<label for=\"".$labelID."\">" . $metafields[$fieldnum][$METAFIELD_FORM] . ": </label>";
 1528                     $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "<input type=\"text\" id=\"".$labelID."\" name=\"".$metafields[$fieldnum][$METAFIELD_NAME]."\" size=\"20\" value=\"".$meta_query[$fieldnum]."\" class=\"zoom_metaform_text\" />\n";
 1529                 }
 1530             }
 1531             $OutputBuffers[$OUTPUT_FORM_CUSTOMMETA] .= "</span>\n";
 1532         }
 1533         $OutputBuffers[$OUTPUT_FORM_MATCH] = "<span class=\"zoom_match\"><label for=\"zoom_match\">" . $STR_FORM_MATCH . " </label>\n";
 1534         if ($and == 0) {
 1535             $OutputBuffers[$OUTPUT_FORM_MATCH] .= "<label for=\"zoom_match_any\" class=\"zoom_and_label\" id=\"zoom_and_label_any\"><input type=\"radio\" id=\"zoom_match_any\" name=\"zoom_and\" value=\"0\" checked=\"checked\" />" .  $STR_FORM_ANY_SEARCH_WORDS . "</label>\n";
 1536             $OutputBuffers[$OUTPUT_FORM_MATCH] .= "<label for=\"zoom_match_all\" class=\"zoom_and_label\" id=\"zoom_and_label_all\"><input type=\"radio\" id=\"zoom_match_all\" name=\"zoom_and\" value=\"1\" />" . $STR_FORM_ALL_SEARCH_WORDS . "</label>\n";
 1537         } else {
 1538             $OutputBuffers[$OUTPUT_FORM_MATCH] .= "<label for=\"zoom_match_any\" class=\"zoom_and_label\" id=\"zoom_and_label_any\"><input type=\"radio\" id=\"zoom_match_any\" name=\"zoom_and\" value=\"0\" />" . $STR_FORM_ANY_SEARCH_WORDS . "</label>\n";
 1539             $OutputBuffers[$OUTPUT_FORM_MATCH] .= "<label for=\"zoom_match_all\" class=\"zoom_and_label\" id=\"zoom_and_label_all\"><input type=\"radio\" id=\"zoom_match_all\" name=\"zoom_and\" value=\"1\" checked=\"checked\" />" . $STR_FORM_ALL_SEARCH_WORDS . "</label>\n";
 1540         }
 1541         $OutputBuffers[$OUTPUT_FORM_START] .= "<input type=\"hidden\" name=\"zoom_sort\" value=\"" . $sort . "\" />\n";     
 1542         $OutputBuffers[$OUTPUT_FORM_MATCH] .= "<br /><br /></span>\n";
 1543         
 1544         if ($DateRangeSearch == 1)
 1545         {
 1546             $OutputBuffers[$OUTPUT_FORM_DATERANGE] = "<span class=\"zoom_daterange\">\n";
 1547             if ($DateRangeFormat == 1)
 1548                 $dateformatStr = "mdy";
 1549             else
 1550                 $dateformatStr = "dmy";
 1551             $OutputBuffers[$OUTPUT_FORM_DATERANGE] .= "<label for=\"zoom_datefrom\">". $STR_FORM_DATE_FROM . " </label><input id=\"zoom_datefrom\" name=\"zoom_datefrom\" value=\"".$date_from."\"><input type=\"button\" value=\"".$STR_FORM_DATE_BUTTON."\" onclick=\"displayDatePicker('zoom_datefrom', false, '".$dateformatStr."');\" />";
 1552             $OutputBuffers[$OUTPUT_FORM_DATERANGE] .= "<label for=\"zoom_dateto\">".$STR_FORM_DATE_TO . " </label><input id=\"zoom_dateto\" name=\"zoom_dateto\" value=\"".$date_to."\"><input type=\"button\" value=\"".$STR_FORM_DATE_BUTTON."\" onclick=\"displayDatePicker('zoom_dateto', false, '".$dateformatStr."');\" />";
 1553             $OutputBuffers[$OUTPUT_FORM_DATERANGE] .= "</span>";
 1554         }       
 1555     }
 1556     else
 1557     {
 1558         $OutputBuffers[$OUTPUT_FORM_START] .= "<input type=\"hidden\" name=\"zoom_per_page\" value=\"" . $per_page . "\" />\n";
 1559         $OutputBuffers[$OUTPUT_FORM_START] .= "<input type=\"hidden\" name=\"zoom_and\" value=\"" . $and . "\" />\n";
 1560         $OutputBuffers[$OUTPUT_FORM_START] .= "<input type=\"hidden\" name=\"zoom_sort\" value=\"" . $sort . "\" />\n";
 1561     }   
 1562 }
 1563 
 1564 // Give up early if no search words provided
 1565 $IsNoKeywordQuery = false;
 1566 if (empty($query))
 1567 {
 1568     $NoSearch = false;
 1569     if ($UseMetaFields == 1)
 1570     {
 1571         if ($IsZoomQuery == 1)
 1572             $IsNoKeywordQuery = true;
 1573         else
 1574             $NoSearch = true;
 1575     }
 1576     else
 1577     {
 1578         // only display 'no query' line if no form is shown
 1579         if ($IsZoomQuery == 1)
 1580         {
 1581             $OutputBuffers[$OUTPUT_SUMMARY] .= "<div class=\"summary\">" . $STR_NO_QUERY . "</div>";
 1582         }
 1583 
 1584         $NoSearch = true;
 1585     }
 1586     if ($NoSearch)
 1587     {
 1588         //Let others know about Zoom.
 1589         if ($ZoomInfo == 1)
 1590             $OutputBuffers[$OUTPUT_PAGENUMBERS] .= "<center><p><small>" . $STR_POWEREDBY . " <a href=\"http://www.wrensoft.com/zoom/\" target=\"_blank\"><b>Zoom Search Engine</b></a></small></p></center>";
 1591 
 1592         ShowTemplate();
 1593         return;
 1594     }
 1595 }
 1596 
 1597 // Prepare query for search ---------------------------------------------------
 1598 
 1599 if ($MapAccents == 1) {
 1600     $query = str_replace($AccentChars, $NormalChars, $query);
 1601 }
 1602 
 1603 // Special query processing required when SearchAsSubstring is enabled
 1604 if ($SearchAsSubstring == 1 && $UseUTF8 == 1)
 1605     $query = FixQueryForAsianWords($query);
 1606 
 1607 
 1608 // prepare search query, strip quotes, trim whitespace
 1609 if ($AllowExactPhrase == 0)
 1610 {
 1611     $query = str_replace("\"", " ", $query);
 1612 }
 1613 if (strspn(".", $WordJoinChars) == 0)
 1614     $query = str_replace(".", " ", $query);
 1615 
 1616 if (strspn("-", $WordJoinChars) == 0)
 1617     $query = preg_replace("/(\S)-/", "$1 ", $query);
 1618 
 1619 if (strspn("#", $WordJoinChars) == 0)
 1620     $query = preg_replace("/#(\S)/", " $1", $query);
 1621 
 1622 if (strspn("+", $WordJoinChars) == 0)
 1623 {
 1624     $query = preg_replace("/[\+]+([^\+\s])/", " $1", $query);
 1625     $query = preg_replace("/([^\+\s])\+\s/", "$1 ", $query);
 1626     $query = preg_replace("/\s\+\s/", " ", $query);
 1627 }
 1628 
 1629 if (strspn("_", $WordJoinChars) == 0)
 1630     $query = str_replace("_", " ", $query);
 1631 
 1632 if (strspn("'", $WordJoinChars) == 0)
 1633     $query = str_replace("'", " ", $query);
 1634 
 1635 if (strspn("$", $WordJoinChars) == 0)
 1636     $query = str_replace("$", " ", $query);
 1637 
 1638 if (strspn(",", $WordJoinChars) == 0)
 1639     $query = str_replace(",", " ", $query);
 1640 
 1641 if (strspn(":", $WordJoinChars) == 0)
 1642 {
 1643     // We temporarily replace the search syntax for "site:" and "url:"
 1644     // to avoid stripping it out when colon is disabled for word join
 1645     $query = str_replace("site:", "[#@!]", $query);
 1646     $query = str_replace("url:", "[#@]", $query);           
 1647     $query = str_replace(":", " ", $query);
 1648     
 1649     // We then restore it
 1650     $query = str_replace("[#@!]", "site:", $query);
 1651     $query = str_replace("[#@]", "url:", $query);
 1652 }
 1653 
 1654 if (strspn("&", $WordJoinChars) == 0)
 1655     $query = str_replace("&", " ", $query);
 1656 
 1657 if (strspn("/", $WordJoinChars) == 0)
 1658     $query = str_replace("/", " ", $query);
 1659 
 1660 if (strspn("\\", $WordJoinChars) == 0)
 1661     $query = str_replace("\\", " ", $query);
 1662 
 1663 if (strspn("@", $WordJoinChars) == 0)
 1664     $query = str_replace("@", " ", $query);
 1665 
 1666 // strip consecutive spaces, parenthesis, etc.
 1667 // also strip any of the wordjoinchars if followed immediately by a space
 1668 $query = preg_replace("/[\s\(\)\^\[\]\|\{\}\%\!]+|[\-._',:&\/\\\](\s|$)/", " ", $query);
 1669 $query = trim($query);
 1670 
 1671 $queryForHTML = htmlspecialchars($query, ENT_COMPAT, $Charset);
 1672 if ($ToLowerSearchWords == 1)
 1673 {
 1674     if ($UseUTF8 == 1 && $UseMBFunctions == 1)
 1675         $queryForSearch = mb_strtolower($query, "UTF-8");
 1676     else
 1677         $queryForSearch = strtolower($query);
 1678 }
 1679 else
 1680     $queryForSearch = $query;
 1681 
 1682 //Split search phrase into words
 1683 preg_match_all("/\"(.*?)\"|\-\"(.*?)\"|[^\\s\"]+/", $queryForSearch, $SearchWords);
 1684 $SearchWords = preg_replace("/\"[\s]+|[\s]+\"|\"/", "", $SearchWords[0]);
 1685 
 1686 //Sort search words if there are negative signs
 1687 if (strpos($queryForSearch, "-") !== false)
 1688     usort($SearchWords, "sw_compare");
 1689 
 1690 $NumSearchWords = count ($SearchWords);
 1691 
 1692 // Load index data files (*.zdat) ---------------------------------------------
 1693 
 1694 if ($IsZoomAC == 1)
 1695 {
 1696     $fp_ac = fopen($AUTOCOMPLETEFILE, "rt");
 1697     $ac_count = 0;  
 1698     while (!feof($fp_ac))
 1699     {
 1700         $acline = trim(fgets($fp_ac, $MaxKeyWordLineLen));
 1701         if (strlen($acline) > 0)
 1702         {           
 1703             for ($sw = 0; $sw < $NumSearchWords; $sw++)
 1704             {
 1705                 if (strncasecmp($acline, $SearchWords[$sw], strlen($SearchWords[$sw])) == 0)
 1706                 {
 1707                     $ZoomACOutput .= "<div class=\"zoom_ac_item\" onclick=\"ZoomAutoComplete_UseSuggestion('$acline');\"><a class=\"zoom_ac_item\" href=\"#\">" . $acline . "</a></div>\n";
 1708                     $ac_count++;
 1709                 }
 1710             }
 1711         }
 1712     }
 1713     fclose($fp_ac);
 1714     print($ZoomACOutput);
 1715     exit(0);    
 1716 }
 1717 
 1718 // Open pagetext file
 1719 if ($DisplayContext == 1 || $AllowExactPhrase == 1)
 1720 {   
 1721     $fp_pagetext = fopen($PAGETEXTFILE, "rb");  
 1722     if ($fp_pagetext === FALSE)
 1723     {
 1724         $OutputResultsBuffer .= "<b>Zoom config error:</b> Failed to open zoom_pagetext.zdat file.<br />";
 1725         return;
 1726     }
 1727     $teststr = fgets($fp_pagetext, 8);
 1728     if ($teststr[0] == "T" && $teststr[2] == "h" && $teststr[4] == "i" && $teststr[6] == "s")
 1729     {
 1730         $OutputResultsBuffer .= "<b>Zoom config error:</b> The zoom_pagetext.zdat file is not properly created for the search settings specified.<br />Please check that you have re-indexed your site with the search settings selected in the configuration window.<br />";
 1731         fclose($fp_pagetext);
 1732         return;
 1733     }
 1734 }
 1735 
 1736 // Open recommended link file
 1737 if ($Recommended == 1)
 1738 {
 1739     $fp_rec = fopen($RECOMMENDEDFILE, "rt");
 1740     $i = 0;
 1741     while (!feof($fp_rec))
 1742     {
 1743         $recline = fgets($fp_rec, $MaxKeyWordLineLen);
 1744         if (strlen($recline) > 0)
 1745         {
 1746             $sep = strrpos($recline, " ");
 1747             if ($sep !== false)
 1748             {
 1749                 $rec[$i][0] = substr($recline, 0, $sep);
 1750                 $rec[$i][1] = substr($recline, $sep);
 1751                 $i++;
 1752             }
 1753         }
 1754     }
 1755     fclose($fp_rec);
 1756     $rec_count = $i;
 1757 }
 1758 
 1759 //Open pageinfo file
 1760 $fp_pageinfo = fopen($PAGEINFOFILE, "rb");
 1761 $pageinfo_count = $NumPages;
 1762 $rec_headersize = 2+5+4+4+1+1;
 1763 for ($i = 0; !feof($fp_pageinfo) && $i < $pageinfo_count; $i++)
 1764 {
 1765     $bytes_buffer = fread($fp_pageinfo, $rec_headersize);
 1766     $pageinfo[$i] = unpack("vrecsize/Vdataoffset/CextraByte/Vfilesize/Vdatetime/cboost/Cfiletype", $bytes_buffer);
 1767     
 1768     if ($UseCats == 1 && $NumCatBytes > 0)
 1769     {
 1770         $catpages[$i] = array();
 1771         for ($byte = 0; $byte < $NumCatBytes; $byte++)
 1772             $catpages[$i][$byte] = GetBytes($fp_pageinfo, 1);
 1773     }
 1774 
 1775     if ($UseMetaFields == 1)
 1776     {
 1777         for ($fieldnum = 0; $fieldnum < $NumMetaFields; $fieldnum++)
 1778         {
 1779             if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_TEXT)
 1780             {
 1781                 $valueSize = GetBytes($fp_pageinfo, 1);
 1782                 if ($valueSize > 0 && $valueSize != $METAFIELD_NOVALUE_MARKER)
 1783                     $metavalues[$i][$fieldnum] = fread($fp_pageinfo, $valueSize);
 1784                 else
 1785                     $metavalues[$i][$fieldnum] = "";
 1786             }
 1787             else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_DROPDOWN)
 1788             {
 1789                 // read in one byte
 1790                 $metavalues[$i][$fieldnum] = GetBytes($fp_pageinfo, 1);
 1791             }
 1792             else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MULTI)
 1793             {
 1794                 // read in one byte count then variable bytes
 1795                 $valueSize = GetBytes($fp_pageinfo, 1);
 1796                 if ($valueSize > 0 && $valueSize != $METAFIELD_NOVALUE_MARKER)
 1797                 {
 1798                     $tmpMultiValues = array($valueSize);
 1799                     for ($mvi = 0; $mvi < $valueSize; $mvi++)
 1800                         array_push($tmpMultiValues, GetBytes($fp_pageinfo, 1));
 1801                     $metavalues[$i][$fieldnum] = $tmpMultiValues;
 1802                 }
 1803                 else
 1804                     $metavalues[$i][$fieldnum] = $valueSize;// this will be METAFIELD_NOVALUE_MARKER
 1805             }
 1806             else
 1807             {
 1808                 // numeric meta field type
 1809                 $metavalues[$i][$fieldnum] = (double)GetBytes($fp_pageinfo, 4);
 1810             }
 1811         }
 1812     }
 1813 }
 1814 
 1815 if ($Recommended == 1)
 1816     $i += $rec_count;   // take into account the recommended links before verifying
 1817 if ($i < $NumPages)
 1818 {
 1819     $OutputResultsBuffer .= ("<b>Zoom config error</b>: The zoom_pageinfo.zdat file is invalid or not up-to-date. Please make sure you have uploaded all files from the same indexing session.<br />");
 1820     $UseDateTime = 0;
 1821     $UseZoomImage = 0;
 1822     $DisplayFilesize = 0;
 1823 }
 1824 fclose($fp_pageinfo);
 1825 
 1826 // Open pagedata file
 1827 $fp_pagedata = fopen($PAGEDATAFILE, "rb");
 1828 
 1829 // Open wordmap file
 1830 $fp_wordmap = fopen($WORDMAPFILE, "rb");
 1831 
 1832 // Open dictionary file
 1833 $fp_dict = fopen($DICTIONARYFILE, "rb");
 1834 $i = 0;
 1835 while (!feof($fp_dict))
 1836 {
 1837     $dictline = fgets($fp_dict, $MaxKeyWordLineLen);
 1838     if (strlen($dictline) > 0)
 1839     {
 1840         $dict[$i] = explode(" ", $dictline, 3);
 1841         if (isset($dict[$i][$DICT_VARCOUNT]))
 1842         {
 1843             if ($dict[$i][$DICT_VARCOUNT] > 0)
 1844             {
 1845                 $variantsArray = array();
 1846                 // variants available
 1847                 for ($vi = 0; $vi < $dict[$i][$DICT_VARCOUNT]; $vi++)
 1848                 {
 1849                     $variantsArray[$vi] = rtrim(fgets($fp_dict, $MaxKeyWordLineLen));
 1850                 }
 1851                 $dict[$i][$DICT_VARIANTS] = $variantsArray;
 1852             }
 1853         }
 1854         $i++;
 1855     }
 1856 }
 1857 fclose($fp_dict);
 1858 $dict_count = $i;
 1859 
 1860 $query_zoom_cats = "";
 1861 
 1862 //Print heading
 1863 $OutputBuffers[$OUTPUT_HEADING] .= "<div class=\"searchheading\">" . $STR_RESULTS_FOR . " " . $queryForHTML;
 1864 if ($UseCats)
 1865 {
 1866     if ($cat[0] == -1)
 1867     {
 1868         $OutputBuffers[$OUTPUT_HEADING] .= " " . $STR_RESULTS_IN_ALL_CATEGORIES;
 1869         $query_zoom_cats = "&amp;zoom_cat%5B%5D=-1";
 1870     }
 1871     else
 1872     {
 1873         $OutputBuffers[$OUTPUT_HEADING] .= " " . $STR_RESULTS_IN_CATEGORY . " ";
 1874         for ($catit = 0; $catit < $num_zoom_cats; $catit++)
 1875         {
 1876             if ($catit > 0)
 1877                 $OutputBuffers[$OUTPUT_HEADING] .= ", ";
 1878             $OutputBuffers[$OUTPUT_HEADING] .= "\"". rtrim($catnames[$cat[$catit]]) . "\"";
 1879             $query_zoom_cats .= "&amp;zoom_cat%5B%5D=".$cat[$catit];
 1880         }
 1881     }
 1882 }
 1883 $OutputBuffers[$OUTPUT_HEADING] .= "<br /><br /></div>\n";
 1884 
 1885 $OutputResultsBuffer .= "<div class=\"results\">\n";
 1886 
 1887 // Begin main search loop -----------------------------------------------------
 1888 
 1889 //$pagesCount = count($urls);
 1890 $pagesCount = $NumPages;
 1891 $outputline = 0;
 1892 $IsMaxLimitExceeded = 0;
 1893 $wordsmatched = 0;
 1894 
 1895 // Initialise $res_table to be a 2D array of count($pages) long, filled with zeros.
 1896 //$res_table = array_fill(0, $pagesCount, array_fill(0, 6, 0));
 1897 $res_table = array();
 1898 for ($i = 0; $i < $pagesCount; $i++)
 1899 {
 1900     $res_table[$i] = array();
 1901     $res_table[$i][0] = 0;  // score
 1902     $res_table[$i][1] = 0;  // num of sw matched
 1903     $res_table[$i][2] = 0;  // pagetext ptr #1
 1904     $res_table[$i][3] = 0;  // pagetext ptr #2
 1905     $res_table[$i][4] = 0;  // pagetext ptr #3
 1906     $res_table[$i][5] = 0;  // 'and' user search terms matched
 1907     $res_table[$i][6] = 0;  // combined prox field
 1908 }
 1909 
 1910 if (isset($UseDomainDiversity) && $UseDomainDiversity == 1)
 1911 {
 1912     $MaxDomainDiversity = 3;
 1913     $div_res_table = array($MaxDomainDiversity);
 1914     $div_res_urls = array($MaxDomainDiversity);
 1915     $div_res_count = 0; 
 1916 }
 1917 else
 1918     $UseDomainDiversity = 0;
 1919 
 1920 $exclude_count = 0;
 1921 
 1922 // check if word is in skipword file
 1923 $SkippedWords = 0;
 1924 $context_maxgoback = 1;
 1925 $SkippedExactPhrase = 0;
 1926 $maxscore = 0;
 1927 
 1928 // queryForURL is the query prepared to be passed in a URL.
 1929 $queryForURL = urlencode($query);
 1930 
 1931 // Find recommended links if any (before stemming)
 1932 $num_recs_found = 0;
 1933 if ($Recommended == 1)
 1934 {
 1935     for ($rl = 0; $rl < $rec_count && $num_recs_found < $RecommendedMax; $rl++)
 1936     {
 1937         $rec_word = $rec[$rl][0];
 1938         $rec_idx = intval($rec[$rl][1]);
 1939         if (strchr($rec_word, ','))
 1940         {
 1941             $rec_multiwords = explode(",", $rec_word);
 1942             $rec_multiwords_count = count($rec_multiwords);
 1943             for ($rlm = 0; $rlm < $rec_multiwords_count; $rlm++)
 1944             {
 1945                 if (RecLinkWordMatch($rec_multiwords[$rlm], $rec_idx) == true)
 1946                     break;
 1947             }
 1948         }
 1949         else
 1950             RecLinkWordMatch($rec_word, $rec_idx);
 1951     }
 1952     if ($num_recs_found > 0)
 1953         $OutputBuffers[$OUTPUT_RECOMMENDED] .= "</div>";
 1954 }
 1955 
 1956 $searchUrlBuffer = "";
 1957 
 1958 // Prepopulate some data for each searchword
 1959 $sw_results = array();
 1960 $search_terms_ids = array();
 1961 $phrase_terms_ids = array();
 1962 for ($sw = 0; $sw < $NumSearchWords; $sw++)
 1963 {
 1964     $sw_results[$sw] = 0;
 1965     $UseWildCards[$sw] = 0;
 1966 
 1967     // for main search terms
 1968     $search_terms_ids[$sw] = array();
 1969     // for exact phrases
 1970     $phrase_terms_ids[$sw] = array();
 1971 
 1972     if (strpos($SearchWords[$sw], "*") !== false || strpos($SearchWords[$sw], "?") !== false)
 1973     {
 1974         $RegExpSearchWords[$sw] = pattern2regexp($SearchWords[$sw]);
 1975         $UseWildCards[$sw] = 1;
 1976     }
 1977 
 1978     if ($Highlighting == 1 && $UseWildCards[$sw] == 0)
 1979     {
 1980         $RegExpSearchWords[$sw] = $SearchWords[$sw];
 1981         if (strpos($RegExpSearchWords[$sw], "\\") !== false)
 1982             $RegExpSearchWords[$sw] = str_replace("\\", "\\\\", $RegExpSearchWords[$sw]);
 1983         if (strpos($RegExpSearchWords[$sw], "/") !== false)
 1984             $RegExpSearchWords[$sw] = str_replace("/", "\/", $RegExpSearchWords[$sw]);
 1985         if (strpos($RegExpSearchWords[$sw], "+") !== false)
 1986             $RegExpSearchWords[$sw] = str_replace("+", "\+", $RegExpSearchWords[$sw]);
 1987     }
 1988 }
 1989 
 1990 for ($sw = 0; $sw < $NumSearchWords; $sw++)
 1991 {
 1992     if ($SearchWords[$sw] == "")
 1993         continue;
 1994 
 1995     // check min length
 1996     if (strlen($SearchWords[$sw]) < $MinWordLen)
 1997     {
 1998         SkipSearchWord($sw);
 1999         continue;
 2000     }
 2001 
 2002     $ExactPhrase = 0;
 2003     $ExcludeTerm = 0;   
 2004 
 2005     // Check exclusion searches
 2006     if ($SearchWords[$sw][0] == "-")
 2007     {
 2008         $SearchWords[$sw] = substr($SearchWords[$sw], 1);
 2009         $ExcludeTerm = 1;
 2010         $exclude_count++;
 2011     }
 2012     
 2013     $colonPos = 0;
 2014     // check if this is a search option (e.g. "site:mysite.com")
 2015     if (($colonPos = strpos($SearchWords[$sw], ':')) !== FALSE)
 2016     {
 2017         if (strncmp($SearchWords[$sw], "site:", 5) == 0 || strncmp($SearchWords[$sw], "url:", 4) == 0)
 2018         {           
 2019             $searchUrlBuffer = substr($SearchWords[$sw], $colonPos+1);
 2020             $exclude_count++;
 2021             // if this site: term is the only search term in the query, then we enable 
 2022             // empty query behaviour (so we return all results)
 2023             if ($NumSearchWords == 1)
 2024             {
 2025                 $IsNoKeywordQuery = true;
 2026                 // we need to break out of the loop here and not continue searching through
 2027                 // the dictionary (and waste time) when there's no word to look up!
 2028                 // we'll continue to the top of the loop (where the while condition will break
 2029                 // since IsNoKeywordQuery is flagged)
 2030                 continue;   
 2031             }
 2032         }
 2033     }
 2034         
 2035     // Stem the words if necessary (only AFTER stripping exclusion char)
 2036     if ($UseStemming == 1)
 2037     {
 2038         if ($AllowExactPhrase == 0 || strpos($SearchWords[$sw], " ") === false)
 2039             $SearchWords[$sw] = $porterStemmer->Stem($SearchWords[$sw]);
 2040     }       
 2041 
 2042     if ($AllowExactPhrase == 1 && strpos($SearchWords[$sw], " ") !== false)
 2043     {
 2044         // Initialise exact phrase matching for this search term
 2045         $ExactPhrase = 1;
 2046         $phrase_terms = explode(" ", $SearchWords[$sw]);
 2047         //$phrase_terms = preg_split("/\W+/", $SearchWords[$sw], -1, 0 /*PREG_SPLIT_DELIM_CAPTURE*/);
 2048         $num_phrase_terms = count($phrase_terms);
 2049         if ($num_phrase_terms > $context_maxgoback)
 2050             $context_maxgoback = $num_phrase_terms;
 2051 
 2052         $phrase_terms_data = array();
 2053 
 2054         if ($UseStemming == 1)
 2055         {
 2056             for ($j = 0; $j < $num_phrase_terms; $j++)
 2057                 $phrase_terms[$j] = $porterStemmer->Stem($phrase_terms[$j]);
 2058         }
 2059 
 2060         $tmpid = 0;
 2061         $WordNotFound = 0;
 2062         $j = 0;
 2063         for ($j = 0; $j < $num_phrase_terms; $j++)
 2064         {
 2065             $tmpid = GetDictID($phrase_terms[$j]);
 2066             if ($tmpid == -1)   // word is not in dictionary
 2067             {
 2068                 $WordNotFound = 1;
 2069                 break;
 2070             }
 2071             $phrase_terms_ids[$sw][$j] = $tmpid;
 2072 
 2073             $wordmap_row = $dict[$tmpid][$DICT_PTR];
 2074             if ($wordmap_row != -1)
 2075             {
 2076                 fseek($fp_wordmap, $wordmap_row);
 2077                 $countbytes = fread($fp_wordmap, 2);
 2078                 $phrase_data_count[$j] = ord($countbytes[0]) | ord($countbytes[1])<<8;
 2079                 for ($xbi = 0; $xbi < $phrase_data_count[$j]; $xbi++) {
 2080                     $xbindata = fread($fp_wordmap, 8);
 2081                     if (strlen($xbindata) == 0)
 2082                         $OutputResultsBuffer .= "error in wordmap file: expected data not found";
 2083                     $phrase_terms_data[$j][$xbi] = unpack("Cscore/Cprox/vpagenum/Vptr", $xbindata);
 2084                 }
 2085             }
 2086             else
 2087             {
 2088                 $phrase_data_count[$j] = 0;
 2089                 $phrase_terms_data[$j] = 0;
 2090             }
 2091         }
 2092         $phrase_terms_ids[$sw][$j] = 0; // null terminate the list
 2093 
 2094         if ($WordNotFound == 1)
 2095             continue;
 2096     }
 2097     else if ($UseWildCards[$sw])
 2098     {
 2099         $pattern = "/";
 2100 
 2101         // match entire word
 2102         if ($SearchAsSubstring == 0)
 2103             $pattern = $pattern . "\A";
 2104 
 2105         $pattern = $pattern . $RegExpSearchWords[$sw];
 2106 
 2107         if ($SearchAsSubstring == 0)
 2108             $pattern = $pattern . "\Z";
 2109 
 2110         if ($ToLowerSearchWords != 0)
 2111             $pattern = $pattern . "/i";
 2112         else
 2113             $pattern = $pattern . "/";
 2114     }
 2115 
 2116     for ($i = 0; $i < $dict_count; $i++)
 2117     {
 2118         $dictline = $dict[$i];
 2119         $word = $dict[$i][$DICT_WORD];
 2120 
 2121         // if we're not using wildcards, direct match
 2122         if ($ExactPhrase == 1)
 2123         {
 2124             // todo: move to next phrase term if first phrase term is skipped?
 2125             // compare first term in exact phrase
 2126             //$result = wordcasecmp($phrase_terms[0], $word);
 2127             if ($i == $phrase_terms_ids[$sw][0])
 2128                 $result = 0;
 2129             else
 2130                 $result = 1;
 2131         }
 2132         else if ($UseWildCards[$sw] == 1)
 2133         {
 2134             // if we have wildcards...
 2135             $result = 1; // set to not matched before loop
 2136             if (isset($dict[$i][$DICT_VARCOUNT]))
 2137             {
 2138                 for ($variant_index = 1; $result != 0 && $variant_index <= $dict[$i][$DICT_VARCOUNT]; $variant_index++)
 2139                 {               
 2140                     $variant_word = GetDictionaryWord($i, $variant_index);
 2141                     $result = !(preg_match($pattern, $variant_word));
 2142                 }
 2143             }
 2144         }
 2145         else
 2146         {
 2147             if ($SearchAsSubstring == 0)
 2148                 $result = wordcasecmp($SearchWords[$sw], $word);
 2149             else
 2150             {
 2151                 if (mystristr($word, $SearchWords[$sw]) == FALSE)
 2152                     $result = 1;    // not matched
 2153                 else
 2154                     $result = 0;    // matched
 2155             }
 2156         }
 2157         
 2158         // result = 0 if matched, result != 0 if not matched.
 2159 
 2160         // word found but indicated to be not indexed or skipped
 2161         if ($result == 0 && (is_numeric($dictline[$DICT_PTR]) == false || $dictline[$DICT_PTR] == -1))
 2162         {
 2163             if ($UseWildCards[$sw] == 0 && $SearchAsSubstring == 0)
 2164             {
 2165                 if ($ExactPhrase == 1)
 2166                     $SkippedExactPhrase = 1;
 2167 
 2168                 SkipSearchWord($sw);
 2169                 break;
 2170             }
 2171             else
 2172                 continue;
 2173         }
 2174         
 2175         if ($result == 0)
 2176         {
 2177             // keyword found in the dictionary
 2178             $wordsmatched++;
 2179             if ($ExcludeTerm == false && $wordsmatched > $MaxMatches)
 2180             {
 2181                 $IsMaxLimitExceeded = true;
 2182                 break;
 2183             }
 2184 
 2185             /// remember the dictionary ID for this matched search term
 2186             $search_terms_ids[$sw] = $i;
 2187 
 2188             if ($ExactPhrase == 1)
 2189             {
 2190                 // we'll use the wordmap data for the first term that we have worked out earlier
 2191                 $data = $phrase_terms_data[0];
 2192                 $data_count = $phrase_data_count[0];
 2193                 $ContextSeeks = 0;
 2194             }
 2195             else
 2196             {
 2197                 // seek to position in wordmap file
 2198                 fseek($fp_wordmap, $dictline[$DICT_PTR]);
 2199                 //print "seeking in wordmap: " . $dictline[1] . "<br />";
 2200 
 2201                 // first 2 bytes is data count
 2202                 $countbytes = fread($fp_wordmap, 2);
 2203                 $data_count = ord($countbytes[0]) | ord($countbytes[1])<<8;
 2204                 //print "data count: " . $data_count . "<br />";
 2205 
 2206                 for ($bi = 0; $bi < $data_count; $bi++)
 2207                 {
 2208                     $bindata = fread($fp_wordmap, 8);
 2209                     if (strlen($bindata) == 0)
 2210                         $OutputResultsBuffer .= "Error in wordmap file: expected data not found";
 2211                     $data[$bi] = unpack("Cscore/Cprox/vpagenum/Vptr", $bindata);
 2212                 }
 2213             }
 2214             $sw_results[$sw] += $data_count;
 2215 
 2216             // Go through wordmap for each page this word appears on
 2217             for ($j = 0; $j < $data_count; $j++)
 2218             {
 2219                 $score = $data[$j]["score"];
 2220                 $prox = $data[$j]["prox"];
 2221                 $txtptr = $data[$j]["ptr"];
 2222                 $ipage = $data[$j]["pagenum"];
 2223 
 2224                 if ($score == 0)
 2225                     continue;
 2226 
 2227                 if ($pageinfo[$ipage]["boost"] != 0)
 2228                 {
 2229                     $score *= ($pageinfo[$ipage]["boost"] / 10);
 2230                     $score = ceil($score);
 2231                 }
 2232 
 2233                 if ($ExactPhrase == 1)
 2234                 {
 2235                     $maxptr = $data[$j]["ptr"];
 2236                     $maxptr_term = 0;
 2237                     $GotoNextPage = 0;
 2238 
 2239                     // Check if all of the other words in the phrase appears on this page.
 2240                     for ($xi = 0; $xi < $num_phrase_terms && $GotoNextPage == 0; $xi++)
 2241                     {
 2242                         // see if this word appears at all on this page, if not, we stop scanning page.
 2243                         // do not check for skipped words (data count value of zero)
 2244                         if ($phrase_data_count[$xi] != 0)
 2245                         {
 2246                             // check wordmap for this search phrase to see if it appears on the current page.
 2247                             for ($xbi = 0; $xbi < $phrase_data_count[$xi]; $xbi++)
 2248                             {
 2249                                 if ($phrase_terms_data[$xi][$xbi]["pagenum"] == $data[$j]["pagenum"])
 2250                                 {
 2251                                     // make sure that words appear in same proximity
 2252 
 2253                                     $overlapProx = $phrase_terms_data[$xi][$xbi]["prox"] << 1;
 2254 
 2255                                     if (($data[$j]["prox"] & $phrase_terms_data[$xi][$xbi]["prox"]) == 0 &&
 2256                                         ($data[$j]["prox"] & $overlapProx) == 0)
 2257                                     {
 2258                                         $GotoNextPage = 1;
 2259                                     }
 2260                                     else
 2261                                     {
 2262                                         // intersection, this term appears on both pages, goto next term
 2263                                         // remember biggest pointer.
 2264                                         if ($phrase_terms_data[$xi][$xbi]["ptr"] > $maxptr)
 2265                                         {
 2266                                             $maxptr = $phrase_terms_data[$xi][$xbi]["ptr"];
 2267                                             $maxptr_term = $xi;
 2268                                         }
 2269                                         $score += $phrase_terms_data[$xi][$xbi]["score"];
 2270                                     }
 2271                                     break;
 2272                                 }
 2273                             }
 2274                             if ($xbi == $phrase_data_count[$xi]) // if not found
 2275                             {
 2276                                 $GotoNextPage = 1;
 2277                                 break;  // goto next page
 2278                             }
 2279                         }
 2280                     }   // end phrase term for loop
 2281                     if ($GotoNextPage == 1)
 2282                     {
 2283                         continue;
 2284                     }
 2285 
 2286                     // Check how many context seeks we have made.
 2287                     $ContextSeeks++;
 2288                     if ($ContextSeeks > $MaxContextSeeks)
 2289                     {                       
 2290                         $IsMaxLimitExceeded = true;
 2291                         break;
 2292                     }
 2293 
 2294                     // ok, so this page contains all of the words in the phrase
 2295                     $FoundPhrase = 0;
 2296                     $FoundFirstWord = 0;
 2297 
 2298                     // we goto the first occurance of the first word in pagetext
 2299                     $pos = $maxptr - (($maxptr_term+3) * $DictIDLen);    // assume 3 possible punctuations.
 2300                     // do not seek further back than the occurance of the first word (avoid wrong page)
 2301                     if ($pos < $data[$j]["ptr"])
 2302                         $pos = $data[$j]["ptr"];
 2303 
 2304                     fseek($fp_pagetext, $pos);
 2305 
 2306                     // now we look for the phrase within the context of this page
 2307                     do
 2308                     {
 2309                         for ($xi = 0; $xi < $num_phrase_terms; $xi++)
 2310                         {
 2311                             // do...while loop to ignore punctuation marks in context phrase
 2312                             do
 2313                             {
 2314                                 // Inlined (and unlooped) the following function for speed reasons
 2315                                 //$xword_id = GetNextDictWord($fp_pagetext);
 2316                                 $bytes_buffer = fread($fp_pagetext, $DictIDLen);
 2317                                 if ($DictIDLen == 4)
 2318                                 {
 2319                                     $xword_id = ord($bytes_buffer[0]);
 2320                                     $xword_id = $xword_id | ord($bytes_buffer[1]) << 8;
 2321                                     $xword_id = $xword_id | ord($bytes_buffer[2]) << (8*2);
 2322                                     $variant_index = $bytes_buffer[3];
 2323                                 }
 2324                                 else
 2325                                 {
 2326                                     $xword_id = ord($bytes_buffer[0]);
 2327                                     $xword_id = $xword_id | ord($bytes_buffer[1]) << 8;
 2328                                     $variant_index = $bytes_buffer[2];
 2329                                 }
 2330                                 $pos += $DictIDLen;
 2331                                 // check if we are at the end of page (wordid = 0) or invalid $xword_id
 2332                                 if ($xword_id == 0 || $xword_id == 1 || $xword_id >= $dict_count)
 2333                                     break;
 2334                             } while ($xword_id <= $DictReservedLimit && !feof($fp_pagetext));
 2335 
 2336                             if ($xword_id == 0 || $xword_id == 1 || $xword_id >= $dict_count)
 2337                                 break;
 2338 
 2339                             // if the words are NOT the same, we break out
 2340                             if ($xword_id != $phrase_terms_ids[$sw][$xi])
 2341                             {
 2342                                 // also check against first word
 2343                                 if ($xi != 0 && $xword_id == $phrase_terms_ids[$sw][0])
 2344                                     $xi = 0;    // matched first word
 2345                                 else
 2346                                     break;
 2347                             }
 2348 
 2349                             // remember how many times we find the first word on this page
 2350                             if ($xi == 0)
 2351                             {
 2352                                 $FoundFirstWord++;
 2353                                 // remember the position of the 'start' of this phrase
 2354                                 $txtptr = $pos - $DictIDLen;
 2355                             }
 2356                         }
 2357                         if ($xi == $num_phrase_terms)
 2358                         {
 2359                             // exact phrase found!
 2360                             $FoundPhrase = 1;
 2361                         }
 2362                     } while ($xword_id != 0 && $FoundPhrase == 0 &&
 2363                             $FoundFirstWord <= $data[$j]["score"]);
 2364 
 2365                     if ($FoundPhrase != 1)
 2366                         continue;   // goto next page.
 2367                         
 2368                     
 2369                     $checktime = time();
 2370                     $checkTimeDiff = abs($starttime - $checktime);
 2371                     if ($checkTimeDiff > $MaxSearchTime)
 2372                     {
 2373                         $IsMaxLimitExceeded = true;                     
 2374                         break;
 2375                     }
 2376                 }
 2377 
 2378                 //Check if page is already in output list
 2379                 $pageexists = 0;
 2380 
 2381                 if ($ExcludeTerm == 1)
 2382                 {
 2383                     // we clear out the score entry so that it'll be excluded in the filtering stage
 2384                     $res_table[$ipage][0] = 0;
 2385                 }
 2386                 elseif ($res_table[$ipage][0] == 0)
 2387                 {
 2388                     // not in list, count this page as a unique match
 2389                     $res_table[$ipage][0] = $score;
 2390                     $res_table[$ipage][2] = $txtptr;
 2391                     $res_table[$ipage][6] = $prox;
 2392                 }
 2393                 else
 2394                 {
 2395                     // already in list
 2396                     if ($res_table[$ipage][0] > 10000)
 2397                     {
 2398                         // take it easy if its too big (to prevent huge scores)
 2399                         $res_table[$ipage][0] += 1;
 2400                     }
 2401                     else
 2402                     {
 2403                         $res_table[$ipage][0] += $score;    //Add in score
 2404                         //$res_table[$ipage][0] *= 2;         //Double Score as we have two words matching
 2405                     }
 2406 
 2407                     // store the next two searchword matches
 2408                     if ($res_table[$ipage][1] > 0 && $res_table[$ipage][1] < $MaxContextKeywords)
 2409                     {
 2410                         if ($res_table[$ipage][3] == 0)
 2411                             $res_table[$ipage][3] = $txtptr;
 2412                         elseif ($res_table[$ipage][4] == 0)
 2413                             $res_table[$ipage][4] = $txtptr;
 2414                     }
 2415 
 2416                     $res_table[$ipage][6] = $res_table[$ipage][6] & $prox;
 2417                 }
 2418                 $res_table[$ipage][1] += 1;
 2419 
 2420                 if ($res_table[$ipage][0] > $maxscore)
 2421                     $maxscore = $res_table[$ipage][0];
 2422 
 2423                 // store the 'and' user search terms matched' value
 2424                 if ($res_table[$ipage][5] == $sw || $res_table[$ipage][5] == $sw-$SkippedWords-$exclude_count)
 2425                     $res_table[$ipage][5] += 1;
 2426             }
 2427 
 2428             if ($UseWildCards[$sw] == 0 && $SearchAsSubstring == 0)
 2429                 break;  //This search word was found, so skip to next
 2430         }
 2431     }
 2432 }
 2433 //Close the files
 2434 fclose($fp_wordmap);
 2435 
 2436 if ($SkippedWords > 0)
 2437 {
 2438     $OutputBuffers[$OUTPUT_SUMMARY] .= "<div class=\"summary\">" . $STR_SKIPPED_FOLLOWING_WORDS . " " . $SkippedOutputStr . "<br />\n";     
 2439     if ($SkippedExactPhrase == 1)
 2440         $OutputBuffers[$OUTPUT_SUMMARY] .= $STR_SKIPPED_PHRASE . ".<br />\n";
 2441     $OutputBuffers[$OUTPUT_SUMMARY] .=  "<br /></div>\n";
 2442 }
 2443 
 2444 $metaParams = "";
 2445 // append to queryForURL with other query parameters for custom meta fields?
 2446 if ($UseMetaFields == 1)
 2447 {
 2448     for ($fieldnum = 0; $fieldnum < $NumMetaFields; $fieldnum++)
 2449     {
 2450         if (is_array($meta_query[$fieldnum]))
 2451         {
 2452             $num_multi_query = count($meta_query[$fieldnum]);
 2453             for ($mqi = 0; $mqi < $num_multi_query; $mqi++)
 2454                 $metaParams .= "&amp;".$metafields[$fieldnum][$METAFIELD_NAME]."[]=".$meta_query[$fieldnum][$mqi];
 2455         }
 2456         else
 2457         {
 2458             if ($meta_query[$fieldnum] !== "")
 2459                 $metaParams .= "&amp;".$metafields[$fieldnum][$METAFIELD_NAME]."=".$meta_query[$fieldnum];
 2460         }
 2461     }
 2462 }
 2463 
 2464 // Do this after search form so we can keep the search form value the same as the way the user entered it
 2465 if ($UseMetaFields == 1 && $MetaMoneyShowDec == 1)
 2466 {
 2467     for ($fieldnum = 0; $fieldnum < $NumMetaFields; $fieldnum++)
 2468     {
 2469         if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MONEY && $meta_query[$fieldnum] !== "")
 2470             $meta_query[$fieldnum] = $meta_query[$fieldnum] * 100;
 2471     }
 2472 }
 2473 
 2474 //Count number of output lines that match ALL search terms
 2475 $oline = 0;
 2476 $fullmatches = 0;
 2477 $matches = 0;
 2478 
 2479 $baseScale = 1.3;
 2480 $proxScale = 1.7;
 2481 if (isset($WeightProximity))
 2482     $proxScale += ($WeightProximity/10);
 2483 
 2484 $CatCounterFilled = 0;
 2485 if ($UseCats && $DisplayCatSummary == 1)
 2486 {
 2487     if (($cat[0] == -1 || $num_zoom_cats > 1) && $NumCats > 0)
 2488         $CatCounter = array_fill(0, $NumCats, 0);
 2489     else
 2490         $DisplayCatSummary = 0;
 2491 }
 2492 
 2493 $dateRangeParams = ""; // append to queryForURL with other query parameters for custom meta fields?
 2494 if ($DateRangeSearch == 1)
 2495 {
 2496     $UseDateRange = false;
 2497     $tmpFromMonth = 0;
 2498     $tmpFromDay = 0;
 2499     $tmpFromYear = 0;
 2500     $tmpToMonth = 0;
 2501     $tmpToDay = 0;
 2502     $tmpToYear = 0;
 2503     if ($DateRangeFormat == 1)
 2504     {
 2505         sscanf($date_from, "%d/%d/%d", $tmpFromMonth, $tmpFromDay, $tmpFromYear);
 2506         sscanf($date_to, "%d/%d/%d", $tmpToMonth, $tmpToDay, $tmpToYear);
 2507     }
 2508     else
 2509     {
 2510         sscanf($date_from, "%d/%d/%d", $tmpFromDay, $tmpFromMonth, $tmpFromYear);
 2511         sscanf($date_to, "%d/%d/%d", $tmpToDay, $tmpToMonth, $tmpToYear);
 2512     }
 2513     if ($tmpFromDay > 0 && $tmpFromMonth > 0 && $tmpFromYear > 0 && $tmpToDay > 0 && $tmpToMonth > 0 && $tmpToYear > 0)
 2514     {       
 2515         $from_datetime = mktime(0, 0, 0, $tmpFromMonth, $tmpFromDay, $tmpFromYear);
 2516         $to_datetime = mktime(23, 59, 59, $tmpToMonth, $tmpToDay, $tmpToYear);
 2517         if ($from_datetime !== FALSE && $to_datetime !== FALSE)
 2518         {
 2519             $UseDateRange = true;
 2520             $dateRangeParams = "&amp;zoom_datefrom=".urlencode($date_from)."&amp;zoom_dateto=".urlencode($date_to);
 2521         }
 2522     }
 2523 }
 2524 
 2525 // Second pass, results filtering.
 2526 $full_numwords = $NumSearchWords - $SkippedWords - $exclude_count;
 2527 for ($i = 0; $i < $pagesCount; $i++)
 2528 {
 2529     $IsFiltered = false;
 2530     $pageUrlBuffer = "";
 2531     
 2532     if ($res_table[$i][0] > 0 || $IsNoKeywordQuery)
 2533     {
 2534         if ($pageinfo[$i]["dataoffset"] == 0)   // filter out if deleted
 2535             $IsFiltered = true;
 2536             
 2537         if ($IsFiltered == false && $searchUrlBuffer !== "")
 2538         {
 2539             $pageUrlBuffer = GetUrlFromPageData($i);
 2540             if (mystristr($pageUrlBuffer, $searchUrlBuffer) === FALSE)
 2541                 $IsFiltered = true;
 2542             else
 2543             {
 2544                 // the site/URL matched with the site: parameter
 2545                 if ($IsNoKeywordQuery)
 2546                 {
 2547                     // increment score/terms if we're allowing this through on site: match alone
 2548                     $res_table[$i][0]++;
 2549                     $res_table[$i][1]++;                    
 2550                 }
 2551             }
 2552         }
 2553         
 2554         if ($UseMetaFields && $IsFiltered == false)
 2555         {           
 2556             for ($fieldnum = 0; $fieldnum < $NumMetaFields && !$IsFiltered; $fieldnum++)
 2557             {               
 2558                 $IsAnyDropdown = false;
 2559                 if (is_array($meta_query[$fieldnum]))
 2560                     $tmpQueryVal = $meta_query[$fieldnum][0];
 2561                 else
 2562                     $tmpQueryVal = $meta_query[$fieldnum];
 2563                     
 2564 
 2565                 if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_DROPDOWN ||
 2566                     $metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MULTI)
 2567                 {
 2568                     if ($tmpQueryVal == -1)
 2569                         $IsAnyDropdown = true;
 2570                 }
 2571 
 2572                 if ($tmpQueryVal !== "" && $IsAnyDropdown == false)
 2573                 {
 2574                     if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_TEXT)
 2575                     {
 2576                         if (strlen($metavalues[$i][$fieldnum]) == 0)
 2577                             $IsFiltered = true;
 2578                         else if ($metafields[$fieldnum][$METAFIELD_METHOD] == $METAFIELD_METHOD_SUBSTRING)
 2579                         {
 2580                             if (mystristr($metavalues[$i][$fieldnum], $meta_query[$fieldnum]) === FALSE)
 2581                                 $IsFiltered = true;
 2582                         }                       
 2583                         else                        
 2584                         {
 2585                             if (strcasecmp($metavalues[$i][$fieldnum], $meta_query[$fieldnum]) !== 0)
 2586                                 $IsFiltered = true;
 2587                         }                       
 2588                     }
 2589                     else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_DROPDOWN)
 2590                     {
 2591                         if ($metavalues[$i][$fieldnum] == $METAFIELD_NOVALUE_MARKER)
 2592                             $IsFiltered = true;
 2593                         else if ($metavalues[$i][$fieldnum] != floatval($meta_query[$fieldnum]))
 2594                             $IsFiltered = true;
 2595                     }
 2596                     else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MULTI)
 2597                     {
 2598                         $IsFiltered = true;
 2599                         if ($metavalues[$i][$fieldnum] !== 0)
 2600                         {
 2601                             $num_multi_query = 0;
 2602                             if (is_array($meta_query[$fieldnum]))
 2603                                 $num_multi_query = count($meta_query[$fieldnum]);
 2604                             for ($mqi = 0; $mqi < $num_multi_query && $IsFiltered; $mqi++)
 2605                             {
 2606                                 for ($mvi = 0; $mvi < $metavalues[$i][$fieldnum][0]; $mvi++)
 2607                                 {
 2608                                     if ($metavalues[$i][$fieldnum][$mvi+1] == intval($meta_query[$fieldnum][$mqi]))
 2609                                     {
 2610                                         $IsFiltered = false;
 2611                                         break;
 2612                                     }
 2613                                 }
 2614                             }
 2615                         }
 2616                     }
 2617                     else
 2618                     {
 2619                         // numeric comparison here
 2620                         if ($metavalues[$i][$fieldnum] == $METAFIELD_NOVALUE_MARKER)
 2621                         {
 2622                             $bRet = false;
 2623                         }
 2624                         else if ($metafields[$fieldnum][$METAFIELD_METHOD] == $METAFIELD_METHOD_LESSTHAN)
 2625                         {
 2626                             $bRet = $metavalues[$i][$fieldnum] < $meta_query[$fieldnum];
 2627                         }
 2628                         else if ($metafields[$fieldnum][$METAFIELD_METHOD] == $METAFIELD_METHOD_LESSTHANORE)
 2629                         {
 2630                             $bRet = $metavalues[$i][$fieldnum] <= $meta_query[$fieldnum];
 2631                         }
 2632                         else if ($metafields[$fieldnum][$METAFIELD_METHOD] == $METAFIELD_METHOD_GREATERTHAN)
 2633                         {
 2634                             $bRet = $metavalues[$i][$fieldnum] > $meta_query[$fieldnum];
 2635                         }
 2636                         else if ($metafields[$fieldnum][$METAFIELD_METHOD] == $METAFIELD_METHOD_GREATERTHANORE)
 2637                         {
 2638                             $bRet = $metavalues[$i][$fieldnum] >= $meta_query[$fieldnum];
 2639                         }
 2640                         else
 2641                         {
 2642                             // exact match
 2643                             $bRet = $metavalues[$i][$fieldnum] == $meta_query[$fieldnum];
 2644                         }
 2645 
 2646                         if ($bRet == false)
 2647                             $IsFiltered = true;
 2648                     }
 2649                 }
 2650                 // only add to res_table if empty query!
 2651                 if ($IsNoKeywordQuery == true && $IsFiltered == false)
 2652                 {
 2653                     $res_table[$i][0]++;
 2654                     $res_table[$i][1]++;
 2655                 }
 2656             }
 2657         }
 2658 
 2659         if ($IsFiltered == false)
 2660         {
 2661             if ($res_table[$i][5] < $full_numwords && $and == 1)
 2662             {
 2663                 // if AND search, only copy AND results             
 2664                 $IsFiltered = true;
 2665             }
 2666         }
 2667         
 2668         if ($UseCats && $cat[0] != -1 && $IsFiltered == false)
 2669         {
 2670             // Using cats and not doing an "all cats" search
 2671             $bFoundCat = false;
 2672             for ($cati = 0; $cati < $num_zoom_cats; $cati++)
 2673             {
 2674                 if (CheckBitInByteArray($cat[$cati], $catpages[$i]) !== 0)
 2675                 {
 2676                     if ($DisplayCatSummary == 1)
 2677                     {
 2678                         $CatCounter[$cat[$cati]]++;
 2679                         $CatCounterFilled = 1;
 2680                     }                   
 2681                     $bFoundCat = true;
 2682                 }
 2683             }
 2684             //if ($cati == $num_zoom_cats)
 2685             if ($bFoundCat == false)
 2686                 $IsFiltered = true; 
 2687         }       
 2688                 
 2689         if ($IsFiltered == false && $DateRangeSearch == 1 && $UseDateRange == true)
 2690         {
 2691             if ($pageinfo[$i]["datetime"] < $from_datetime)
 2692                 $IsFiltered = true;
 2693             else if ($pageinfo[$i]["datetime"] > $to_datetime)
 2694                 $IsFiltered = true;
 2695         } 
 2696         
 2697         if ($IsFiltered == false)
 2698         {
 2699             // we can only count our AND total here AFTER we've filtered out the cats
 2700             if ($res_table[$i][5] >= $full_numwords)
 2701                 $fullmatches++;
 2702                 
 2703             // copy if not filtered out
 2704             $output[$oline][0] = $i;                    // page index
 2705             
 2706             $finalScale = (($res_table[$i][6] / 255.0) * $proxScale) + $baseScale;
 2707 
 2708             if ($res_table[$i][1] > 1)  // multiword search
 2709             {
 2710                 if ($res_table[$i][1] <= 10)
 2711                 {
 2712                     $finalScale = pow($finalScale, $res_table[$i][1]-1);
 2713                 }
 2714                 else
 2715                 {
 2716                     $finalScale = pow($finalScale, 10);
 2717                     $finalScale += $res_table[$i][1] - 10;
 2718                 }
 2719             }
 2720 
 2721             if ($UseCats && $DisplayCatSummary == 1 && $cat[0] == -1)
 2722             {
 2723                 // if we are doing an All category search AND we're showing cat summary
 2724                 for ($cati = 0; $cati < $NumCats; $cati++)
 2725                 {
 2726                     //if (($pageinfo[$i]["catnumber"] & (1 << $cati)) !== 0)
 2727                     if (CheckBitInByteArray($cati, $catpages[$i]) !== 0)
 2728                     {
 2729                         $CatCounter[$cati]++;
 2730                         $CatCounterFilled = 1;
 2731                     }
 2732                 }               
 2733             }
 2734 
 2735             // final score and rounding
 2736             $output[$oline][1] = (int) ($res_table[$i][0] * $finalScale + 0.5);
 2737             $output[$oline][2] = $res_table[$i][1];     // num of sw matched
 2738             $output[$oline][3] = $res_table[$i][2];     // pagetext ptr #1
 2739             $output[$oline][4] = $res_table[$i][3];     // pagetext ptr #2
 2740             $output[$oline][5] = $res_table[$i][4];     // pagetext ptr #3
 2741             $oline++;
 2742         }
 2743     }
 2744 }
 2745 $matches = $oline;
 2746 
 2747 //Sort results in order of score, use the "SortCompare" function
 2748 if ($matches > 1)
 2749 {
 2750     if ($UseDateTime == 1 && $sort == 1)
 2751         usort($output, "SortByDate");
 2752     else if ($UseDateTime == 1 && $sort == 2)
 2753         usort($output, "SortByDateAsc");
 2754     else        
 2755         usort($output, "SortCompare");// Default sort by relevance  
 2756 }
 2757 
 2758 
 2759 if ($UseDomainDiversity == 1)
 2760 {
 2761     if ($page == 1 && $matches > 5) 
 2762     {
 2763         $arrayline = 0;
 2764         $div_res_count = 0;     
 2765         if(!defined('PHP_URL_HOST')) define('PHP_URL_HOST', 2); // This define is missing in PHP4. 
 2766 
 2767         while ($arrayline < $matches && $div_res_count < $MaxDomainDiversity)
 2768         {
 2769             $pageUrlBuffer = GetUrlFromPageData($output[$arrayline][0]);
 2770             $domainBuffer = parse_url($pageUrlBuffer, PHP_URL_HOST);                
 2771             $IsDifferentDomain = true;
 2772             for ($div_url_i = 0; $div_url_i < $div_res_count; $div_url_i++)
 2773             {
 2774                 if (strcasecmp($div_res_urls[$div_url_i], $domainBuffer) == 0)
 2775                 {
 2776                     $IsDifferentDomain = false;
 2777                     break;
 2778                 }
 2779             }
 2780             if ($IsDifferentDomain == true)
 2781             {
 2782                 $div_res_table[$div_res_count] = $arrayline;                
 2783                 $div_res_urls[$div_res_count] = $domainBuffer;
 2784                 $div_res_count++;
 2785             }                                           
 2786             $arrayline++;
 2787         }   
 2788     }
 2789     else
 2790         $UseDomainDiversity = 0;
 2791 }           
 2792 
 2793 //Display search result information
 2794 $OutputBuffers[$OUTPUT_SUMMARY] .= "<div class=\"summary\">\n";
 2795 
 2796 if ($IsMaxLimitExceeded)
 2797     $OutputBuffers[$OUTPUT_SUMMARY] .= $STR_PHRASE_CONTAINS_COMMON_WORDS . "<br /><br />";
 2798 
 2799 if ($matches == 0)
 2800     $OutputBuffers[$OUTPUT_SUMMARY] .= $STR_SUMMARY_NO_RESULTS_FOUND;
 2801 elseif ($NumSearchWords > 1 && $and == 0)
 2802 {
 2803     //OR
 2804     $SomeTermMatches = $matches - $fullmatches;
 2805     $OutputBuffers[$OUTPUT_SUMMARY] .= PrintNumResults($fullmatches) . " " . $STR_SUMMARY_FOUND_CONTAINING_ALL_TERMS . " ";
 2806     if ($SomeTermMatches > 0)
 2807         $OutputBuffers[$OUTPUT_SUMMARY] .= PrintNumResults($SomeTermMatches) . " " . $STR_SUMMARY_FOUND_CONTAINING_SOME_TERMS;
 2808 }
 2809 elseif ($NumSearchWords > 1 && $and == 1) //AND
 2810     $OutputBuffers[$OUTPUT_SUMMARY] .= PrintNumResults($fullmatches) . " " . $STR_SUMMARY_FOUND_CONTAINING_ALL_TERMS;
 2811 else
 2812     $OutputBuffers[$OUTPUT_SUMMARY] .= PrintNumResults($matches) . " " . $STR_SUMMARY_FOUND;
 2813 
 2814 $OutputBuffers[$OUTPUT_SUMMARY] .= "<br />\n</div>\n";
 2815 
 2816 if ($matches < 3)
 2817 {
 2818     if ($and == 1 && $NumSearchWords > 1)
 2819         $OutputBuffers[$OUTPUT_SUGGESTION] .= "<div class=\"suggestion\"><br />" . $STR_POSSIBLY_GET_MORE_RESULTS . " <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=0&amp;zoom_sort=".$sort."\">". $STR_ANY_OF_TERMS . "</a>.</div>";
 2820     else if ($UseCats && $cat[0] != -1)
 2821         $OutputBuffers[$OUTPUT_SUGGESTION] .= "<div class=\"suggestion\"><br />" . $STR_POSSIBLY_GET_MORE_RESULTS . " <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_per_page=".$per_page."&amp;zoom_cat=-1".$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=".$sort."\">" . $STR_ALL_CATS . "</a>.</div>";
 2822 }
 2823 
 2824 // Show category summary
 2825 if ($UseCats == 1 && $DisplayCatSummary == 1 && $CatCounterFilled == 1)
 2826 {   
 2827     $OutputBuffers[$OUTPUT_CATSUMMARY] .= "<div class=\"cat_summary\"><br />".$STR_CAT_SUMMARY."\n<ul>\n";
 2828     $catSummaryItemCount = 0;
 2829     for ($catit = 0; $catit < $NumCats; $catit++)
 2830     {               
 2831         if ($CatCounter[$catit] > 0)
 2832         {
 2833             // if all the results found belonged in this current category, then we don't show it in the summary
 2834             if ($CatCounter[$catit] != $matches)
 2835             {
 2836                 $catSummaryItemCount++;             
 2837                 $OutputBuffers[$OUTPUT_CATSUMMARY] .= "<li><a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_cat=".$catit.$dateRangeParams."&amp;zoom_per_page=".$per_page."&amp;zoom_and=".$and."&amp;zoom_sort=".$sort."\">".$catnames[$catit];
 2838                 $OutputBuffers[$OUTPUT_CATSUMMARY] .= "</a> (".$CatCounter[$catit].")</li>";
 2839             }           
 2840         }
 2841     }
 2842     if ($catSummaryItemCount == 0)
 2843     {
 2844         // Clear the cat summary if we decided we didn't need to show it afterall
 2845         $OutputBuffers[$OUTPUT_CATSUMMARY] = "";
 2846     }
 2847     else
 2848         $OutputBuffers[$OUTPUT_CATSUMMARY] .= "</ul>\n</div>\n";
 2849 }
 2850 
 2851 if ($Spelling == 1)
 2852 {
 2853     // load in spellings file
 2854     $fp_spell = fopen($SPELLINGFILE, "rt");
 2855     $i = 0;
 2856     while (!feof($fp_spell))
 2857     {
 2858         $spline = fgets($fp_spell, $MaxKeyWordLineLen);
 2859         if (strlen($spline) > 0)
 2860         {
 2861             $spell[$i] = explode(" ", $spline, 4);
 2862             $i++;
 2863         }
 2864     }
 2865     fclose($fp_spell);
 2866     $spell_count = $i;
 2867 
 2868     $SuggestStr = "";
 2869     $SuggestionFound = 0;
 2870     $SuggestionCount = 0;
 2871 
 2872     $word = "";
 2873     $word2 = "";
 2874     $word3 = "";
 2875     $tmpWordStr = "";   // for local stemming and comparison
 2876 
 2877     for ($sw = 0; $sw < $NumSearchWords; $sw++)
 2878     {
 2879         if ($sw_results[$sw] >= $SpellingWhenLessThan)
 2880         {
 2881             // this word has enough results
 2882             if ($sw > 0)
 2883                 $SuggestStr = $SuggestStr . " ";
 2884             $SuggestStr = $SuggestStr . $SearchWords[$sw];
 2885         }
 2886         else
 2887         {
 2888             // this word returned less results than threshold, and requires spelling suggestions
 2889             $sw_spcode = GetSPCode($SearchWords[$sw]);          
 2890 
 2891             if (strlen($sw_spcode) > 0)
 2892             {
 2893                 $SuggestionFound = 0;
 2894                 for ($i = 0; $i < $spell_count && $SuggestionFound == 0; $i++)
 2895                 {
 2896                     $spcode = $spell[$i][0];
 2897 
 2898                     if ($spcode == $sw_spcode)
 2899                     {
 2900                         $j = 0;
 2901                         while ($SuggestionFound == 0 && $j < 3 && isset($spell[$i][1+$j]))
 2902                         {
 2903                             $dictid = intval($spell[$i][1+$j]);
 2904                             $word = GetSpellingWord($dictid);
 2905                             $tmpWordStr = $word;
 2906                             if ($UseStemming == 1)
 2907                             {
 2908                                 $tmpWordStr = strtolower($tmpWordStr);
 2909                                 $tmpWordStr = $porterStemmer->Stem($tmpWordStr);
 2910                             }
 2911 
 2912                             if (wordcasecmp($tmpWordStr, $SearchWords[$sw]) == 0)
 2913                             {
 2914                                 // Check that it is not a skipped word or the same word
 2915                                 $SuggestionFound = 0;
 2916                             }
 2917                             else
 2918                             {
 2919                                 $SuggestionFound = 1;
 2920                                 $SuggestionCount++;
 2921                                 if ($NumSearchWords == 1) // if single word search
 2922                                 {
 2923                                     if ($j < 1 && isset($spell[$i][1+$j+1]))
 2924                                     {
 2925                                         $dictid = intval($spell[$i][1+$j+1]);
 2926                                         $word2 = GetSpellingWord($dictid);
 2927                                         $tmpWordStr = $word2;
 2928                                         if ($UseStemming == 1)
 2929                                         {
 2930                                             $tmpWordStr = strtolower($tmpWordStr);
 2931                                             $tmpWordStr = $porterStemmer->Stem($tmpWordStr);
 2932                                         }
 2933                                         if (wordcasecmp($tmpWordStr, $SearchWords[$sw]) == 0)
 2934                                             $word2 = "";
 2935                                     }
 2936                                     if ($j < 2 && isset($spell[$i][1+$j+2]))
 2937                                     {
 2938                                         $dictid = intval($spell[$i][1+$j+2]);
 2939                                         $word3 = GetSpellingWord($dictid);
 2940                                         $tmpWordStr = $word3;
 2941                                         if ($UseStemming == 1)
 2942                                         {
 2943                                             $tmpWordStr = strtolower($tmpWordStr);
 2944                                             $tmpWordStr = $porterStemmer->Stem($tmpWordStr);
 2945                                         }
 2946                                         if (wordcasecmp($tmpWordStr, $SearchWords[$sw]) == 0)
 2947                                             $word3 = "";
 2948                                     }
 2949                                 }
 2950                             }
 2951                             $j++;
 2952                         }
 2953                     }
 2954                     elseif (strcmp($spcode, $sw_spcode) > 0)
 2955                     {
 2956                         break;
 2957                     }
 2958                 }
 2959 
 2960                 if ($SuggestionFound == 1)
 2961                 {
 2962                     if ($sw > 0)
 2963                         $SuggestStr = $SuggestStr . " ";
 2964                     $SuggestStr = $SuggestStr . $word;  // add string AFTER so we can preserve order of words
 2965                 }
 2966             }
 2967         }
 2968     }
 2969     if ($SuggestionCount > 0)
 2970     {
 2971         $OutputBuffers[$OUTPUT_SUGGESTION] .= "<div class=\"suggestion\"><br />" . $STR_DIDYOUMEAN . " <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".urlencode($SuggestStr).$metaParams."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=0&amp;zoom_sort=".$sort."\">". $SuggestStr . "</a>";
 2972         if (strlen($word2) > 0)
 2973             $OutputBuffers[$OUTPUT_SUGGESTION] .= " $STR_OR <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".urlencode($word2).$metaParams."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=".$sort."\">". $word2 . "</a>";
 2974         if (strlen($word3) > 0)
 2975             $OutputBuffers[$OUTPUT_SUGGESTION] .= " $STR_OR <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".urlencode($word3).$metaParams."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=".$sort."\">". $word3 . "</a>";
 2976         $OutputBuffers[$OUTPUT_SUGGESTION] .= "?</div>";
 2977     }
 2978 }
 2979 
 2980 // Number of pages of results
 2981 $num_pages = ceil($matches / $per_page);
 2982 if ($num_pages > 1)
 2983     $OutputBuffers[$OUTPUT_PAGESCOUNT] .= "<div class=\"result_pagescount\"><br />" . $num_pages . " " . $STR_PAGES_OF_RESULTS . "</div>\n";
 2984 
 2985 // Show sorting options
 2986 if ($matches > 1)
 2987 {
 2988     if ($UseDateTime == 1)
 2989     {
 2990         $OutputBuffers[$OUTPUT_SORTING] .= "<div class=\"sorting\">";
 2991         if ($sort == 1)
 2992             $OutputBuffers[$OUTPUT_SORTING] .= "<a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".$page."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=0\">". $STR_SORTBY_RELEVANCE . "</a> / <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".$page."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=2\">". $STR_SORTEDBY_DATE . "</a>";
 2993         elseif ($sort == 2)
 2994             $OutputBuffers[$OUTPUT_SORTING] .= "<a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".$page."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=0\">". $STR_SORTBY_RELEVANCE . "</a> / <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".$page."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=1\">". $STR_SORTEDBY_DATE_ASC . "</a>";
 2995         else
 2996             $OutputBuffers[$OUTPUT_SORTING] .= "<b>". $STR_SORTEDBY_RELEVANCE . "</b> / <a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".$page."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=1\">". $STR_SORTBY_DATE . "</a>";
 2997         $OutputBuffers[$OUTPUT_SORTING] .= "</div>";
 2998     }
 2999 }
 3000 
 3001 // Determine current line of result from the $output array
 3002 if ($page == 1) {
 3003     $arrayline = 0;
 3004 } else {
 3005     $arrayline = (($page - 1) * $per_page);
 3006 }
 3007 
 3008 // The last result to show on this page
 3009 $result_limit = $arrayline + $per_page;
 3010 
 3011 $display_num = $arrayline + 1;
 3012 
 3013 // Display the results
 3014 while ($arrayline < $matches && $arrayline < $result_limit)
 3015 {   
 3016     if ($UseDomainDiversity == 1 && $arrayline < $div_res_count)
 3017     {
 3018         $ipage = $output[$div_res_table[$arrayline]][0];        
 3019         $score = $output[$div_res_table[$arrayline]][1];
 3020         $termsmatched = $output[$div_res_table[$arrayline]][2];
 3021         
 3022         // we'll mark this as done
 3023         $output[$div_res_table[$arrayline]][1] = -1;
 3024     }
 3025     else    
 3026     {
 3027         $ipage = $output[$arrayline][0];
 3028         $score = $output[$arrayline][1];
 3029         $termsmatched = $output[$arrayline][2];
 3030         
 3031         if ($output[$arrayline][1] == -1)
 3032         {
 3033             $arrayline++;
 3034             continue;
 3035         }
 3036     }       
 3037 
 3038     $pgdata = GetPageData($ipage);
 3039     $url = $pgdata[$PAGEDATA_URL];
 3040     $title = $pgdata[$PAGEDATA_TITLE];
 3041     $description = $pgdata[$PAGEDATA_DESC];
 3042     
 3043     $urlLink = $url;
 3044 
 3045     //$urlLink = rtrim($urls[$ipage]);
 3046     if ($GotoHighlight == 1)
 3047     {
 3048         if ($SearchAsSubstring == 1)
 3049             $urlLink = AddParamToURL($urlLink, "zoom_highlightsub=".$queryForURL);
 3050         else
 3051             $urlLink = AddParamToURL($urlLink, "zoom_highlight=".$queryForURL);
 3052     }
 3053     if ($PdfHighlight == 1 && $IsNoKeywordQuery == false)
 3054     {
 3055         if (stristr($urlLink, ".pdf") != FALSE)
 3056             $urlLink = $urlLink."#search=%22".str_replace("\"", "", $query)."%22";
 3057     }
 3058 
 3059     if ($arrayline % 2 == 0)
 3060         $OutputResultsBuffer .= "<div class=\"result_block\">";
 3061     else
 3062         $OutputResultsBuffer .= "<div class=\"result_altblock\">";
 3063 
 3064     if ($PluginOpenNewWindow == 1 && $pageinfo[$ipage]["filetype"] >= $FileTypePluginStart)
 3065         $target = " target=\"_blank\"";
 3066     else
 3067         $target = $zoom_target;
 3068 
 3069     if ($UseZoomImage)
 3070     {
 3071         if (isset($pgdata[$PAGEDATA_IMG]))
 3072             $image = $pgdata[$PAGEDATA_IMG];
 3073         else
 3074             $image = "";
 3075         if (strlen($image) > 0)
 3076         {
 3077             $OutputResultsBuffer .= "<div class=\"result_image\">";
 3078             $OutputResultsBuffer .= "<a href=\"".$urlLink."\"" . $target . "><img src=\"$image\" alt=\"\" class=\"result_image\" /></a>";
 3079             $OutputResultsBuffer .= "</div>";
 3080         }
 3081     }
 3082 
 3083     $OutputResultsBuffer .= "<div class=\"result_title\">";
 3084     if ($DisplayNumber == 1)
 3085         $OutputResultsBuffer .= "<b>".($display_num).".</b>&nbsp;";
 3086     $display_num++;
 3087 
 3088     if ($DisplayTitle == 1)
 3089     {
 3090         $OutputResultsBuffer .= "<a href=\"".$urlLink."\"" . $target . ">";
 3091         $OutputResultsBuffer .= PrintHighlightDescription(rtrim($title));
 3092         $OutputResultsBuffer .= "</a>";
 3093     }
 3094     else
 3095         $OutputResultsBuffer .= "<a href=\"".$urlLink."\"" . $target . ">".rtrim($url)."</a>";
 3096 
 3097     if ($UseCats)
 3098     {
 3099         $OutputResultsBuffer .= " <span class=\"category\">";
 3100         for ($catit = 0; $catit < $NumCats; $catit++)
 3101         {
 3102             //if (($pageinfo[$ipage]["catnumber"] & (1 << $catit)) !== 0)
 3103             if (CheckBitInByteArray($catit, $catpages[$ipage]) !== 0)
 3104                 $OutputResultsBuffer .= " [".trim($catnames[$catit])."]";
 3105         }
 3106         $OutputResultsBuffer .= "</span>";
 3107     }
 3108     $OutputResultsBuffer .= "</div>\n";
 3109 
 3110     if ($UseMetaFields == 1 && $DisplayMetaFields == 1)
 3111     {
 3112         for ($fieldnum = 0; $fieldnum < $NumMetaFields; $fieldnum++)
 3113         {
 3114             $cssFieldName = "result_metaname_" . $metafields[$fieldnum][$METAFIELD_NAME];
 3115             $cssValueName = "result_metavalue_" . $metafields[$fieldnum][$METAFIELD_NAME];          
 3116             if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MULTI)
 3117             {
 3118                 if ($metavalues[$ipage][$fieldnum][0] > 0)
 3119                 {
 3120                     $OutputResultsBuffer .= "<div class=\"result_custommeta\">";
 3121                     $OutputResultsBuffer .= "<span class=\"$cssFieldName\">".$metafields[$fieldnum][$METAFIELD_SHOW].": </span>";
 3122                     $OutputResultsBuffer .= "<span class=\"$cssValueName\">";
 3123                     $ddarray = $metafields[$fieldnum][$METAFIELD_DROPDOWN];
 3124                     for ($mvi = 0; $mvi < $metavalues[$ipage][$fieldnum][0]; $mvi++)
 3125                     {
 3126                         if ($mvi > 0)
 3127                             $OutputResultsBuffer .= ", ";
 3128                         $OutputResultsBuffer .= $ddarray[$metavalues[$ipage][$fieldnum][$mvi+1]];
 3129                     }
 3130                     $OutputResultsBuffer .= "</span>";
 3131                     $OutputResultsBuffer .= "</div>";
 3132                 }
 3133             }
 3134             else
 3135             {
 3136                 if ($metavalues[$ipage][$fieldnum] != $METAFIELD_NOVALUE_MARKER && strlen($metavalues[$ipage][$fieldnum]) > 0)
 3137                 {               
 3138                     if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_DROPDOWN)
 3139                     {
 3140                         $OutputResultsBuffer .= "<div class=\"result_custommeta\">";
 3141                         $OutputResultsBuffer .= "<span class=\"$cssFieldName\">".$metafields[$fieldnum][$METAFIELD_SHOW].": </span>";
 3142                         $OutputResultsBuffer .= "<span class=\"$cssValueName\">";
 3143                         $ddarray = $metafields[$fieldnum][$METAFIELD_DROPDOWN];
 3144                         $OutputResultsBuffer .= $ddarray[$metavalues[$ipage][$fieldnum]]."</span>";
 3145                         $OutputResultsBuffer .= "</div>";
 3146                     }               
 3147                     else if ($metafields[$fieldnum][$METAFIELD_TYPE] == $METAFIELD_TYPE_MONEY)
 3148                     {
 3149                         $OutputResultsBuffer .= "<div class=\"result_custommeta\">";
 3150                         $OutputResultsBuffer .= "<span class=\"$cssFieldName\">".$metafields[$fieldnum][$METAFIELD_SHOW].": </span>";
 3151                         $OutputResultsBuffer .= "<span class=\"$cssValueName\">".$MetaMoneyCurrency;
 3152                         $tmpMoneyStr = "";
 3153                         if ($MetaMoneyShowDec == 1)
 3154                             $tmpMoneyStr = sprintf("%01.2f", $metavalues[$ipage][$fieldnum]/100);
 3155                         else
 3156                             $tmpMoneyStr = sprintf("%d", $metavalues[$ipage][$fieldnum]);
 3157                         $OutputResultsBuffer .= $tmpMoneyStr."</span>";
 3158                         $OutputResultsBuffer .= "</div>";
 3159                     }
 3160                     else
 3161                     {
 3162                         // just print it out
 3163                         $OutputResultsBuffer .= "<div class=\"result_custommeta\">";
 3164                         $OutputResultsBuffer .= "<span class=\"$cssFieldName\">".$metafields[$fieldnum][$METAFIELD_SHOW].": </span>";
 3165                         $OutputResultsBuffer .= "<span class=\"$cssValueName\">";
 3166                         $OutputResultsBuffer .= $metavalues[$ipage][$fieldnum]."</span>";
 3167                         $OutputResultsBuffer .= "</div>";
 3168                     }
 3169                 }
 3170             }
 3171         }
 3172     }
 3173 
 3174     if ($DisplayMetaDesc == 1)
 3175     {
 3176         // Print meta description
 3177         if (strlen($description) > 2) {
 3178             $OutputResultsBuffer .= "<div class=\"description\">";
 3179             $OutputResultsBuffer .= PrintHighlightDescription(rtrim($description));
 3180             $OutputResultsBuffer .= "</div>\n";
 3181         }
 3182     }
 3183 
 3184     if ($DisplayContext == 1 && $output[$arrayline][2] > 0 && $IsNoKeywordQuery == false)
 3185     {
 3186         // Extract contextual page content
 3187         $context_keywords = $output[$arrayline][2]; // # of terms matched
 3188 
 3189         if ($context_keywords > $MaxContextKeywords)
 3190             $context_keywords = $MaxContextKeywords;
 3191 
 3192         $context_word_count = ceil($ContextSize / $context_keywords);
 3193 
 3194         $goback = floor($context_word_count / 2);
 3195         $gobackbytes = $goback * $DictIDLen;
 3196 
 3197         $last_startpos = 0;
 3198         $first_startpos = 0;
 3199         $last_endpos = 0;
 3200 
 3201         $FoundContext = 0;
 3202         $IsEndOfContent = 0;
 3203 
 3204         $OutputResultsBuffer .= "<div class=\"context\">\n";
 3205         for ($j = 0; $IsEndOfContent == 0 && $j < $context_keywords && ($j == 0 || !feof($fp_pagetext)); $j++)
 3206         {
 3207             $origpos = $output[$arrayline][3 + $j];
 3208             $startpos = $origpos;
 3209 
 3210             if ($gobackbytes < $startpos)
 3211             {
 3212                 $startpos = $startpos - $gobackbytes;
 3213                 $noGoBack = false;
 3214             }
 3215             else
 3216                 $noGoBack = true;
 3217 
 3218             // Check that this will not overlap with previous extract
 3219             if (($startpos > $last_startpos || $startpos > $first_startpos) && $startpos < $last_endpos)
 3220                 $startpos = $last_endpos;   // we will just continue last extract if so.
 3221 
 3222             // find the pagetext pointed to
 3223             fseek($fp_pagetext, $startpos);
 3224 
 3225             // remember the last start position
 3226             $last_startpos = $startpos;
 3227             if ($j == 0)
 3228                 $first_startpos = $startpos;        
 3229 
 3230             $last_bytesread = 0;
 3231             $bytesread = 0;
 3232 
 3233             $retDict = GetNextDictWord($fp_pagetext);
 3234             $word_id = $retDict[0];
 3235             $variant_index = $retDict[1];
 3236             $bytesread += $DictIDLen;
 3237 
 3238             $contextArray = array_fill(0, $context_word_count, 0);
 3239             $highlightArray = array_fill(0, $context_word_count, 0);
 3240 
 3241             for ($cti = 0; $cti < $context_word_count && !feof($fp_pagetext); $cti++)
 3242             {
 3243                 if ($word_id == 0 || $word_id == 1 || $word_id >= $dict_count)    // check if end of page or section
 3244                 {
 3245                     // if end of page occurs AFTER word pointer (ie: reached next page)
 3246                     if ($noGoBack || ($startpos+$bytesread) > $origpos)
 3247                     {
 3248                         $IsEndOfContent = 1;
 3249                         break;          // then we stop.
 3250                     }
 3251                     else                // if end of page occurs BEFORE word pointer (ie: reached previous page)
 3252                     {
 3253                         //$context_str = "";// then we clear the existing context buffer we've created.
 3254                         $contextArray = array_fill(0, $context_word_count, 0);  // then we clear the existing context buffer we've created.
 3255                         $cti = 0;
 3256                     }
 3257                 }
 3258                 else
 3259                 {
 3260                     if ($word_id >= $NumKeywords)
 3261                     {
 3262                         $OutputResultsBuffer .= "Critical error with pagetext file.  Check that your files are from the same indexing session.";
 3263                     }
 3264                     else
 3265                     {
 3266                         if ($Highlighting == 1 && $IsNoKeywordQuery == false && ($startpos+$last_bytesread) == $origpos)
 3267                             $highlightArray[$cti] = 1;
 3268 
 3269                         $contextArray[$cti] = array();
 3270                         $contextArray[$cti][0] = $word_id;
 3271                         $contextArray[$cti][1] = $variant_index;
 3272                     }
 3273                 }
 3274                 $last_bytesread = $bytesread;
 3275 
 3276                 $retDict = GetNextDictWord($fp_pagetext);
 3277                 $word_id = $retDict[0];
 3278                 $variant_index = $retDict[1];
 3279                 $bytesread += $DictIDLen;
 3280             }
 3281             
 3282             // remember the last end position (if not already at end of page)
 3283             if ($word_id != 0)
 3284                 $last_endpos = ftell($fp_pagetext);
 3285 
 3286             if ($Highlighting == 1)
 3287             {
 3288                 HighlightContextArray($context_word_count);
 3289             }
 3290 
 3291             $prev_word_id = 0;
 3292             $context_str = "";
 3293             $noSpaceForNextChar = false;
 3294 
 3295             for ($cti = 0; $cti < $context_word_count && !feof($fp_pagetext); $cti++)
 3296             {
 3297                 if ($contextArray[$cti] == 0)
 3298                     continue;
 3299 
 3300                 $word_id = $contextArray[$cti][0];
 3301                 $variant_index = $contextArray[$cti][1];
 3302 
 3303                 if ($noSpaceForNextChar == false)
 3304                 {
 3305                     // No space for reserved words (punctuation, etc)
 3306                     if ($word_id > $DictReservedNoSpaces)
 3307                     {
 3308                         if ($prev_word_id <= $DictReservedPrefixes || $prev_word_id > $DictReservedNoSpaces)
 3309                             $context_str .= " ";
 3310                     }
 3311                     elseif  ($word_id > $DictReservedSuffixes && $word_id <= $DictReservedPrefixes)
 3312                     {
 3313                         // This is a Prefix character
 3314                         $context_str .= " ";
 3315                         $noSpaceForNextChar = true;
 3316                     }
 3317                     elseif ($word_id > $DictReservedPrefixes)   // this is a nospace character
 3318                         $noSpaceForNextChar = true;
 3319                 }
 3320                 else
 3321                     $noSpaceForNextChar = false;
 3322 
 3323                 if ($word_id > 0)
 3324                 {
 3325                     if ($Highlighting == 1 &&
 3326                         ($highlightArray[$cti] == $HIGHLIGHT_SINGLE || $highlightArray[$cti] == $HIGHLIGHT_START))
 3327                         $context_str .= "<span class=\"highlight\">";
 3328 
 3329                     $context_str .= GetDictionaryWord($word_id, $variant_index);
 3330 
 3331                     if ($Highlighting == 1 &&
 3332                         ($highlightArray[$cti] == $HIGHLIGHT_SINGLE || $highlightArray[$cti] == $HIGHLIGHT_END))
 3333                         $context_str .= "</span>";
 3334 
 3335                     $prev_word_id = $word_id;
 3336                 }
 3337             }
 3338 
 3339             if (strcmp(trim($context_str), trim($title)) == 0)
 3340             {
 3341                 $context_str = ""; // clear the string if its identical to the title
 3342             }
 3343 
 3344             if ($context_str != "")
 3345             {
 3346                 $OutputResultsBuffer .= " <b>...</b> ";
 3347                 $FoundContext = 1;              
 3348                 $OutputResultsBuffer .= $context_str;
 3349                 //$OutputResultsBuffer .= PrintHighlightDescription($context_str);
 3350             }
 3351         }
 3352         if ($FoundContext == 1)
 3353             $OutputResultsBuffer .= " <b>...</b>";
 3354         $OutputResultsBuffer .= "</div>\n";
 3355     }
 3356 
 3357     $info_str = "";
 3358 
 3359     if ($DisplayTerms == 1)
 3360     {
 3361         $info_str .= $STR_RESULT_TERMS_MATCHED . " ". $termsmatched;
 3362     }
 3363 
 3364     if ($DisplayScore == 1)
 3365     {
 3366         if (strlen($info_str) > 0)
 3367             $info_str .= "&nbsp; - &nbsp;";
 3368         $info_str .= $STR_RESULT_SCORE . " " . $score;
 3369     }
 3370 
 3371     if ($DisplayDate == 1 && $pageinfo[$ipage]["datetime"] > 0)
 3372     {
 3373         if (strlen($info_str) > 0)
 3374             $info_str .= "&nbsp; - &nbsp;";
 3375         $info_str .= date("j M Y", $pageinfo[$ipage]["datetime"]);
 3376     }
 3377 
 3378     if ($DisplayFilesize == 1)
 3379     {
 3380         if (strlen($info_str) > 0)
 3381             $info_str .= "&nbsp; - &nbsp;";
 3382         $filesize = $pageinfo[$ipage]["filesize"]/1024;
 3383         if ($filesize == 0)
 3384             $filesize = 1;
 3385         $info_str .= number_format($filesize) . "k";
 3386     }
 3387 
 3388     if ($DisplayURL == 1)
 3389     {
 3390         if (strlen($info_str) > 0)
 3391             $info_str .= "&nbsp; - &nbsp;";
 3392 
 3393         $url = rtrim($url);
 3394         if ($TruncateShowURL > 0)
 3395         {
 3396             if (strlen($url) > $TruncateShowURL)
 3397                 $url = substr($url, 0, $TruncateShowURL) . "...";
 3398         }
 3399         $info_str .= $STR_RESULT_URL . " ".$url;
 3400     }
 3401 
 3402     $OutputResultsBuffer .= "<div class=\"infoline\">";
 3403     $OutputResultsBuffer .= $info_str;
 3404     $OutputResultsBuffer .= "</div>\n";
 3405 
 3406     $OutputResultsBuffer .= "</div>";
 3407 
 3408     $arrayline++;
 3409 }
 3410 
 3411 if ($DisplayContext == 1 || $AllowExactPhrase == 1)
 3412     fclose($fp_pagetext);
 3413 
 3414 fclose($fp_pagedata);
 3415 
 3416 $OutputResultsBuffer .= "</div>"; // end of results style tag
 3417 
 3418 // Show links to other result pages
 3419 if ($num_pages > 1)
 3420 {
 3421     // 10 results to the left of the current page
 3422     $start_range = $page - 10;
 3423     if ($start_range < 1)
 3424         $start_range = 1;
 3425 
 3426     // 10 to the right
 3427     $end_range = $page + 10;
 3428     if ($end_range > $num_pages)
 3429         $end_range = $num_pages;
 3430 
 3431     $OutputBuffers[$OUTPUT_PAGENUMBERS] .= "<div class=\"result_pages\">\n" . $STR_RESULT_PAGES . " ";
 3432     if ($page > 1)
 3433         $OutputBuffers[$OUTPUT_PAGENUMBERS] .= "<a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".($page-1)."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=".$sort."\">&lt;&lt; " . $STR_RESULT_PAGES_PREVIOUS . "</a> ";
 3434     for ($i = $start_range; $i <= $end_range; $i++)
 3435     {
 3436         if ($i == $page)
 3437             $OutputBuffers[$OUTPUT_PAGENUMBERS] .= $page." ";
 3438         else
 3439             $OutputBuffers[$OUTPUT_PAGENUMBERS] .= "<a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".($i)."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=".$sort."\">".$i."</a> ";
 3440     }
 3441     if ($page != $num_pages)
 3442         $OutputBuffers[$OUTPUT_PAGENUMBERS] .= "<a href=\"".$SelfURL.$LinkBackJoinChar."zoom_query=".$queryForURL.$metaParams."&amp;zoom_page=".($page+1)."&amp;zoom_per_page=".$per_page.$query_zoom_cats.$dateRangeParams."&amp;zoom_and=".$and."&amp;zoom_sort=".$sort."\">" . $STR_RESULT_PAGES_NEXT . " &gt;&gt;</a> ";
 3443     $OutputBuffers[$OUTPUT_PAGENUMBERS] .= "</div>";
 3444 }
 3445 
 3446 //Let others know about Zoom.
 3447 if ($ZoomInfo == 1)
 3448     $OutputBuffers[$OUTPUT_PAGENUMBERS] .= "<center><p><small>" . $STR_POWEREDBY . " <a href=\"http://www.wrensoft.com/zoom/\" target=\"_blank\"><b>Zoom Search Engine</b></a></small></p></center>";
 3449 
 3450 
 3451 if ($Timing == 1 || $Logging == 1)
 3452 {
 3453     $mtime = explode(" ", microtime());
 3454     $endtime   = doubleval($mtime[1]) + doubleval($mtime[0]);
 3455     $difference = abs($starttime - $endtime);
 3456     $timetaken = number_format($difference, 3, '.', '');
 3457     if ($Timing == 1)
 3458         $OutputBuffers[$OUTPUT_SEARCHTIME] .= "<div class=\"searchtime\"><br /><br />" . $STR_SEARCH_TOOK . " " . $timetaken . " " . $STR_SECONDS . "</div>\n";
 3459 }
 3460 
 3461 //Log the search words, if required
 3462 if ($Logging == 1)
 3463 {
 3464     $LogQuery = str_replace("\"", "\"\"", $query);
 3465     if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
 3466     {
 3467         $ip_addr = $_SERVER['HTTP_X_FORWARDED_FOR'];
 3468         $ip_array = explode(",", $ip_addr);
 3469         if (count($ip_array) > 0)
 3470             $ip_addr = trim($ip_array[0]);  // get first IP if there are multiple addresses
 3471     }
 3472     else
 3473         $ip_addr = $_SERVER['REMOTE_ADDR'];
 3474     $LogString = Date("Y-m-d, H:i:s") . ", " . $ip_addr . ", \"" .$LogQuery  . "\", Matches = " . $matches;
 3475     if ($and == 1)
 3476         $LogString = $LogString . ", AND";
 3477     else
 3478         $LogString = $LogString . ", OR";
 3479 
 3480     if ($NewSearch == 1)
 3481         $page = 0;
 3482 
 3483     $LogString = $LogString . ", PerPage = " . $per_page . ", PageNum = " . $page;
 3484 
 3485     if ($UseCats == 0)
 3486         $LogString = $LogString . ", No cats";
 3487     else
 3488     {
 3489         if ($cat[0] == -1)
 3490             $LogString = $LogString . ", \"Cat = All\"";
 3491         else
 3492         {
 3493             $LogString = $LogString . ", \"Cat = ";
 3494             for ($cati = 0; $cati < $num_zoom_cats; $cati++)
 3495             {
 3496                 if ($cati > 0)
 3497                     $LogString = $LogString . "; ";
 3498                 $logCatStr = trim($catnames[$cat[$cati]]);
 3499                 $logCatStr = str_replace("\"", "\"\"", $logCatStr);
 3500                 $LogString = $LogString . $logCatStr;
 3501             }
 3502             $LogString = $LogString . "\"";
 3503         }
 3504     }
 3505     $LogString = $LogString . ", Time = " . $timetaken;
 3506 
 3507     $LogString = $LogString . ", Rec = " . $num_recs_found;
 3508 
 3509     // end of entry
 3510     $LogString = $LogString . "\r\n";
 3511 
 3512     $fp = fopen ($LogFileName, "ab");
 3513     if ($fp != false)
 3514     {
 3515         fputs ($fp, $LogString);
 3516         fclose ($fp);
 3517     }
 3518     else
 3519     {
 3520         $OutputResultsBuffer .= "Unable to write to log file (" . $LogFileName . "). Check that you have specified the correct log filename in your Indexer settings and that you have the required file permissions set.<br />";
 3521     }
 3522 }
 3523 
 3524 //Print out the end of the template
 3525 ShowTemplate();
 3526 
 3527 
 3528 // ----------------------------------------------------------------------------------
 3529 // Porter Stemming algorithm by Dr Martin Porter.
 3530 // PHP5 implementation by Richard Heyes, copyright 2005.
 3531 // PHP4 support and additional features by Wrensoft, copyright 2009.
 3532 // The PorterStemmer class is available for use "free of charge for any purpose" as
 3533 // published on Martin Porter's website (http://tartarus.org/~martin/PorterStemmer/)
 3534 // ----------------------------------------------------------------------------------
 3535 class PorterStemmer
 3536 {
 3537     var $regex_consonant = '(?:[bcdfghjklmnpqrstvwxz]|(?<=[aeiou])y|^y)';
 3538     var $regex_vowel = '(?:[aeiou]|(?<![aeiou])y)';
 3539     var $StemStopChars = '`1234567890-=[]\\;\',./~!@#$%^&*_+|:"<>?';
 3540 
 3541     function Stem($word)
 3542     {
 3543         if (strlen($word) <= 2) {
 3544             return $word;
 3545         }
 3546 
 3547         if (strcspn($word, $this->StemStopChars) < strlen($word))
 3548             return $word;
 3549 
 3550         $word = $this->step1ab($word);
 3551         $word = $this->step1c($word);
 3552         $word = $this->step2($word);
 3553         $word = $this->step3($word);
 3554         $word = $this->step4($word);
 3555         $word = $this->step5($word);
 3556 
 3557         return $word;
 3558     }
 3559 
 3560     function step1ab($word)
 3561     {
 3562         // Part a
 3563         if (substr($word, -1) == 's') {
 3564 
 3565                $this->replace($word, 'sses', 'ss')
 3566             OR $this->replace($word, 'ies', 'i')
 3567             OR $this->replace($word, 'ss', 'ss')
 3568             OR $this->replace($word, 's', '');
 3569         }
 3570 
 3571         // Part b
 3572         if (substr($word, -2, 1) != 'e' OR !$this->replace($word, 'eed', 'ee', 0)) { // First rule
 3573             $v = $this->regex_vowel;
 3574 
 3575             // ing and ed
 3576             if (   preg_match("#$v+#", substr($word, 0, -3)) && $this->replace($word, 'ing', '')
 3577                 OR preg_match("#$v+#", substr($word, 0, -2)) && $this->replace($word, 'ed', '')) { // Note use of && and OR, for precedence reasons
 3578 
 3579                 // If one of above two test successful
 3580                 if (    !$this->replace($word, 'at', 'ate')
 3581                     AND !$this->replace($word, 'bl', 'ble')
 3582                     AND !$this->replace($word, 'iz', 'ize')) {
 3583 
 3584                     // Double consonant ending
 3585                     if (    $this->doubleConsonant($word)
 3586                         AND substr($word, -2) != 'll'
 3587                         AND substr($word, -2) != 'ss'
 3588                         AND substr($word, -2) != 'zz') {
 3589 
 3590                         $word = substr($word, 0, -1);
 3591 
 3592                     } else if ($this->m($word) == 1 AND $this->cvc($word)) {
 3593                         $word .= 'e';
 3594                     }
 3595                 }
 3596             }
 3597         }
 3598         return $word;
 3599     }
 3600 
 3601     function step1c($word)
 3602     {
 3603         $v = $this->regex_vowel;
 3604 
 3605         if (substr($word, -1) == 'y' && preg_match("#$v+#", substr($word, 0, -1))) {
 3606             $this->replace($word, 'y', 'i');
 3607         }
 3608 
 3609         return $word;
 3610     }
 3611 
 3612     function step2($word)
 3613     {
 3614         switch (substr($word, -2, 1)) {
 3615             case 'a':
 3616                    $this->replace($word, 'ational', 'ate', 0)
 3617                 OR $this->replace($word, 'tional', 'tion', 0);
 3618                 break;
 3619 
 3620             case 'c':
 3621                    $this->replace($word, 'enci', 'ence', 0)
 3622                 OR $this->replace($word, 'anci', 'ance', 0);
 3623                 break;
 3624 
 3625             case 'e':
 3626                 $this->replace($word, 'izer', 'ize', 0);
 3627                 break;
 3628 
 3629             case 'g':
 3630                 $this->replace($word, 'logi', 'log', 0);
 3631                 break;
 3632 
 3633             case 'l':
 3634                    $this->replace($word, 'entli', 'ent', 0)
 3635                 OR $this->replace($word, 'ousli', 'ous', 0)
 3636                 OR $this->replace($word, 'alli', 'al', 0)
 3637                 OR $this->replace($word, 'bli', 'ble', 0)
 3638                 OR $this->replace($word, 'eli', 'e', 0);
 3639                 break;
 3640 
 3641             case 'o':
 3642                    $this->replace($word, 'ization', 'ize', 0)
 3643                 OR $this->replace($word, 'ation', 'ate', 0)
 3644                 OR $this->replace($word, 'ator', 'ate', 0);
 3645                 break;
 3646 
 3647             case 's':
 3648                    $this->replace($word, 'iveness', 'ive', 0)
 3649                 OR $this->replace($word, 'fulness', 'ful', 0)
 3650                 OR $this->replace($word, 'ousness', 'ous', 0)
 3651                 OR $this->replace($word, 'alism', 'al', 0);
 3652                 break;
 3653 
 3654             case 't':
 3655                    $this->replace($word, 'biliti', 'ble', 0)
 3656                 OR $this->replace($word, 'aliti', 'al', 0)
 3657                 OR $this->replace($word, 'iviti', 'ive', 0);
 3658                 break;
 3659         }
 3660         return $word;
 3661     }
 3662 
 3663     function step3($word)
 3664     {
 3665         switch (substr($word, -2, 1)) {
 3666             case 'a':
 3667                 $this->replace($word, 'ical', 'ic', 0);
 3668                 break;
 3669 
 3670             case 's':
 3671                 $this->replace($word, 'ness', '', 0);
 3672                 break;
 3673 
 3674             case 't':
 3675                    $this->replace($word, 'icate', 'ic', 0)
 3676                 OR $this->replace($word, 'iciti', 'ic', 0);
 3677                 break;
 3678 
 3679             case 'u':
 3680                 $this->replace($word, 'ful', '', 0);
 3681                 break;
 3682 
 3683             case 'v':
 3684                 $this->replace($word, 'ative', '', 0);
 3685                 break;
 3686 
 3687             case 'z':
 3688                 $this->replace($word, 'alize', 'al', 0);
 3689                 break;
 3690         }
 3691 
 3692         return $word;
 3693     }
 3694 
 3695     function step4($word)
 3696     {
 3697         switch (substr($word, -2, 1)) {
 3698             case 'a':
 3699                 $this->replace($word, 'al', '', 1);
 3700                 break;
 3701 
 3702             case 'c':
 3703                    $this->replace($word, 'ance', '', 1)
 3704                 OR $this->replace($word, 'ence', '', 1);
 3705                 break;
 3706 
 3707             case 'e':
 3708                 $this->replace($word, 'er', '', 1);
 3709                 break;
 3710 
 3711             case 'i':
 3712                 $this->replace($word, 'ic', '', 1);
 3713                 break;
 3714 
 3715             case 'l':
 3716                    $this->replace($word, 'able', '', 1)
 3717                 OR $this->replace($word, 'ible', '', 1);
 3718                 break;
 3719 
 3720             case 'n':
 3721                    $this->replace($word, 'ant', '', 1)
 3722                 OR $this->replace($word, 'ement', '', 1)
 3723                 OR $this->replace($word, 'ment', '', 1)
 3724                 OR $this->replace($word, 'ent', '', 1);
 3725                 break;
 3726 
 3727             case 'o':
 3728                 if (substr($word, -4) == 'tion' OR substr($word, -4) == 'sion') {
 3729                    $this->replace($word, 'ion', '', 1);
 3730                 } else {
 3731                     $this->replace($word, 'ou', '', 1);
 3732                 }
 3733                 break;
 3734 
 3735             case 's':
 3736                 $this->replace($word, 'ism', '', 1);
 3737                 break;
 3738 
 3739             case 't':
 3740                    $this->replace($word, 'ate', '', 1)
 3741                 OR $this->replace($word, 'iti', '', 1);
 3742                 break;
 3743 
 3744             case 'u':
 3745                 $this->replace($word, 'ous', '', 1);
 3746                 break;
 3747 
 3748             case 'v':
 3749                 $this->replace($word, 'ive', '', 1);
 3750                 break;
 3751 
 3752             case 'z':
 3753                 $this->replace($word, 'ize', '', 1);
 3754                 break;
 3755         }
 3756 
 3757         return $word;
 3758     }
 3759 
 3760     function step5($word)
 3761     {
 3762         // Part a
 3763         if (substr($word, -1) == 'e') {
 3764             if ($this->m(substr($word, 0, -1)) > 1) {
 3765                 $this->replace($word, 'e', '');
 3766 
 3767             } else if ($this->m(substr($word, 0, -1)) == 1) {
 3768 
 3769                 if (!$this->cvc(substr($word, 0, -1))) {
 3770                     $this->replace($word, 'e', '');
 3771                 }
 3772             }
 3773         }
 3774 
 3775         // Part b
 3776         if ($this->m($word) > 1 AND $this->doubleConsonant($word) AND substr($word, -1) == 'l') {
 3777             $word = substr($word, 0, -1);
 3778         }
 3779 
 3780         return $word;
 3781     }
 3782 
 3783     function replace(&$str, $check, $repl, $m = null)
 3784     {
 3785         $len = 0 - strlen($check);
 3786 
 3787         if (substr($str, $len) == $check) {
 3788             $substr = substr($str, 0, $len);
 3789             if (is_null($m) OR $this->m($substr) > $m) {
 3790                 $str = $substr . $repl;
 3791             }
 3792 
 3793             return true;
 3794         }
 3795 
 3796         return false;
 3797     }
 3798 
 3799     function m($str)
 3800     {
 3801         $c = $this->regex_consonant;
 3802         $v = $this->regex_vowel;
 3803 
 3804         $str = preg_replace("#^$c+#", '', $str);
 3805         $str = preg_replace("#$v+$#", '', $str);
 3806 
 3807         preg_match_all("#($v+$c+)#", $str, $matches);
 3808 
 3809         return count($matches[1]);
 3810     }
 3811 
 3812     function doubleConsonant($str)
 3813     {
 3814         $c = $this->regex_consonant;
 3815 
 3816         return preg_match("#$c{2}$#", $str, $matches) AND $matches[0]{0} == $matches[0]{1};
 3817     }
 3818 
 3819     function cvc($str)
 3820     {
 3821         $c = $this->regex_consonant;
 3822         $v = $this->regex_vowel;
 3823 
 3824         return     preg_match("#($c$v$c)$#", $str, $matches)
 3825                AND strlen($matches[1]) == 3
 3826                AND $matches[1]{2} != 'w'
 3827                AND $matches[1]{2} != 'x'
 3828                AND $matches[1]{2} != 'y';
 3829     }
 3830 }
 3831 
 3832 ?>