Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
funnelback_search_page.inc
1 <?php
18 require_once SQ_CORE_PACKAGE_PATH.'/page/page.inc';
19 require_once SQ_PACKAGES_PATH.'/cms/listing_engine/listing_engine.inc';
20 require_once SQ_LIB_PATH.'/html_form/html_form.inc';
21 
35 {
36 
41  var $bodycopies = Array(
42  'initial' => 'Initial Search Page Layout',
43  'results' => 'Results Page Layout',
44  'no_results' => 'No Results Page Layout',
45  );
46 
52  var $defaults = Array('query_width' => 25);
53 
59  var $keywords = Array(
60  'initial' => Array(
61  'current_query_term',
62  'search_query',
63  'search_logic',
64  'search_scope',
65  'search_sort',
66  'search_button',
67  'submit_button',
68  'results_per_page',
69  'metadata_scope_X',
70  'metadata_logic_X',
71  ),
72  'results' => Array(
73  'page_list_X',
74  'result_list',
75  'spell_suggestion',
76  'fluster_category_type',
77  'fluster_category_topic',
78  'fluster_category_site',
79  'fluster_current_term',
80  'fluster_navigation',
81  'result_featured',
82  'result_count',
83  'result_count_fully',
84  'result_count_partially',
85  'result_count_pages',
86  'total_result_pages',
87  'result_per_page',
88  'current_result_page',
89  'current_result_page_start',
90  'current_result_page_end',
91  'result_page_index',
92  'previous_result_page_link',
93  'next_result_page_link',
94  'previous_result_page_href',
95  'next_result_page_href',
96  'initial_layout',
97  ),
98  'no_results' => Array(
99  'initial_layout',
100  'spell_suggestion',
101  ),
102  'default_format' => Array(
103  'result_rank',
104  'result_score',
105  'result_name_linked',
106  'result_title',
107  'result_summary',
108  'result_url',
109  'result_url_click_event',
110  'result_url_click_js',
111  'result_size',
112  'result_type',
113  'result_meta_X'
114  ),
115  'featured_format' => Array(
116  'featured_trigger',
117  'featured_url',
118  'featured_title',
119  'featured_summary',
120  ),
121  'context_format' => Array(
122  'fluster_category_name',
123  'fluster_current_term',
124  'fluster_navigation',
125  'fluster_list',
126  ),
127  'cluster_format' => Array(
128  'cluster_name',
129  'cluster_url',
130  'cluster_count',
131  ),
132  'navigation_format' => Array(
133  'navigation_name',
134  'navigation_url',
135  ),
136  'spell_format' => Array(
137  'spell_url',
138  'spell_text',
139  ),
140  );
141 
142 
149  function __construct($assetid=0)
150  {
151  $this->_ser_attrs = TRUE;
152  parent::__construct($assetid);
153 
154  }//end constructor
155 
156 
177  function _createAdditional(Array &$link)
178  {
179  // Overriding the listing engine _createAdditional() and using Page instead
180  if (!Page::_createAdditional($link)) return FALSE;
181 
182  // add a bodycopy to this page when creating
183  $GLOBALS['SQ_SYSTEM']->am->includeAsset('bodycopy');
184  $GLOBALS['SQ_SYSTEM']->am->includeAsset('folder');
185 
186  $sub_assets= Array(
187  'type_format' => 'folder',
188  'fluster_format' => 'folder',
189  'spell_format' => 'folder',
190  );
191 
192  $type_formats = NULL;
193  foreach ($sub_assets as $name => $type) {
194  $asset = new $type();
195  $copy_link = Array('asset' => &$this, 'value' => $name ,'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
196 
197  $asset->setAttrValue('name', translate($name));
198  if (!$asset->create($copy_link)) return FALSE;
199 
200  // Add in the extra bodycopies
201  switch ($name) {
202  case 'fluster_format':
203  foreach (Array('cluster_format', 'navigation_format', 'context_format') as $extra_format) {
204  $bc2_asset = new Bodycopy();
205  $bc2_copy_link = Array('asset' => &$asset, 'value' => $extra_format, 'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
206  $bc2_asset->setAttrValue('name', translate($extra_format));
207  $bc2_args = Array('content' => $this->_getDefaultBodycopyContent($extra_format));
208  if (!$bc2_asset->create($bc2_copy_link, $bc2_args)) return FALSE;
209  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($bc2_asset);
210  unset($bc2_asset);
211  }//end foreach
212  break;
213 
214  case 'type_format':
215  foreach (Array('featured_format', 'default_format') as $extra_format) {
216  $bc2_asset = new Bodycopy();
217  $bc2_copy_link = Array('asset' => &$asset, 'value' => $extra_format, 'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
218  $bc2_asset->setAttrValue('name', translate($extra_format));
219  $bc2_args = Array('content' => $this->_getDefaultBodycopyContent($extra_format));
220  if (!$bc2_asset->create($bc2_copy_link, $bc2_args)) return FALSE;
221  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($bc2_asset);
222  unset($bc2_asset);
223  }//end foreach
224  break;
225 
226  case 'spell_format':
227  $extra_format = 'spell_format';
228  $bc_asset = new Bodycopy();
229  $bc_copy_link = Array('asset' => &$asset, 'value' => $extra_format, 'link_type' => SQ_LINK_TYPE_2, 'is_dependant' => 1, 'is_exclusive' => 1);
230  $bc_asset->setAttrValue('name', translate($extra_format));
231  $bc_args = Array('content' => $this->_getDefaultBodycopyContent($extra_format));
232  if (!$bc_asset->create($bc_copy_link, $bc_args)) return FALSE;
233  break;
234 
235  default:
236  // Do nothing
237  break;
238  }//end switch
239 
240  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($bc_asset);
241  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($asset);
242  unset($bc_asset);
243  unset($asset);
244  }//end foreach
245 
246  return $this->_createBodycopies();
247 
248  }//end _createAdditional()
249 
250 
259  function _createBodycopies()
260  {
261  foreach ($this->bodycopies as $value => $name) {
262  $copy_link = Array(
263  'asset' => &$this,
264  'link_type' => SQ_LINK_TYPE_2,
265  'is_dependant' => 1,
266  'is_exclusive' => 1,
267  'value' => $value,
268  );
269 
270  $bodycopy = new Bodycopy();
271  $bodycopy->setAttrValue('name', $name);
272  $args = Array('content' => $this->_getDefaultBodycopyContent($value));
273  if (!$bodycopy->create($copy_link, $args)) {
274  return FALSE;
275  }
276  }
277 
278  return TRUE;
279 
280  }//end _createBodycopies()
281 
282 
291  function _getDefaultBodycopyContent($bodycopy_code)
292  {
293  switch ($bodycopy_code) {
294  case 'initial':
295  return '<p>Search: %search_query% %search_sort% %submit_button%</p>';
296  case 'results':
297  return '<p>%initial_layout%<br />%spell_suggestion%<br /> %result_count% Results found:</p><p>%result_featured% <br />%result_list%</p><p>%previous_result_page_link% %page_list_10% %next_result_page_link%</p><p>%fluster_category_topic%</p>';
298  case 'no_results':
299  return '<p>No results</p>%initial_layout%';
300  case 'default_format':
301  case 'custom_format':
302  return '<p>%result_name_linked%<br />%result_summary%</p>';
303  case 'featured_format':
304  return '<p><a href="%featured_url%">%featured_title%</a><br />%featured_summary%</p>';
305  case 'context_format':
306  return '<p>%fluster_current_term% by %fluster_category_name%</p> <p>%fluster_list%</p>';
307  case 'cluster_format':
308  return '<p><a href="%cluster_url%">%cluster_name%</a> (%cluster_count%)</p>';
309  case 'navigation_format':
310  return '<p><a href="%navigation_url%">%navigation_name%</a></p>';
311  case 'spell_format':
312  return '<p>Did you mean: <a href="%spell_url%">%spell_text%</a>?</p>';
313  default:
314  // Do nothing
315  break;
316  }//end switch
317  return parent::_getDefaultBodycopyContent($bodycopy_code);
318 
319  }//end _getDefaultBodycopyContent()
320 
321 
342  function prepareLink(&$asset, $side_of_link, &$link_type, &$value, &$sort_order, &$dependant, &$exclusive)
343  {
344  // if a bodycopy is linking to us then we need to make it a dependant link
345  if ($side_of_link == 'major' && ($asset instanceof Bodycopy) && $dependant != '1') {
346  $dependant = '1';
347  return TRUE;
348  }
349 
350  return FALSE;
351 
352  }//end prepareLink()
353 
354 
363  function isDeletableLink($linkid)
364  {
365  $folder_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'folder', TRUE, 'type_format');
366  if (!empty($folder_link)) {
367  if ($folder_link['linkid'] == $linkid && !$GLOBALS['SQ_PURGING_TRASH']) {
368  return translate('cms_listing_cannot_delete_type_formats_link', str_replace('_',' ', $this->type()));
369  }
370  }
371 
372  $fluster_folder_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'folder', TRUE, 'fluster_format');
373  if (!empty($fluster_folder_link)) {
374  if ($fluster_folder_link['linkid'] == $linkid && !$GLOBALS['SQ_PURGING_TRASH']) {
375  return translate('funnelback_cannot_delete_fluster_format_link', str_replace('_',' ', $this->type()));
376  }
377  }
378 
379  $spelling_folder_link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->id, SQ_LINK_TYPE_2, 'folder', TRUE, 'spell_format');
380  if (!empty($spelling_folder_link)) {
381  if ($spelling_folder_link['linkid'] == $linkid && !$GLOBALS['SQ_PURGING_TRASH']) {
382  return translate('funnelback_cannot_delete_spelling_format_link', str_replace('_',' ', $this->type()));
383  }
384  }
385 
386  // the only reason why we would object to this link being
387  // deleted is if it is the bodycopy linked to us
388  $bodycopy_link = $GLOBALS['SQ_SYSTEM']->am->getLinkById($linkid);
389  if ($bodycopy_link['minor_type_code'] == 'bodycopy' && array_key_exists($bodycopy_link['value'], $this->bodycopies) && !$GLOBALS['SQ_PURGING_TRASH']) {
390  return translate('funnelback_cannot_delete_bodycopy_link', str_replace('_', ' ', ucwords($bodycopy_link['value'])), str_replace('_',' ', ucwords($this->type())));
391  }
392 
393  return parent::isDeletableLink($linkid);
394 
395  }//end isDeletableLink()
396 
397 
405  function _getAllowedLinks()
406  {
407  $page_links = parent::_getAllowedLinks();
408  $page_links[SQ_LINK_TYPE_2]['bodycopy'] = Array('card' => 'M', 'exclusive' => TRUE);
409  $page_links[SQ_LINK_TYPE_2]['folder'] = Array('card' => 4, 'exclusive' => FALSE);
410  $page_links[SQ_LINK_TYPE_3]['folder'] = Array('card' => 1, 'exclusive' => FALSE);
411  $page_links[SQ_LINK_NOTICE]['asset'] = Array('card' => 'M', 'exclusive' => FALSE);
412  return $page_links;
413 
414  }//end _getAllowedLinks()
415 
416 
423  function getSearchURL()
424  {
425  $url = $this->attr('submit_to_page_url') ? $this->getURL() : current_url();
426  return $url;
427 
428  }//end getSearchURL()
429 
430 
437  function printFrontend()
438  {
439  $click = array_get_index($_GET, 'click', 0);
440  $query = array_get_index($_GET, 'click_query', '');
441  $rank = array_get_index($_GET, 'click_rank', '');
442  $url = array_get_index($_GET, 'click_url', '');
443  $collection = array_get_index($_GET, 'click_collection', '');
444 
445  if ($click == '1' && !empty($query) && !empty($rank) && !empty($url) && !empty($collection)) {
446  // Only for internal searches
447  $fm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('funnelback_manager');
448  $binary = $fm->getFunnelbackPath().'/bin/clix2anx';
449  $coll_path = $fm->getCollectionDataPath($collection);
450  $log_file = $fm->getCollectionDataPath($collection, 'log').'/click.log';
451  $command = $binary.' '.$query.' '.$url.' '.$rank.' '.$log_file;
452  $output = '';
453  $fm->runCommand($command, $output, NULL, NULL, $coll_path);
454  header('Location: '.$url);
455  return;
456  }//end if
457 
458  // No click log, move on....
459  parent::printFrontend();
460 
461  }//end printFrontend()
462 
463 
470  function printContents()
471  {
472  $prefix = $this->getPrefix();
473  if (isset($_REQUEST[$prefix.'_submit_button']) && empty($_REQUEST['mode'])) {
474  $_REQUEST['mode'] = 'results';
475  }//end if
476  $mode = array_get_index($_REQUEST, 'mode', '');
477 
478  $search_vars = Array();
479  $search_vars['query'] = htmlspecialchars(array_get_index($_REQUEST, $prefix.'_search_query', ''), ENT_NOQUOTES, SQ_CONF_DEFAULT_CHARACTER_SET);
480  $search_vars['scope'] = htmlspecialchars(array_get_index($_REQUEST, $prefix.'_search_scope', ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
481  $search_vars['sort'] = htmlspecialchars(array_get_index($_REQUEST, $prefix.'_search_sort', ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
482  $search_vars['page'] = htmlspecialchars(array_get_index($_REQUEST, 'current_result_page', 1), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
483  $search_vars['num_per_page'] = htmlspecialchars(array_get_index($_REQUEST, 'results_per_page', $this->_getNumPerPage()), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
484 
485  // If the flustering links are clicked, we need these extra vars to pass off to funnelback
486  $search_vars['stem'] = htmlspecialchars(array_get_index($_REQUEST, $prefix.'_stem', ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
487  $search_vars['type_max'] = htmlspecialchars(array_get_index($_REQUEST, $prefix.'_type_max_clusters', ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
488  $search_vars['topic_max'] = htmlspecialchars(array_get_index($_REQUEST, $prefix.'_topic_max_clusters', ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
489  $search_vars['site_max'] = htmlspecialchars(array_get_index($_REQUEST, $prefix.'_site_max_clusters', ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
490 
491  $search_vars['cluster'] = Array();
492  foreach ($_GET as $index => $value) {
493  if (strpos($index, $prefix.'_cluster') !== FALSE) {
494  $count = str_replace($prefix.'_cluster', '', $index);
495  $search_vars['cluster'][$count] = $value;
496  }//end if
497  }//end foreach
498 
499  if($this->attr('disable_keyword_replacements') && isset($search_vars['query']) && !empty($search_vars['query'])) {
500  $search_vars['query'] = $this->_sanitizeQueries($search_vars['query']);
501  }
502 
503  // Process any dynamic vars
504  $pmap = $this->getAttribute('dynamic_parameters');
505  $pmap_params = $pmap->getParameters();
506  $jump_to_result = FALSE;
507 
508  if (is_array($pmap_params) && !empty($pmap_params)) {
509  foreach ($pmap_params as $params) {
510  switch ($params) {
511  case 'query':
512  $dynamic_query = $pmap->getParameterValue($params);
513  if (!empty($dynamic_query) && empty($search_vars['query'])) {
514  $search_vars['query'] = $dynamic_query;
515  $jump_to_result = TRUE;
516  }//end if
517  break;
518 
519  case 'results_per_page':
520  $dynamic_results = $pmap->getParameterValue($params);
521  if (!empty($dynamic_results)) {
522  $search_vars['num_per_page'] = $dynamic_results;
523  }//end if
524  break;
525 
526  case 'scope':
527  $dynamic_scope = $pmap->getParameterValue($params);
528  if (!empty($dynamic_scope) && empty($search_vars['scope'])) {
529  $search_vars['scope'] = $dynamic_scope;
530  }//end if
531  break;
532 
533  case 'sort_order':
534  $dynamic_sort = $pmap->getParameterValue($params);
535  if (!empty($dynamic_sort) && empty($search_vars['sort'])) {
536  $search_vars['sort'] = $dynamic_sort;
537  }//end if
538  break;
539 
540  default:
541  // Do nothing
542  break;
543  }//end switch
544  }//end foreach
545  }//end if
546 
547  if (empty($mode)) {
548  $mode = 'initial';
549  }//end if
550 
551  if (empty($search_vars['sort'])) {
552  $search_vars['sort'] = $this->attr('sort_order');
553  }
554 
555  // If Stored Query is to be used, then jump to the results page directly
556  if ($this->attr('stored_query_show_results') && $mode == 'initial' && $jump_to_result) {
557  $mode = 'results';
558  }//end if
559 
560 
561  switch ($mode) {
562  case 'results':
563  echo $this->_getSearchPageJavascript();
564  $this->printResultsBody($search_vars);
565  break;
566 
567  case 'initial':
568  default:
569  echo $this->getBodycopyContents('initial', $this->getInitialBodyReplacements($search_vars));
570  break;
571  }
572 
573  }//end printContents()
574 
575 
584  function printResultsBody($search=Array())
585  {
586  $search_results = $this->processSearch($search);
587  $search_results['params'] = $search;
588  $results = array_get_index($search_results, 'results', Array());
589 
590  $this->_tmp['search_results'] =& $results;
591  $bc_name = 'results';
592  if (empty($results)) $bc_name = 'no_results';
593 
594  echo $this->getBodycopyContents($bc_name, $this->getResultsBodyReplacements($search_results, $bc_name));
595 
596  }//end printResultsBody()
597 
598 
599 // --- SEARCH FUNCTIONS --- //
600 
601 
610  public function processSearch($search)
611  {
612  // Defaults
613  $search_summary = Array('summary' => Array(), 'fluster' => Array(), 'spell' => Array());
614  $search_results = Array('results' => Array(), 'summary' => $search_summary);
615 
616  // Type of search
617  $type = $this->attr('search_type');
618  switch ($type) {
619  case 'squiz':
620  // SquizSearch Query through SquizSuite.
621  $xml_results = $this->_querySquizSearch($search);
622  if (empty($xml_results)) {
623  // Something went wrong
624  trigger_localised_error('FNB0002', E_USER_WARNING);
625  return $search_results;
626  }//end if
627  break;
628 
629  case 'hosted':
630  case 'web':
631  // Web Search ie. Using a funnelback search engine
632  $url = $this->parseURL($search);
633  if (empty($url)) {
634  // The error has triggered inside this function
635  return $search_results;
636  }//end if
637 
638  $xml_results = $this->_queryFunnelback($url);
639  if (empty($xml_results)) {
640  // Something went wrong
641  trigger_localised_error('FNB0002', E_USER_WARNING);
642  return $search_results;
643  }//end if
644  break;
645 
646  default:
647  // Integrated Search ie. OEM Funnelback is installed
648  $xml_results = $this->_searchFunnelback($search);
649 
650  if ($xml_results === FALSE) {
651  // An error occurred in the search
652  trigger_localised_error('FNB0003', E_USER_WARNING);
653  return $search_results;
654  } else if (empty($xml_results)) {
655  // Empty Searches are not permitted
656  return $search_results;
657  }//end if
658  break;
659  }//end switch
660 
661  // Just in case, XML returned can be malformed
662  $old_error_handler = set_error_handler('funnelback_xml_error_handler');
663 
664  try {
665  $xml_results = utf8_encode($xml_results);
666  $dom = new DOMDocument('1.0', 'UTF-8');
667  $dom->loadXML($xml_results);
668  } catch (ErrorException $e) {
669  restore_error_handler();
670  trigger_localised_error('FNB0002', E_USER_WARNING);
671  return $search_results;
672  }
673 
674  restore_error_handler();
675 
676  $errorNode = $dom->getElementsByTagName('error')->item(0);
677  if (isset($errorNode)) {
678  $errorMessage = $dom->getElementsByTagName('usermsg')->item(0);
679  $errorMsg = (isset($errorMessage)) ? $errorMessage->nodeValue : '';
680  trigger_localised_error('FNB0002', E_USER_WARNING);
681  } else {
682  // No errors so continue processing
683  // Process the search results
684  $search_results['results'] = $this->processSearchResults($dom);
685 
686  // Process the search summary
687  $search_results['summary'] = $this->processSearchSummary($dom);
688  }//end if
689 
690  return $search_results;
691 
692  }//end processSearch()
693 
694 
695 // --- KEYWORD FUNCTIONS --- //
696 
697 
708  function onRequestKeywords(&$broadcaster, $vars=Array())
709  {
710  $vars['keywords'] = isset($vars['keywords']) ? $vars['keywords'] : Array();
711 
712  $parents = $GLOBALS['SQ_SYSTEM']->am->getParents($broadcaster->id, 'bodycopy', TRUE);
713  $bodycopy_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'bodycopy');
714 
715  $bodycopies = Array();
716  $type_formats = Array();
717  $keywords = Array();
718 
719  foreach ($bodycopy_links as $link_info) {
720  if (isset($parents[$link_info['minorid']])) {
721  $bodycopies[] = $link_info['value'];
722  }
723  }
724 
725  // ATTENTION!
726  // this check relies on the fact that ALL single asset formats like type, default or position
727  // are located in subfolders of this asset, and only its context bodycopies are its direct children
728  if (empty($bodycopies)) {
729  // So try and guess the correct bodycopy!
730  $bc_parents = $GLOBALS['SQ_SYSTEM']->am->getParents($broadcaster->id, 'folder', TRUE);
731  $folder_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2, 'folder');
732 
733  foreach ($folder_links as $link_info) {
734  if (isset($bc_parents[$link_info['minorid']])) {
735  $bc_folder = $GLOBALS['SQ_SYSTEM']->am->getLinks($link_info['minorid'], SQ_LINK_TYPE_2, 'bodycopy');
736  foreach ($bc_folder as $bc_link_info) {
737  if (isset($parents[$bc_link_info['minorid']])) {
738  $bodycopies[] = $bc_link_info['value'];
739  }//end if
740  }//end foreach
741  }//end if
742  }//end foreach
743 
744  if (empty($bodycopies)) {
745  parent::onRequestKeywords($broadcaster, $vars);
746  return;
747  }//end if
748  }
749 
750  foreach ($bodycopies as $bodycopy) {
751  if (!isset($this->keywords[$bodycopy])) {
752  // If bodycopy not found, just assume the default type format
753  $bodycopy = 'default_format';
754  }//end if
755  foreach ($this->keywords[$bodycopy] as $keyword) {
756  $keywords[$keyword] = ucwords(str_replace('_', ' ', $keyword));
757  }//end foreach
758  }//end foreach
759 
760  $vars['keywords'] = array_merge($vars['keywords'], $keywords);
761 
762  }//end onRequestKeywords()
763 
764 
773  function getInitialBodyReplacements($extra=Array())
774  {
775  $bodycopy =& $this->getBodycopy('initial');
776 
777  $keywords = $bodycopy->getKeywords();
778  $replaces = Array();
779 
780  foreach ($keywords as $keyword) {
781  $replaces[$keyword] = $this->getGeneralReplacement($keyword, $extra);
782  }//end foreach
783 
784  return $replaces;
785 
786  }//end getInitialBodyReplacements()
787 
788 
798  function getResultsBodyReplacements($search_results, $bc_name='results')
799  {
800  $results = array_get_index($search_results, 'results', Array());
801 
802  $mode = htmlspecialchars(array_get_index($_REQUEST, 'mode', 'results'), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
803  $bodycopy =& $this->getBodycopy($bc_name);
804  $keywords = $bodycopy->getKeywords();
805 
806  $replaces = Array();
807  $this->_tmp['initial_results'] = $results;
808 
809  foreach ($keywords as $keyword) {
810  $replacement = $this->getFunnelbackReplacement($keyword, $search_results);
811  $replaces[$keyword] = $replacement;
812  }//end foreach
813 
814  return $replaces;
815 
816  }//end getResultsBodyReplacements()
817 
818 
830  function getFunnelbackReplacement($keyword, $search_results=Array(), $index=NULL, $type='site')
831  {
832  $default_fluster = Array('category' => Array('type' => Array(), 'topic' => Array(), 'site' => Array()));
833  $default_summary = Array('summary' => Array(), 'fluster' => $default_fluster, 'spell' => Array(), 'featured' => Array());
834  $results = array_get_index($search_results, 'results', Array());
835  $summary = array_get_index($search_results, 'summary', $default_summary);
836  $params = array_get_index($search_results, 'params', Array());
837 
838  $prefix = $this->getPrefix();
839  $mode = htmlspecialchars(array_get_index($_REQUEST, 'mode', 'results'), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
840 
841  // Sort out the query vars
842  $queries = '';
843  foreach ($_GET as $query_name => $query_value) {
844  // skip some get vars that will be added later by the keyword replacements
845  if (!in_array($query_name, Array('mode', 'current_result_page', 'results_per_page'))) {
846  if (is_array($query_value)) {
847  foreach ($query_value as $value_index => $value_contents) {
848  $queries .= '&'.urlencode($query_name).'['.urlencode($value_index).']='.urlencode($value_contents);
849  }
850  } else {
851  $queries .= '&'.urlencode($query_name).'='.urlencode($query_value);
852  }//end if
853  }//end if
854  }//end foreach
855 
856 
857  // Here is where we define the common values used across the page
858  $num_per_page = array_get_index($summary['summary'], 'num_ranks', 10);
859  $start_record = array_get_index($summary['summary'], 'currstart', 1);
860  $last_record = array_get_index($summary['summary'], 'currend', 1);
861  $total_result = array_get_index($summary['summary'], 'total_matching', 0);
862  $total_pages_main = floor($total_result / $num_per_page);
863  $total_pages = $total_pages_main + (($total_result % $num_per_page == 0) ? 0 : 1);
864  $fully_result = array_get_index($summary['summary'], 'fully_matching', 0);
865  $partial_result = array_get_index($summary['summary'], 'partially_matching', 0);
866  $current_result_page = floor($last_record / $num_per_page);
867  $current_result_page = (($last_record % $num_per_page) != 0) ? $current_result_page+1 : $current_result_page;
868  $category = array_get_index($summary['fluster'], 'category', Array('type' => Array(), 'topic' => Array(), 'site' => Array()));
869  $category_type = array_get_index($category, $type, Array());
870  $keyword = parse_keyword($keyword, $modifiers);
871 
872  $replacement = '%'.$keyword.'%';
873  if (strpos($keyword, 'page_list') === 0) {
874  // Page list keyword
875  $show_pages = substr($keyword, 9);
876  $show_pages = ltrim($show_pages, '_');
877  if (empty($show_pages) || $show_pages > $total_pages) {
878  $show_pages = $total_pages;
879  }//end if
880  $replacement = $this->_paintSlidingPageNavigation($mode, $current_result_page, $total_pages, $show_pages, $num_per_page, $queries);
881  } else if (strpos($keyword, 'result_meta') === 0) {
882  // Metadata keywords
883  $metadata_class = substr($keyword, 12, 1);
884  $replacement = '';
885  if ($metadata_class !== 'S') {
886  $metadata_field = 'meta_'.$metadata_class;
887  $replacement = array_get_index(array_get_index($results, $index, Array()), $metadata_field, '');
888  }
889  } else {
890  // Everything else
891  switch ($keyword) {
892  case 'result_list':
893  // print the results
894  ob_start();
895  $this->_printResultList($search_results);
896  $replacement = ob_get_contents();
897  ob_end_clean();
898  break;
899 
900  case 'fluster_category_type':
901  // print the type category
902  $fluster_category_type = array_get_index($category, 'type', Array());
903  if (!empty($summary['fluster']) && !empty($fluster_category_type)) {
904  ob_start();
905  $this->printFlusterList($search_results, 'type');
906  $replacement = ob_get_contents();
907  ob_end_clean();
908  }//end if
909  break;
910 
911  case 'fluster_category_topic':
912  // print the topic category
913  $fluster_category_type = array_get_index($category, 'topic', Array());
914  if (!empty($summary['fluster']) && !empty($fluster_category_type)) {
915  ob_start();
916  $this->printFlusterList($search_results, 'topic');
917  $replacement = ob_get_contents();
918  ob_end_clean();
919  }//end if
920  break;
921 
922  case 'fluster_category_site':
923  // print the site category
924  $fluster_category_type = array_get_index($category, 'site', Array());
925  if (!empty($summary['fluster']) && !empty($fluster_category_type)) {
926  ob_start();
927  $this->printFlusterList($search_results, 'site');
928  $replacement = ob_get_contents();
929  ob_end_clean();
930  }//end if
931  break;
932 
933  case 'fluster_current_term':
934  $replacement = '';
935  $navigation = array_get_index($summary['fluster'], 'navigation', Array());
936  if (!empty($navigation)) {
937  $last_record = array_pop($navigation);
938  $replacement = array_get_index($last_record, 'name', '');
939  }//end if
940  break;
941 
942  case 'fluster_navigation':
943  $navigation = array_get_index($summary['fluster'], 'navigation', Array());
944  ob_start();
945  echo '<div id="fluster_navigation">';
946  foreach ($navigation as $index => $nav) {
947  $this->printNavigationList($search_results, $index);
948  }//end foreach
949  echo '</div>';
950  $replacement = ob_get_contents();
951  ob_end_clean();
952  break;
953 
954  case 'result_featured':
955  // print the asset list from the listing engine
956  if (!empty($summary['featured'])) {
957  ob_start();
958  $featured = array_get_index($summary, 'featured', Array());
959  if (!empty($featured)) {
960  foreach ($featured as $index => $feature) {
961  $this->printFeaturedList($search_results, $index);
962  $replacement = ob_get_contents();
963  }//end foreach
964  }//end if
965  ob_end_clean();
966  }//end if
967  break;
968 
969  case 'current_result_page':
970  $replacement = $current_result_page;
971  break;
972 
973  case 'current_result_page_start':
974  $replacement = $start_record;
975  break;
976 
977  case 'current_result_page_end':
978  $replacement = $last_record;
979  break;
980 
981  case 'result_count':
982  $replacement = $total_result;
983  break;
984 
985  case 'result_count_fully':
986  $replacement = $fully_result;
987  break;
988 
989  case 'result_count_partially':
990  $replacement = $partial_result;
991  break;
992 
993  case 'result_count_pages':
994  $replacement = $total_pages;
995  break;
996 
997  case 'result_per_page':
998  $replacement = $num_per_page;
999  break;
1000 
1001  case 'result_page_index':
1002  $replacement = $this->_paintSlidingPageNavigation($mode, $current_result_page, $total_pages, $total_pages, $num_per_page, $queries);
1003  break;
1004 
1005  case 'previous_result_page_link':
1006  if ($current_result_page <= 1) {
1007  $replacement = htmlspecialchars($this->attr('prev_page_text'), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1008  } else {
1009  $replacement = '<a href="'.$this->getSearchURL().'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page - 1).'&results_per_page='.$num_per_page.$queries).'">'.htmlspecialchars($this->attr('prev_page_text'), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET).'</a>';
1010  }//end if
1011  break;
1012 
1013  case 'next_result_page_link':
1014  if ($current_result_page >= $total_pages) {
1015  $replacement = htmlspecialchars($this->attr('next_page_text'), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1016  } else {
1017  $replacement = '<a href="'.$this->getSearchURL().'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page + 1).'&results_per_page='.$num_per_page.$queries).'">'.htmlspecialchars($this->attr('next_page_text'), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET).'</a>';
1018  }//end if
1019  break;
1020 
1021  case 'previous_result_page_href':
1022  if ($current_result_page <= 1) {
1023  $replacement = '';
1024  } else {
1025  $replacement = $this->getSearchURL().'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page - 1).'&results_per_page='.$num_per_page.$queries);
1026  }//end if
1027  break;
1028 
1029  case 'next_result_page_href':
1030  if ($current_result_page >= $total_pages - 1) {
1031  $replacement = '';
1032  } else {
1033  $replacement = $this->getSearchURL().'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.($current_result_page + 1).'&results_per_page='.$num_per_page.$queries);
1034  }//end if
1035  break;
1036 
1037  case 'initial_layout':
1038  $replacement = $this->getBodycopyContents('initial', $this->getInitialBodyReplacements());
1039  break;
1040 
1041  case 'result_rank':
1042  $replacement = array_get_index(array_get_index($results, $index, Array()), 'rank', '');
1043  break;
1044 
1045  case 'result_score':
1046  $replacement = array_get_index(array_get_index($results, $index, Array()), 'score', '');
1047  break;
1048 
1049  case 'result_title':
1050  $replacement = array_get_index(array_get_index($results, $index, Array()), 'title', '');
1051  break;
1052 
1053  case 'result_summary':
1054  $replacement = array_get_index(array_get_index($results, $index, Array()), 'summary', '');
1055  break;
1056 
1057  case 'result_url':
1058  $replacement = array_get_index(array_get_index($results, $index, Array()), 'live_url', '');
1059  break;
1060 
1061  case 'result_date':
1062  $replacement = array_get_index(array_get_index($results, $index, Array()), 'date', '');
1063  break;
1064 
1065  case 'result_url_click_event':
1066  $replacement = '';
1067  $field_name = $prefix.'_search_query';
1068  $query = htmlspecialchars(array_get_index($_REQUEST, $field_name, ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1069  $rank = array_get_index(array_get_index($results, $index, Array()), 'rank', '');
1070  $url = array_get_index(array_get_index($results, $index, Array()), 'live_url', '');
1071  if (!empty($url)) {
1072  $replacement = $this->_getClickLoggingJavascript($query, $rank, $url);
1073  }//end if
1074  break;
1075 
1076  case 'result_url_click_js':
1077  $replacement = '';
1078  $field_name = $prefix.'_search_query';
1079  $query = htmlspecialchars(array_get_index($_REQUEST, $field_name, ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1080  $rank = array_get_index(array_get_index($results, $index, Array()), 'rank', '');
1081  $url = array_get_index(array_get_index($results, $index, Array()), 'live_url', '');
1082  if (!empty($url)) {
1083  $replacement = $this->_getClickLoggingJavascript($query, $rank, $url, FALSE);
1084  }//end if
1085  break;
1086 
1087  case 'result_name_linked':
1088  $replacement = '';
1089  $field_name = $prefix.'_search_query';
1090  $query = htmlspecialchars(array_get_index($_REQUEST, $field_name, ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1091  $rank = array_get_index(array_get_index($results, $index, Array()), 'rank', '');
1092  $title = array_get_index(array_get_index($results, $index, Array()), 'title', '');
1093  $url = array_get_index(array_get_index($results, $index, Array()), 'live_url', '');
1094  if (!empty($title) && !empty($url)) {
1095  $js = $this->_getClickLoggingJavascript($query, $rank, $url);
1096  $replacement = '<a href="'.$url.'" '.$js.'>'.$title.'</a>';
1097  }//end if
1098  break;
1099 
1100  case 'result_cache_url':
1101  $search_type = $this->attr('search_type');
1102  $replacement = '';
1103  if ($search_type == 'web') {
1104  // Cache URL only works on 'web' mode
1105  $replacement = array_get_index(array_get_index($results, $index, Array()), 'cache_url', '');
1106  }//end if
1107  break;
1108 
1109  case 'result_size':
1110  $replacement = easy_filesize(array_get_index(array_get_index($results, $index, Array()), 'filesize', ''));
1111  break;
1112 
1113  case 'result_type':
1114  $replacement = array_get_index(array_get_index($results, $index, Array()), 'filetype', '');
1115  break;
1116 
1117  case 'featured_trigger':
1118  $current_feature = array_get_index($summary['featured'], $index, Array());
1119  $replacement = array_get_index($current_feature, 'fp_trigger', '');
1120  break;
1121 
1122  case 'featured_url':
1123  $current_feature = array_get_index($summary['featured'], $index, Array());
1124  $replacement = array_get_index($current_feature, 'fp_link', '');
1125  break;
1126 
1127  case 'featured_title':
1128  $current_feature = array_get_index($summary['featured'], $index, Array());
1129  $replacement = array_get_index($current_feature, 'fp_title', '');
1130  break;
1131 
1132  case 'featured_summary':
1133  $current_feature = array_get_index($summary['featured'], $index, Array());
1134  $replacement = array_get_index($current_feature, 'fp_desc', '');
1135  break;
1136 
1137  case 'fluster_category_name':
1138  $replacement = ucwords($type);
1139  break;
1140 
1141  case 'fluster_current_term':
1142  $navigation = array_get_index($summary['fluster'], 'navigation', Array());
1143  $replacement = '';
1144  if (!empty($navigation)) {
1145  $last_record = array_pop($navigation);
1146  $replacement = array_get_index($last_record, 'name', '');
1147  }//end if
1148  break;
1149 
1150  case 'fluster_navigation':
1151  $navigation = array_get_index($summary['fluster'], 'navigation', Array());
1152  ob_start();
1153  echo '<div id="fluster_navigation">';
1154  foreach ($navigation as $index => $nav) {
1155  $this->printNavigationList($search_results, $index);
1156  }//end foreach
1157  echo '</div>';
1158  $replacement = ob_get_contents();
1159  ob_end_clean();
1160  break;
1161 
1162  case 'fluster_list':
1163  $replacement = '';
1164  ob_start();
1165  if (!empty($category[$type])) {
1166  echo '<div id="fluster_category">';
1167 
1168  // Print the list
1169  foreach ($category[$type] as $index => $cluster) {
1170  if ((string)$index != 'more') {
1171  $this->printClusterList($search_results, $index, $type);
1172  }//end if
1173  }//end foreach
1174 
1175  // Show the more link if set
1176  if ($this->attr('show_fluster_more')) {
1177  if (isset($category[$type]['more']) && $category[$type]['more']) {
1178  // Variables
1179  $query_cluster = $type.'_max_clusters';
1180  $max_attr = 'more_'.$type.'_num';
1181  $max_clusters = $this->attr($max_attr);
1182  $min_attr = 'less_'.$type.'_num';
1183  $min_clusters = $this->attr($min_attr);
1184  $cluster_query = $this->getPrefix().'_'.$query_cluster.'='.$max_clusters;
1185  $cluster_name = $this->attr('more_'.$type.'_text');
1186  $queries = '';
1187 
1188  // Sort out the current query vars
1189  foreach ($_GET as $query_name => $query_value) {
1190  if ($query_name == 'current_result_page') continue;
1191  if (is_array($query_value)) {
1192  foreach ($query_value as $value_index => $value_contents) {
1193  $queries .= '&'.$query_name.'['.$value_index.']='.$value_contents;
1194  }//end foreach
1195  } else {
1196  $current_query = $query_name.'='.$query_value;
1197  $queries .= '&'.$current_query;
1198  // Already using the 'show more link', flip to 'show less'
1199  if (strpos($current_query, $cluster_query) === 0) {
1200  $cluster_query = $this->getPrefix().'_'.$query_cluster.'='.$min_clusters;
1201  $cluster_name = $this->attr('less_'.$type.'_text');
1202  }//end if
1203  }//end if
1204  }//end foreach
1205 
1206  // Build the url to use
1207  if (strpos($queries, '&') === 0) {
1208  $queries = substr($queries, 1);
1209  }//end if
1210  $url = $this->getSearchUrl().'?'.htmlspecialchars($queries.'&'.$cluster_query, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1211 
1212  // Here we are to print the more... flag
1213  echo '<a href="'.$url.'">'.htmlspecialchars($cluster_name, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET).'</a>';
1214  } else {
1215  // If the show more is has been set (max cluster) show less
1216  $queries = '';
1217  $show_link = FALSE;
1218  $query_cluster = $type.'_max_clusters';
1219  $max_attr = 'more_'.$type.'_num';
1220  $max_clusters = $this->attr($max_attr);
1221  $cluster_query = $this->getPrefix().'_'.$query_cluster.'='.$max_clusters;
1222  $cluster_name = $this->attr('less_'.$type.'_text');
1223  foreach ($_GET as $query_name => $query_value) {
1224  if ($query_name == 'current_result_page') continue;
1225  if (is_array($query_value)) {
1226  foreach ($query_value as $value_index => $value_contents) {
1227  $queries .= '&'.$query_name.'['.$value_index.']='.$value_contents;
1228  }//end foreach
1229  } else {
1230  $current_query = $query_name.'='.$query_value;
1231  if ($current_query != $cluster_query) {
1232  $queries .= '&'.$current_query;
1233  } else {
1234  $show_link = TRUE;
1235  }//end if
1236  }//end if
1237  }//end foreach
1238 
1239  // Build the url to use
1240  if (strpos($queries, '&') === 0) {
1241  $queries = substr($queries, 1);
1242  }//end if
1243  $url = $this->getSearchUrl().'?'.htmlspecialchars($queries, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1244 
1245  // Here we are to print the more... flag
1246  if ($show_link) {
1247  echo '<a href="'.$url.'">'.htmlspecialchars($cluster_name, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET).'</a>';
1248  }//end if
1249  }//end if
1250  }//end if
1251  echo '</div>';
1252  }//end if
1253  $replacement = ob_get_contents();
1254  ob_end_clean();
1255  break;
1256 
1257  case 'cluster_name':
1258  $replacement = array_get_index(array_get_index($category_type, $index, Array()), 'name', '');
1259  break;
1260 
1261  case 'cluster_url':
1262  $replacement = '';
1263  $cluster_url = '';
1264  $url = array_get_index(array_get_index($category_type, $index, Array()), 'href', '');
1265  $query = array_get_index(array_get_index($category_type, $index, Array()), 'query', '');
1266  if (!empty($url)) {
1267  $parts = $this->_getQueryVars($url);
1268  $queries = Array();
1269  $query_found = FALSE;
1270  foreach ($parts as $switch => $param) {
1271  if (strpos($switch, 'query') === 0) {
1272  $queries[$this->getPrefix().'_search_query'] = $param;
1273  $query_found = TRUE;
1274  } else {
1275  $queries[$this->getPrefix().'_'.$switch] = $param;
1276  }//end if
1277  }//end foreach
1278 
1279  // Only add in the extra when a query is found
1280  if ($query_found) {
1281  $queries[$this->getPrefix().'_submit_button'] = $this->attr('submit_button_text');
1282  $queries['mode'] = 'results';
1283  }//end if
1284 
1285  // Build the URL
1286  if (!empty($queries)) {
1287  $get_vars = '';
1288  foreach ($queries as $switch => $param) {
1289  $get_vars .= '&'.$switch.'='.$param;
1290  }//end foreach
1291 
1292  $get_vars = substr($get_vars, 1);
1293  $get_vars = htmlspecialchars($get_vars, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1294  $cluster_url = $this->getSearchURL().'?'.$get_vars;
1295  }//end if
1296  } else if (!empty($query)) {
1297  $queries = Array();
1298  $query_found = FALSE;
1299  $url = array_get_index($_SERVER, 'QUERY_STRING', '');
1300  $parts = $this->_getQueryVars($url);
1301  foreach ($parts as $switch => $param) {
1302  if ($switch == $this->getPrefix().'_search_query') {
1303  $queries[$this->getPrefix().'_search_query'] = $query;
1304  $query_found = TRUE;
1305  } else {
1306  $queries[$switch] = $param;
1307  }//end if
1308  }//end foreach
1309 
1310  // Only add in the extra when a query is found
1311  if ($query_found) {
1312  $queries[$this->getPrefix().'_submit_button'] = $this->attr('submit_button_text');
1313  $queries['mode'] = 'results';
1314  }//end if
1315 
1316  // Build the URL
1317  if (!empty($queries)) {
1318  $get_vars = '';
1319  foreach ($queries as $switch => $param) {
1320  if ($switch == 'current_result_page') continue;
1321  $get_vars .= '&'.$switch.'='.$param;
1322  }//end foreach
1323 
1324  $get_vars = substr($get_vars, 1);
1325  $get_vars = htmlspecialchars($get_vars, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1326  $cluster_url = $this->getSearchURL().'?'.$get_vars;
1327  }//end if
1328  }//end if
1329  $replacement = $cluster_url;
1330  break;
1331 
1332  case 'cluster_count':
1333  $replacement = array_get_index(array_get_index($category_type, $index, Array()), 'count', '');
1334  break;
1335 
1336  case 'navigation_name':
1337  $navigation = array_get_index($summary['fluster'], 'navigation', Array());
1338  $current_element = array_get_index($navigation, $index, Array());
1339  $replacement = array_get_index($current_element, 'name', '');
1340  break;
1341 
1342  case 'navigation_url':
1343  $replacement = '';
1344  $navigation = array_get_index($summary['fluster'], 'navigation', Array());
1345 
1346  $current_element = array_get_index($navigation, $index, Array());
1347  // Process the URL to Matrix format
1348  $url = array_get_index($current_element, 'url', '');
1349  if (!empty($url) && (strpos($url, '&') !== FALSE)) {
1350  $query_vars = $this->_getQueryVars($url);
1351  $query_term = array_get_index($query_vars, 'query_prox', '');
1352  if (!empty($query_term)) {
1353  $replacement = $this->getSearchURL();
1354  $replacement .= '?'.$this->getPrefix().'_search_query='.$query_term;
1355  $replacement .= '&'.$this->getPrefix().'_submit_button='.$this->attr('submit_button_text');
1356  $replacement .= '&mode=results';
1357  }//end if
1358  }//end if
1359  break;
1360 
1361  default:
1362  $replacement = $this->getGeneralReplacement($keyword, $params, $summary['spell']);
1363  break;
1364  }//end switch
1365  }//end if
1366 
1367  apply_keyword_modifiers($replacement, $modifiers, Array('assetid' => $this->id));
1368 
1369  return $replacement;
1370 
1371  }//end getFunnelbackReplacement()
1372 
1373 
1384  public function getGeneralReplacement($keyword, $extra, $spelling=Array())
1385  {
1386  $prefix = $this->getPrefix();
1387  $replacement = '';
1388  if (strpos($keyword, 'metadata_scope') === 0) {
1389  $class = str_replace('metadata_scope_', '', $keyword);
1390  $fm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('funnelback_manager');
1391  $all_class = $fm->getMetadataAliases();
1392  if (array_key_exists($class, $all_class)) {
1393  // Print the interface if a valid class
1394  $current_class = '';
1395  $all_current_class = array_get_index($_GET, $prefix.'_metadata_scope', Array());
1396  if (isset($all_current_class[$class])) $current_class = $all_current_class[$class];
1397  ob_start();
1398  text_box($prefix.'_metadata_scope['.$class.']', $current_class);
1399  $replacement = ob_get_contents();
1400  ob_end_clean();
1401  }//end if
1402  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($fm, TRUE);
1403  } else if (strpos($keyword, 'metadata_logic') === 0) {
1404  $class = str_replace('metadata_logic_', '', $keyword);
1405  $fm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('funnelback_manager');
1406  $all_metadata_config = array_get_index($fm->attr('metamap'), $this->attr('collection'), Array());
1407  $metadata_config = Array();
1408  foreach($all_metadata_config as $config) {
1409  if (isset($config['alias']) && $config['alias'] == $class) {
1410  $metadata_config = $config;
1411  break;
1412  }
1413  }
1414  $all_class = $fm->getMetadataAliases();
1415  if (array_key_exists($class, $all_class)) {
1416  // Print the interface if a valid class
1417  $current_logic = array_get_index($metadata_config, 'word_logic', 2);
1418  $all_current_logic = array_get_index($_GET, $prefix.'_metadata_logic', Array());
1419  if (isset($all_current_logic[$class])) $current_logic = $all_current_logic[$class];
1420  $logic_options = Array('Exclude', 'Include any', 'Include all');
1421  ob_start();
1422  combo_box($prefix.'_metadata_logic['.$class.']', $logic_options, FALSE, $current_logic);
1423  $replacement = ob_get_contents();
1424  ob_end_clean();
1425  }//end if
1426  $GLOBALS['SQ_SYSTEM']->am->forgetAsset($fm, TRUE);
1427  } else {
1428  switch ($keyword) {
1429 
1430  case 'current_query_term':
1431  $field_name = $prefix.'_search_query';
1432  $current_value = htmlspecialchars(array_get_index($_REQUEST, $field_name, ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1433 
1434  $replacement = $current_value;
1435  break;
1436 
1437  case 'search_query':
1438  $field_name = $prefix.'_search_query';
1439  $current_value = htmlspecialchars(array_get_index($_REQUEST, $field_name, ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1440  $dynamic_query = array_get_index($extra, 'query', '');
1441  if (!empty($dynamic_query) && empty($current_value)) {
1442  $current_value = $dynamic_query;
1443  }//end if
1444 
1445  if($this->attr('disable_keyword_replacements') && !empty($current_value)) {
1446  $current_value = $this->_sanitizeQueries($current_value);
1447  }
1448 
1449  $this->registerFormField($field_name);
1450  $replacement = '<input type="text" name="'.$field_name.'" id="'.$field_name.'" value="'.$current_value.'" />';
1451  break;
1452 
1453  case 'search_logic':
1454  $current_sort_logic = array_get_index($_GET, $prefix.'_search_logic', $this->attr('word_logic'));
1455  $logic_options = Array('Exclude' ,'Include any', 'Include all');
1456  ob_start();
1457  combo_box($this->getPrefix().'_search_logic', $logic_options, FALSE, $current_sort_logic);
1458  $replacement = ob_get_contents();
1459  ob_end_clean();
1460  break;
1461 
1462  case 'search_scope':
1463  $field_name = $prefix.'_search_scope';
1464  $scope = $this->attr('scope');
1465  $current_value = htmlspecialchars(array_get_index($_REQUEST, $field_name, ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1466  $dynamic_scope = array_get_index($extra, 'scope', '');
1467  if (!empty($dynamic_scope) && empty($current_value)) {
1468  $current_value = $dynamic_scope;
1469  }//end if
1470  if (empty($current_value)) {
1471  $current_value = $this->attr('default_scope');
1472  }//end if
1473  $this->registerFormField($field_name);
1474 
1475  ob_start();
1476  foreach ($scope as $key => $value) {
1477  $checked = FALSE;
1478  if ($key == $current_value) {
1479  $checked = TRUE;
1480  }//end if
1481  radio_button($field_name, $key, $checked);
1482  label($value, $field_name);
1483  }//end foreach
1484  $replacement = ob_get_contents();
1485  ob_end_clean();
1486  break;
1487 
1488  case 'search_sort':
1489  $sort_options = $this->getSortOptions();
1490  $current_sort = $this->attr('sort_order');
1491  if (isset($_REQUEST[$this->getPrefix().'_search_sort'])) {
1492  // There is an override for the current sort
1493  $current_sort = htmlspecialchars($_REQUEST[$this->getPrefix().'_search_sort'], ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1494  }//end if
1495  ob_start();
1496  combo_box($this->getPrefix().'_search_sort', $sort_options, FALSE, $current_sort);
1497  $replacement = ob_get_contents();
1498  ob_end_clean();
1499  $this->registerFormField($this->getPrefix().'_search_sort');
1500  break;
1501 
1502  case 'spell_suggestion':
1503  // print the spelling suggestion
1504  if (!empty($spelling)) {
1505  // Check for same spelling and dont print it
1506  $current_term = htmlspecialchars(array_get_index($_REQUEST, $this->getPrefix().'_search_query', ''), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1507  $spell_term = array_get_index($spelling, 'text', '');
1508  $spell_term = trim($spell_term);
1509  if ($current_term != $spell_term) {
1510  ob_start();
1511  $this->printSpellList($spelling);
1512  $replacement = ob_get_contents();
1513  ob_end_clean();
1514  }//end if
1515  }//end if
1516  break;
1517 
1518  case 'spell_url':
1519  $url = '';
1520  $spell_url = array_get_index($spelling, 'url', '');
1521  // Parse the query
1522  $returned_get_vars = $this->_getQueryVars($spell_url);
1523  $get_vars = '';
1524  foreach ($returned_get_vars as $var_name => $var_value) {
1525  if ($var_name == 'query') {
1526  $var_name = 'search_query';
1527  }//end if
1528  $get_vars .= '&'.$this->getPrefix().'_'.$var_name.'='.$var_value;
1529  }//end foreach
1530 
1531  if (!empty($get_vars)) $url = '?mode=results'.$get_vars;
1532  $replacement = $this->getSearchURL().$url;
1533  break;
1534 
1535  case 'spell_text':
1536  $replacement = array_get_index($spelling, 'text', '');
1537  break;
1538 
1539  case 'search_button':
1540  case 'submit_button':
1541  // If fluster is set, we need to unset them here
1542  foreach ($_GET as $index => $value) {
1543  if ((strpos($index, $prefix.'_cluster') !== FALSE) || $index == $prefix.'_stem') {
1544  $count = str_replace($prefix.'_cluster', '', $index);
1545  hidden_field($index, '');
1546  $this->registerFormField($index);
1547  }//end if
1548  }//end foreach
1549 
1550  // Go on to create the button
1551  $field_name = $prefix.'_submit_button';
1552  $this->registerFormField($field_name);
1553  $this->_tmp['prints_submit'] = TRUE;
1554 
1555  // if we are on the initial search page, don't use javascript
1556  // for the submit button so enter will submit the form
1557  $mode = htmlspecialchars(array_get_index($_REQUEST, 'mode', 'initial'), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1558  if ($mode == 'initial') {
1559  $replacement = '<input type="submit" name="'.$field_name.'"
1560  value="'.$this->attr('submit_button_text').'" />';
1561  } else {
1562  $replacement = '<input type="submit" name="'.$field_name.'" onclick="listing_form = document.getElementById(\''.$this->getPrefix().'\');
1563  if (typeof listing_form.current_result_page != \'undefined\' ) listing_form.current_result_page.value=\'1\';
1564  if (typeof listing_form.mode != \'undefined\') listing_form.mode.value = \'results\';
1565  return true;
1566  " value="'.$this->attr('submit_button_text').'" />';
1567  }
1568  // We add an extra hidden text field here to workaround an IE bug i.e.
1569  // if form has only one text field then submit button is not sent along
1570  // with other input fields in form when enter key is pressed in the text box.
1571  // See bug #4559
1572  $replacement = '<input type="text" name="'.$prefix.'_extra_field" id="'.$prefix.'_extra_field" style="display:none" />'.$replacement;
1573  break;
1574 
1575  case 'results_per_page':
1576 
1577  $field_name = 'results_per_page';
1578  $results_per_page = htmlspecialchars(array_get_index($_REQUEST, $field_name, $this->_getNumPerPage()), ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET);
1579  $this->registerFormField($field_name);
1580  $replacement = '<input type="text" name="'.$field_name.'" onchange="listing_form = document.getElementById(\''.$this->getPrefix().'\');
1581  listing_form.results_per_page.value = this.value;
1582  " value="'.$results_per_page.'" size="5" />';
1583  break;
1584 
1585  default:
1586  $replacement = $this->getKeywordReplacement($keyword);
1587  break;
1588  }//end switch
1589  }//end if
1590 
1591  return $replacement;
1592 
1593  }//end getGeneralReplacement()
1594 
1595 
1602  public function getSortOptions()
1603  {
1604  return Array(
1605  'rank' => translate('funnelback_sort_rank'),
1606  'date' => translate('funnelback_sort_date'),
1607  'title' => translate('funnelback_sort_title'),
1608  'url' => translate('funnelback_sort_url'),
1609  );
1610 
1611  }//end getSortOptions()
1612 
1613 
1627  private function _paintSlidingPageNavigation($mode, $current_result_page, $total_pages, $show_pages, $num_per_page, $queries='')
1628  {
1629  $replacement = '';
1630  if ($total_pages == $show_pages) {
1631  $start_page = 1;
1632  $end_page = $total_pages;
1633  } else {
1634  $start_page = max(1, min(($current_result_page - (int) floor($show_pages / 2)), $total_pages - $show_pages + 1));
1635  $end_page = min($total_pages, $start_page + $show_pages - 1);
1636  }//end if
1637 
1638  for ($i = $start_page; $i <= $end_page; $i++) {
1639  if ($replacement != '') $replacement .= ' ';
1640 
1641  if ($i == $current_result_page) {
1642  $replacement .= '<b>'.$i.'</b>';
1643  } else {
1644  $replacement .= '<a href="'.$this->getSearchURL().'?'.htmlspecialchars('mode='.$mode.'&current_result_page='.$i.'&results_per_page='.$num_per_page.$queries).'">'.$i.'</a>';
1645  }
1646  }//end for
1647 
1648  return $replacement;
1649 
1650  }//end _paintSlidingPageNavigation()
1651 
1652 
1653 // -- BODYCOPY FUNCTIONS -- //
1654 
1655 
1667  public function &getBodycopy($name)
1668  {
1669  $bodycopy = NULL;
1670 
1671  if (array_key_exists($name, $this->bodycopies)) {
1672  $am =& $GLOBALS['SQ_SYSTEM']->am;
1673  $link = $am->getLink($this->id, SQ_LINK_TYPE_2, 'bodycopy', TRUE, $name, 'major', '1');
1674  $bodycopy = $am->getAsset($link['minorid'], $link['minor_type_code']);
1675  }
1676 
1677  return $bodycopy;
1678 
1679  }//end getBodycopy()
1680 
1681 
1693  public function &getBodycopyContents($name, $replacements=Array())
1694  {
1695  $bodycopy =& $this->getBodycopy($name);
1696  if (is_null($bodycopy)) return '';
1697 
1698  $bodycopy->setKeywordReplacements($replacements);
1699 
1700  ob_start();
1701  $bodycopy->printBody();
1702  $html = ob_get_contents();
1703  ob_end_clean();
1704 
1705  return $html;
1706 
1707  }//end getBodycopyContents()
1708 
1709 
1716  public function getFormatFolderLink()
1717  {
1718  $link = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'folder', TRUE, 'major', 'format_folder');
1719  return (!empty($link)) ? $link[0] : Array();
1720 
1721  }//end getFormatFolderLink()
1722 
1723 
1730  public function &getFormatFolder()
1731  {
1732  $folder = NULL;
1733 
1734  $link = $this->getFormatFolderLink();
1735  if (!empty($link)) {
1736  $folder = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], $link['minor_type_code']);
1737  }
1738 
1739  return $folder;
1740 
1741  }//end getFormatFolder()
1742 
1743 
1752  public function getFormatBodycopyLink($link_value)
1753  {
1754  $format_folder =& $this->getFormatFolder();
1755  if (is_null($format_folder)) return Array();
1756 
1757  $link = $GLOBALS['SQ_SYSTEM']->am->getLinks($format_folder->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'bodycopy', TRUE, 'major', $link_value);
1758  return (!empty($link)) ? $link[0] : Array();
1759 
1760  }//end getFormatBodycopyLink()
1761 
1762 
1774  public function &getFormatBodycopy($link_value)
1775  {
1776  $bodycopy = NULL;
1777 
1778  $bodycopy_link = $this->getFormatBodycopyLink($link_value);
1779  if (!empty($bodycopy_link)) {
1780  $bodycopy = $GLOBALS['SQ_SYSTEM']->am->getAsset($bodycopy_link['minorid'], $bodycopy_link['minor_type_code']);
1781  }
1782 
1783  return $bodycopy;
1784 
1785  }//end getFormatBodycopy()
1786 
1787 
1788 // --- RESULT LISTING FUNCTIONS --- //
1789 
1790 
1802  private function _printResultList($search_results)
1803  {
1804  $todo = array_get_index($search_results, 'results', Array());
1805  if (empty($todo)) return;
1806 
1807  foreach ($todo as $index => $result) {
1808  $this->_printResult($search_results, $index);
1809  }//end foreach
1810 
1811  }//end _printResultList()
1812 
1813 
1823  private function _printResult($search_results, $index)
1824  {
1825  $results = array_get_index($search_results, 'results', Array());
1826 
1827  // Setting the Default Type Folder
1828  if (!isset($this->_tmp['type_folder_id'])) {
1829  $type_folder = $this->getFolder('type_format');
1830  $this->_tmp['type_folder_id'] = $type_folder->id;
1831  }//end if
1832 
1833  // Getting the Default Format Bodycopy
1834  if (!isset($this->_tmp['default_format_bc'])) {
1835  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->_tmp['type_folder_id'], SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'default_format');
1836  if ($link) {
1837  $this->_tmp['default_format_bc'] = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], 'bodycopy');
1838  } else {
1839  trigger_localised_error('FNB0004', E_USER_WARNING, 'Default');
1840  return;
1841  }
1842  }
1843  $bodycopy = $this->_tmp['default_format_bc'];
1844 
1845  // Check for a customised layout for this item only
1846  $filetype = array_get_index($results[$index], 'filetype', '');
1847  $custom_type = $GLOBALS['SQ_SYSTEM']->am->getLink($this->_tmp['type_folder_id'], SQ_LINK_TYPE_2, 'bodycopy', TRUE, $filetype);
1848  if (!empty($custom_type)) {
1849  $bodycopy = $GLOBALS['SQ_SYSTEM']->am->getAsset($custom_type['minorid'], 'bodycopy');
1850  }//end if
1851 
1852  // by the time we reach this point we already have a bodycopy for this asset
1853  $bc_keywords = $bodycopy->getKeywords();
1854  $keywords = Array();
1855  foreach ($bc_keywords as $keyword) {
1856  $keywords[$keyword] = $this->getFunnelbackReplacement($keyword, $search_results, $index);
1857  }//end foreach
1858 
1859  $bodycopy->setKeywordReplacements($keywords);
1860  $bodycopy->printBody();
1861 
1862  }//end _printResult()
1863 
1864 
1874  public function printFeaturedList($results, $index)
1875  {
1876  // Setting the Default Type Folder
1877  if (!isset($this->_tmp['type_folder_id'])) {
1878  $type_folder = $this->getFolder('type_format');
1879  $this->_tmp['type_folder_id'] = $type_folder->id;
1880  }//end if
1881 
1882  // Getting the Default Format Bodycopy
1883  if (!isset($this->_tmp['featured_format_bc'])) {
1884  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->_tmp['type_folder_id'], SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'featured_format');
1885  if ($link) {
1886  $this->_tmp['featured_format_bc'] = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], 'bodycopy');
1887  } else {
1888  trigger_localised_error('FNB0004', E_USER_WARNING, 'Featured');
1889  return;
1890  }
1891  }
1892  $bodycopy = $this->_tmp['featured_format_bc'];
1893 
1894  // by the time we reach this point we already have a bodycopy for this asset
1895  $bc_keywords = $bodycopy->getKeywords();
1896  $keywords = Array();
1897  foreach ($bc_keywords as $keyword) {
1898  $keywords[$keyword] = $this->getFunnelbackReplacement($keyword, $results, $index);
1899  }//end foreach
1900 
1901  $bodycopy->setKeywordReplacements($keywords);
1902  $bodycopy->printBody();
1903 
1904  }//end printFeaturedList()
1905 
1906 
1916  public function printFlusterList($results, $type='site')
1917  {
1918  // Getting the Fluster Format folder
1919  if (!isset($this->_tmp['fluster_folder_id'])) {
1920  $fluster_folder = $this->getFolder('fluster_format');
1921  $this->_tmp['fluster_folder_id'] = $fluster_folder->id;
1922  }//end if
1923 
1924  // Getting the Fluster Default Format Bodycopy
1925  if (!isset($this->_tmp['fluster_format_bc'])) {
1926  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->_tmp['fluster_folder_id'], SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'context_format');
1927  if ($link) {
1928  $this->_tmp['fluster_format_bc'] = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], 'bodycopy');
1929  } else {
1930  trigger_localised_error('FNB0004', E_USER_WARNING, 'Context');
1931  return;
1932  }
1933  }
1934  $bodycopy = $this->_tmp['fluster_format_bc'];
1935 
1936  // by the time we reach this point we already have a bodycopy for this asset
1937  $bc_keywords = $bodycopy->getKeywords();
1938  $keywords = Array();
1939  foreach ($bc_keywords as $keyword) {
1940  $keywords[$keyword] = $this->getFunnelbackReplacement($keyword, $results, 0, $type);
1941  }//end foreach
1942 
1943  $bodycopy->setKeywordReplacements($keywords);
1944  $bodycopy->printBody();
1945 
1946  }//end printFlusterList()
1947 
1948 
1959  public function printClusterList($results, $index, $type='site')
1960  {
1961  // Getting the Cluster Format folder
1962  if (!isset($this->_tmp['fluster_folder_id'])) {
1963  $fluster_folder = $this->getFolder('fluster_format');
1964  $this->_tmp['fluster_folder_id'] = $fluster_folder->id;
1965  }//end if
1966 
1967  // Getting the Cluster Default Format Bodycopy
1968  if (!isset($this->_tmp['cluster_format_bc'])) {
1969  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->_tmp['fluster_folder_id'], SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'cluster_format');
1970  if ($link) {
1971  $this->_tmp['cluster_format_bc'] = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], 'bodycopy');
1972  } else {
1973  trigger_localised_error('FNB0004', E_USER_WARNING, 'Cluster');
1974  return;
1975  }
1976  }
1977  $bodycopy = $this->_tmp['cluster_format_bc'];
1978 
1979  // by the time we reach this point we already have a bodycopy for this asset
1980  $bc_keywords = $bodycopy->getKeywords();
1981  $keywords = Array();
1982  // Go through and replace keywords
1983  foreach ($bc_keywords as $keyword) {
1984  $keywords[$keyword] = $this->getFunnelbackReplacement($keyword, $results, $index, $type);
1985  }//end foreach
1986 
1987  $bodycopy->setKeywordReplacements($keywords);
1988  $bodycopy->printBody();
1989 
1990  }//end printClusterList()
1991 
1992 
2002  public function printNavigationList($results, $index)
2003  {
2004  // Getting the Fluster Format folder
2005  if (!isset($this->_tmp['fluster_folder_id'])) {
2006  $fluster_folder = $this->getFolder('fluster_format');
2007  $this->_tmp['fluster_folder_id'] = $fluster_folder->id;
2008  }//end if
2009 
2010  // Getting the Navigation Default Format Bodycopy
2011  if (!isset($this->_tmp['nav_format_bc'])) {
2012  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->_tmp['fluster_folder_id'], SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'navigation_format');
2013  if ($link) {
2014  $this->_tmp['nav_format_bc'] = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], 'bodycopy');
2015  } else {
2016  trigger_localised_error('FNB0004', E_USER_WARNING, 'Navigation');
2017  return;
2018  }
2019  }
2020  $bodycopy = $this->_tmp['nav_format_bc'];
2021 
2022  // by the time we reach this point we already have a bodycopy for this asset
2023  $bc_keywords = $bodycopy->getKeywords();
2024  $keywords = Array();
2025  foreach ($bc_keywords as $keyword) {
2026  $keywords[$keyword] = $this->getFunnelbackReplacement($keyword, $results, $index);
2027  }//end foreach
2028 
2029  $bodycopy->setKeywordReplacements($keywords);
2030  $bodycopy->printBody();
2031 
2032  }//end printNavigationList()
2033 
2034 
2043  public function printSpellList($results)
2044  {
2045  // Getting the Spell Formats folder
2046  if (!isset($this->_tmp['spell_folder_id'])) {
2047  $spell_folder = $this->getFolder('spell_format');
2048  $this->_tmp['spell_folder_id'] = $spell_folder->id;
2049  }//end if
2050 
2051  // Getting the Spell Default Format Bodycopy
2052  if (!isset($this->_tmp['spell_format_bc'])) {
2053  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($this->_tmp['spell_folder_id'], SQ_LINK_TYPE_2, 'bodycopy', TRUE, 'spell_format');
2054  if ($link) {
2055  $this->_tmp['spell_format_bc'] = $GLOBALS['SQ_SYSTEM']->am->getAsset($link['minorid'], 'bodycopy');
2056  } else {
2057  trigger_localised_error('FNB0004', E_USER_WARNING, 'Spell');
2058  return;
2059  }
2060  }
2061  $bodycopy = $this->_tmp['spell_format_bc'];
2062 
2063  // by the time we reach this point we already have a bodycopy for this asset
2064  $bc_keywords = $bodycopy->getKeywords();
2065  $keywords = Array();
2066  foreach ($bc_keywords as $keyword) {
2067  $keywords[$keyword] = $this->getGeneralReplacement($keyword, Array(), $results);
2068  }//end foreach
2069 
2070  $bodycopy->setKeywordReplacements($keywords);
2071  $bodycopy->printBody();
2072 
2073  }//end printSpellList()
2074 
2075 
2076 // --- PRIVATE FUNCTIONS --- //
2077 
2078 
2087  private function _getQueryVars($query_string)
2088  {
2089  // get rid of any leadin '?' if any
2090  $query_string = ltrim($query_string, '?');
2091 
2092  // The regex expression expects a start & so let us do that first
2093  if (strpos($query_string, '&') !== 0) {
2094  $query_string = '&'.$query_string;
2095  }//end if
2096 
2097  $vars = Array();
2098  preg_match_all('|&([^=]+)=([^&]+)?|', $query_string, $matches);
2099  foreach ($matches[1] as $index => $query_name) {
2100  $vars[$query_name] = isset($matches[2][$index]) ? $matches[2][$index] : '';
2101  }//end foreach
2102 
2103  return $vars;
2104 
2105  }//end _getQueryVars()
2106 
2107 
2116  public function parseURL($search)
2117  {
2118  // Get the query term
2119  $query = array_get_index($search, 'query', '');
2120  $query = str_replace(' ', '+', $query);
2121 
2122  // Play nice
2123  $query = str_replace('&', '', $query);
2124 
2125  // Get the URL
2126  $funnelback_url = $this->attr('funnelback_url');
2127  $funnelback_url = trim($funnelback_url);
2128 
2129  // Get the other vars
2130  $collection = $this->attr('collection');
2131  $scope = array_get_index($search, 'scope', '');
2132  $current_result_page = array_get_index($search, 'page', 1);
2133  $num_per_page = array_get_index($search, 'num_per_page', $this->_getNumPerPage());
2134  $cluster = array_get_index($search, 'cluster', Array());
2135  $stem = array_get_index($search, 'stem', 0);
2136  $type_max = array_get_index($search, 'type_max', 0);
2137  $topic_max = array_get_index($search, 'topic_max', 0);
2138  $site_max = array_get_index($search, 'site_max', 0);
2139  $valid_sort = Array ('date' , 'adate' , 'title' , 'dtitle' , 'size' , 'dsize' , 'url' , 'durl' , 'coll' , 'dcoll' , 'shuffle');
2140  $sort = array_get_index($search, 'sort', 'rank');
2141 
2142  // Check for required information
2143  if (empty($funnelback_url) || empty($collection)) {
2144  // No server set
2145  trigger_localised_error('FNB0003', E_USER_WARNING);
2146  return '';
2147  }//end if
2148 
2149  // Add in the collection
2150  $url = '?collection='.urlencode($collection);
2151 
2152  // Add in the scope
2153  if (empty($scope)) {
2154  $scope = $this->attr('default_scope');
2155  }//end if
2156  if (!empty($scope) && $scope != 'ALL') {
2157  $url .= '&scope='.urlencode($scope);
2158  }//end if
2159 
2160  // Add in the paging commands
2161  if ($current_result_page != 1) {
2162  $url .= '&start_rank='.urlencode((($current_result_page-1) * $num_per_page) + 1);
2163  }//end if
2164  if (!empty($num_per_page)) {
2165  $url .= '&num_ranks='.urlencode($num_per_page);
2166  }//end if
2167 
2168  if (!empty($cluster)) {
2169  // If flustering links where clicked
2170  $cluster_string = '';
2171  foreach ($cluster as $count => $item) {
2172  if (empty($item)) continue;
2173  $cluster_string .= '&cluster'.$count.'='.urlencode($item);
2174  }//end foreach
2175  $query_string = '';
2176  rsort($cluster);
2177  foreach ($cluster as $item) {
2178  $query_string .= ' '.$item;
2179  }//end foreach
2180  $query_string = substr($query_string, 1);
2181  if (!empty($cluster_string)) {
2182  $url .= $cluster_string;
2183  $url .= '&query_prox='.urlencode(str_replace('+', ' ', $query));
2184 
2185  // Add in the stem var
2186  if (!empty($stem)) {
2187  $url .= '&stem='.urlencode($stem);
2188  }//end if
2189  } else {
2190  $url .= '&query='.$query;
2191  }//end if
2192  } else {
2193  // Add in the query
2194  $url .= '&query='.$query;
2195  }//end if
2196 
2197  // Fluster more/less links
2198  if (!empty($type_max)) {
2199  $url .= '&type.max_clusters='.$type_max;
2200  } else {
2201  $url .= '&type.max_clusters='.$this->attr('less_type_num');
2202  }//end if
2203  if (!empty($topic_max)) {
2204  $url .= '&topic.max_clusters='.$topic_max;
2205  } else {
2206  $url .= '&topic.max_clusters='.$this->attr('less_topic_num');
2207  }//end if
2208  if (!empty($site_max)) {
2209  $url .= '&site.max_clusters='.$site_max;
2210  } else {
2211  $url .= '&site.max_clusters='.$this->attr('less_site_num');
2212  }//end if
2213 
2214 
2215  // Add in sorting
2216  if (!empty($sort) && $sort !== 'rank' && in_array($sort, $valid_sort)) {
2217  $url .= '&sort='.$sort;
2218  }
2219 
2220  // get the current user and also the assetid
2221  // of all the groups the user is in
2222  $user_info = Array($GLOBALS['SQ_SYSTEM']->user->id);
2223  $user_info = array_merge($GLOBALS['SQ_SYSTEM']->user->getUserGroups(), $user_info);
2224 
2225  $url .= '&userkeys='.implode(',', $user_info);
2226 
2227  return $funnelback_url.$url;
2228 
2229  }//end parseURL()
2230 
2231 
2240  private function _queryFunnelback($url)
2241  {
2242  if (empty($url)) {
2243  trigger_localised_error('FNB0003', E_USER_WARNING);
2244  return FALSE;
2245  }//end if
2246 
2247  $url_ok = @parse_url($url);
2248  if (!$url_ok) {
2249  trigger_localised_error('FNB0003', E_USER_WARNING);
2250  return FALSE;
2251  }//end if
2252 
2253  $options = array(
2254  'TIMEOUT' => 5,
2255  'CONNECTTIMEOUT' => 5,
2256  'MAXREDIRS' => 2,
2257  'FOLLOWLOCATION' => true,
2258  'RETURNTRANSFER' => true,
2259  );
2260 
2261  $headers = Array(
2262  'X-Forwarded-For' => $_SERVER['REMOTE_ADDR'],
2263  );
2264 
2265  $urlResponse = fetch_url($url, $options, $headers);
2266  if ($urlResponse['errornumber'] != 0) {
2267  trigger_localised_error('FNB0002', E_USER_WARNING);
2268  return FALSE;
2269  }
2270 
2271  $xml = $urlResponse['response'];
2272  $code = $urlResponse['curlinfo']['http_code'];
2273 
2274  if (empty($xml) || empty($code) || $code != '200') {
2275  return FALSE;
2276  }//end if
2277 
2278  return $xml;
2279 
2280  }//end _queryFunnelback()
2281 
2282 
2291  private function _searchFunnelback($params)
2292  {
2293  $output = '';
2294 
2295  // Wha..? No params no search
2296  if (empty($params)) {
2297  return FALSE;
2298  }//end if
2299 
2300  // Get the params to work with
2301  $fm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('funnelback_manager');
2302  $nullquery = $fm->getNullQueryKeyword();
2303  $collection_id = $this->attr('collection');
2304  $bin_path = $fm->getFunnelbackPath().'/bin/';
2305  if (!$fm->isCollectionValid($collection_id)) {
2306 
2307  // Collection is not valid, stop the search...
2308  return FALSE;
2309  }//end if
2310  $coll_path = $fm->getCollectionDataPath($collection_id);
2311  $data_path = $fm->getCollectionDataPath($collection_id, 'idx');
2312  $log_file = $fm->getCollectionDataPath($collection_id, 'log').'/query.log';
2313  $thesaurus_config = $fm->getCollectionDataPath($collection_id, 'conf').'/synonyms.cfg';
2314  $search_term = array_get_index($params, 'query', '');
2315  $scope = array_get_index($params, 'scope', '');
2316  $page = array_get_index($params, 'page', 1);
2317  $num_per_page = array_get_index($params, 'num_per_page', $this->_getNumPerPage());
2318  $sort = array_get_index($params, 'sort', $this->attr('sort_order'));
2319  $metadata_scope = $this->_getMetadataScope();
2320  if (empty($scope)) {
2321  $scope = $this->attr('default_scope');
2322  }//end if
2323 
2324  // Build the command line based on params set above
2325  $command = 'echo ';
2326  $query = $this->_getSearchQuery($search_term);
2327  if (empty($query)) {
2328  if ($this->attr('allow_empty')) {
2329  // 'NULL' query (basically use a string with no meaning and use ! - which match everything else)
2330  $query = $nullquery;
2331  $fluster = ''; // Flustering is disabled on a NULL query
2332  } else {
2333  // Empty searches are not permitted
2334  return $output;
2335  }//end if
2336  } else {
2337  // Enable flustering
2338  $fluster = $this->_getFlusterOptions($params);
2339  }//end if
2340  $command .= escapeshellarg($query.' '.$metadata_scope);
2341  $command .= ' | '.$bin_path.'padre-sw'; // Pipe the query to the search command (padre-sw)
2342  $command .= ' '.escapeshellarg($collection_id); // Index Stem aka Collection
2343  $command .= ' -res xml -SMboth -SF'.$this->_getMetadataFields().' -spelling_enabled -qlog_file='.$log_file.$fluster;
2344  $command .= ' -userkeys="'.implode(',', $this->_getUserKeys()).'"';
2345  if (!empty($scope) && $scope != 'ALL') {
2346  $command .= ' -scope '.escapeshellarg($scope);
2347  }//end if
2348  if ($page != 1) {
2349  $command .= ' -start_rank'.((($page-1) * $num_per_page) + 1);
2350  }//end if
2351  if (!empty($num_per_page)) {
2352  $command .= ' -num_ranks'.$num_per_page;
2353  }//end if
2354  switch($sort) {
2355  case 'date':
2356  case 'title':
2357  case 'url':
2358  $command .= ' -sort '.$sort;
2359  break;
2360 
2361  case 'rank':
2362  default:
2363  // Default to rank, already handled by default by Funnelback
2364  break;
2365  }//end switch
2366 
2367  // Searching... Searching... Searching...
2368  $status = $fm->runCommand($command, $output, NULL, NULL, $data_path, Array('SITE_SEARCH_ROOT' => $coll_path));
2369 
2370  // Make sure the 'NULL' query doesn't come through in the results
2371  $output = str_replace($nullquery, '', $output);
2372 
2373  return $output;
2374 
2375  }//end _searchFunnelback()
2376 
2377 
2386  private function _querySquizSearch($search)
2387  {
2388  $systemid = $this->attr('systemid');
2389 
2390  // Get the query term
2391  $query = array_get_index($search, 'query', '');
2392  $query = str_replace('&', '', $query);
2393 
2394  // Get the collection
2395  $collection = $this->attr('collection');
2396 
2397  // Get the other vars
2398  $current_result_page = array_get_index($search, 'page', 1);
2399  $num_per_page = array_get_index($search, 'num_per_page', $this->_getNumPerPage());
2400  $valid_sort = Array ('date' , 'adate' , 'title' , 'dtitle' , 'size' , 'dsize' , 'url' , 'durl' , 'coll' , 'dcoll' , 'shuffle');
2401  $sort = array_get_index($search, 'sort', 'rank');
2402  $scope = array_get_index($search, 'scope', '');
2403  $type_max = array_get_index($search, 'type_max', 0);
2404  $topic_max = array_get_index($search, 'topic_max', 0);
2405  $site_max = array_get_index($search, 'site_max', 0);
2406 
2407  // Build the options.
2408  $options = array();
2409  $options['num_per_page'] = $num_per_page;
2410  $options['contextual_navigation_enabled'] = TRUE;
2411  $options['userkeys'] = $this->_getUserKeys(TRUE);
2412 
2413  // Check for required information
2414  if (empty($systemid) || empty($collection)) {
2415  // No server set
2416  trigger_localised_error('FNB0003', E_USER_WARNING);
2417  return '';
2418  }//end if
2419 
2420  // Add in the scope
2421  if (empty($scope)) {
2422  $scope = $this->attr('default_scope');
2423  }//end if
2424  if (!empty($scope) && $scope != 'ALL') {
2425  $options['scope'] = $scope;
2426  }//end if
2427 
2428  // Add in the paging commands
2429  if ($current_result_page != 1) {
2430  $options['start_at'] = ((($current_result_page-1) * $num_per_page) + 1);
2431  }//end if
2432 
2433  // Fluster more/less links
2434  if (!empty($type_max)) {
2435  $options['type_max_clusters'] = $type_max;
2436  } else {
2437  $options['type_max_clusters'] = $this->attr('less_type_num');
2438  }//end if
2439  if (!empty($topic_max)) {
2440  $options['topic_max_clusters'] = $topic_max;
2441  } else {
2442  $options['topic_max_clusters'] = $this->attr('less_topic_num');
2443  }//end if
2444  if (!empty($site_max)) {
2445  $options['site_max_clusters'] = $site_max;
2446  } else {
2447  $options['site_max_clusters'] = $this->attr('less_site_num');
2448  }//end if
2449 
2450  // Add in sorting
2451  if (!empty($sort) && $sort !== 'rank' && in_array($sort, $valid_sort)) {
2452  $options['sort'] = $sort;
2453  }
2454 
2455  $suitem = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('suite_manager');
2456  $system = $suitem->getProduct($systemid);
2457  $xml = '';
2458 
2459  $request = array(
2460  'query' => $suitem->encodeJson($query),
2461  'collectionid' => $collection,
2462  'options' => $suitem->encodeJson($options),
2463  );
2464  if (!empty($system)) {
2465  $response = $suitem->sendRequest($systemid, 'json', 'SquizSearch', 'Search', $request);
2466  if (isset($response['curlInfo']['http_code']) === TRUE && $response['curlInfo']['http_code'] == 200) {
2467  $resultData = $response['result'];
2468  $resultData = (array) $suitem->decodeJson($resultData);
2469  $xml = (string) $resultData['result'];
2470  }//end if
2471  }//end if
2472 
2473  // Services_JSON will forcibly change Content-type header to json, which is not expected
2474  if (!headers_sent()) {
2475  header('Content-type: text/html;');
2476  }
2477 
2478  return $xml;
2479 
2480  }//end _querySquizSearch()
2481 
2482 
2491  private function _getUserKeys($useSuiteSystemId=FALSE)
2492  {
2493  // Default to the public user keys
2494  $keys = array("'public'");
2495  $user_id = $GLOBALS['SQ_SYSTEM']->currentUserId();
2496  if (!empty($user_id)) {
2497  // Return if public user
2498  $public_user = $GLOBALS['SQ_SYSTEM']->am->getSystemAssetId('public_user');
2499  if ($user_id == $public_user) return $keys;
2500 
2501  // Collate the user and his/her groups
2502  $user = $GLOBALS['SQ_SYSTEM']->am->getAsset($user_id);
2503  if (!is_null($user)) {
2504  $prefix = '';
2505  if ($useSuiteSystemId == TRUE) {
2506  $sm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('suite_manager');
2507  $current = $sm->getCurrentProduct();
2508  $prefix = array_get_index($current, 'systemid', '');
2509  if (!empty($prefix)) $prefix .= '://';
2510  }//end if
2511 
2512  $fm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('funnelback_manager');
2513  $keys = Array($user->id, $public_user, 'public');
2514  $groups = $user->getUserGroups();
2515  $keys = array_merge($keys, $groups);
2516  sort($keys);
2517 
2518  // Nasty.... but essential
2519  foreach ($keys as $index => $key) {
2520  if ($key === 'public') continue;
2521  $keys[$index] = "'".$prefix.$fm->encodeText((string) $key)."'";
2522  }//end foreach
2523 
2524  $userkeys = ' -userkeys="'.implode(',', $keys).'"';
2525  }//end if
2526  }//end if
2527 
2528  return $keys;
2529 
2530  }//end _getUserKeys()
2531 
2532 
2541  private function _getFlusterOptions($params)
2542  {
2543  $fluster = ' -contextual_navigation_enabled';
2544  // $cluster = array_get_index($params, 'cluster', Array());
2545  // $stem = array_get_index($params, 'stem', 0);
2546  $type_max = array_get_index($params, 'type_max', 0);
2547  $topic_max = array_get_index($params, 'topic_max', 0);
2548  $site_max = array_get_index($params, 'site_max', 0);
2549 
2550  if (!empty($type_max)) {
2551  $fluster .= ' -type.max_clusters='.(int) $type_max;
2552  } else {
2553  $fluster .= ' -type.max_clusters='.(int) $this->attr('less_type_num');
2554  }//end if
2555 
2556  if (!empty($topic_max)) {
2557  $fluster .= ' -topic.max_clusters='.(int) $topic_max;
2558  } else {
2559  $fluster .= ' -topic.max_clusters='.(int) $this->attr('less_topic_num');
2560  }//end if
2561 
2562  if (!empty($site_max)) {
2563  $fluster .= ' -site.max_clusters='.(int) $site_max;
2564  } else {
2565  $fluster .= ' -site.max_clusters='.(int) $this->attr('less_site_num');
2566  }//end if
2567 
2568  return $fluster;
2569 
2570  }//end _getFlusterOptions()
2571 
2572 
2579  private function _getMetadataFields()
2580  {
2581  $scope = '';
2582 
2583  $fm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('funnelback_manager');
2584  $all_metadata_config = array_get_index($fm->attr('metamap'), $this->attr('collection'), Array());
2585 
2586  $fields = Array();
2587  foreach($all_metadata_config as $metamap) {
2588  if ($metamap['alias'] !== 'S') {
2589  $fields[] = $metamap['alias'];
2590  }
2591  }
2592 
2593  $fields = array_unique($fields);
2594 
2595  return implode($fields);
2596 
2597  }//end _getMetadataFields()
2598 
2599 
2600 
2607  private function _getMetadataScope()
2608  {
2609  $group_scope = '';
2610  $scope = '';
2611 
2612  $fm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('funnelback_manager');
2613  $all_metadata_config = array_get_index($fm->attr('metamap'), $this->attr('collection'), Array());
2614  $metadata_scope = array_get_index($_GET, $this->getPrefix().'_metadata_scope', Array());
2615 
2616  $default_metadata_logic = Array();
2617  foreach($all_metadata_config as $metamap) {
2618  if (array_get_index($metadata_scope, $metamap['alias'], FALSE) !== FALSE) {
2619  $default_metadata_logic[$metamap['alias']] = $metamap['word_logic'];
2620  }
2621  }
2622  $metadata_logic = array_get_index($_GET, $this->getPrefix().'_metadata_logic', $default_metadata_logic);
2623  foreach ($metadata_scope as $index => $metadata_terms) {
2624  $keywords = preg_split('/([\s\+\-\|\*]*"[^"]+")[\s]*|'.'([\s\+\-\|\*]*`[^`]+`)[\s]*|'.'[\s]+/', $metadata_terms, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
2625  // The query having search operator overrides the default word logic settings
2626  // NOTE: A search operator inside double quotes is part of the search keyword and does not overrides the word logic
2627  $contains_op = FALSE;
2628  foreach($keywords as $keyword) {
2629  if (preg_match('/^\s*[\+\-\|\*]\s*/', $keyword)) {
2630  $contains_op = TRUE;
2631  }
2632  }
2633  $logic = array_get_index($metadata_logic, $index, array_get_index($default_metadata_logic, $index, 2));
2634  foreach($keywords as $value) {
2635  $value = trim($value);
2636  if (!empty($value)) {
2637  if ($contains_op) {
2638  $scope .= ' '.preg_replace('/^([\+\-\|\*]?)'.'([^\+\-\|\*]+)'.'|(".+?")|(`.+?`)$/','$1'.$index.':$2', $value);
2639  } else if ($logic == '0') {
2640  $scope .= ' -'.$index.':'.$value;
2641  } else if ($logic == '1') {
2642  $group_scope .= ' '.$index.':'.$value;
2643  } else {
2644  $scope .= ' +'.$index.':'.$value;
2645  }
2646  }//end if
2647  }//end foreach $keywords
2648  }//end foreach
2649 
2650  $scope = trim($group_scope) ? '|['.trim($group_scope).']'.trim($scope) : trim($scope);
2651 
2652  return $scope;
2653 
2654  }//end _getMetadataScope()
2655 
2656 
2665  private function _getSearchQuery($search_term)
2666  {
2667  $keywords = preg_split('/([\s\+\-\|\*]*"[^"]+")[\s]*|'.'([\s\+\-\|\*]*`[^`]+`)[\s]*|'.'[\s]+/', $search_term, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
2668 
2669  // Query having search operator overrides the word logic settings
2670  foreach($keywords as $keyword) {
2671  if (preg_match('/^\s*[\+\-\|\*]\s*/', $keyword)) {
2672  return $search_term;
2673  }
2674  }
2675 
2676  $logic = array_get_index($_GET, $this->getPrefix().'_search_logic', $this->attr('word_logic'));
2677 
2678  $search_query = '';
2679  foreach ($keywords as $keyword) {
2680  $keyword = trim($keyword);
2681 
2682  if (!empty($keyword)) {
2683  if ($logic == '0') {
2684  $search_query .= ' -'.$keyword;
2685  } else if ($logic == '1') {
2686  $search_query .= ' '.$keyword;
2687  } else {
2688  $search_query .= ' +'.$keyword;
2689  }
2690  }//end if
2691  }//end foreach
2692 
2693  return trim($search_query);
2694 
2695  }//end _getSearchQuery()
2696 
2697 
2709  private function _getClickLoggingJavascript($query, $rank, $url, $event=TRUE)
2710  {
2711  // At minimum, the click logging program needs query, rank and url
2712  if (empty($query)) return '';
2713  if (empty($rank)) return '';
2714  if (empty($url)) return '';
2715 
2716  $click_event = '';
2717  $click_event .= (($event) ? 'onclick="' : '');
2718  $click_event .= "FunnelbackSearch.clickLog('".$query."','".$rank."','".$url."'); return true;";
2719  $click_event .= (($event) ? '"' : '');
2720 
2721  return $click_event;
2722 
2723  }//end _getClickLoggingJavascript()
2724 
2725 
2732  private function _getSearchPageJavascript()
2733  {
2734  $collection = $this->attr('collection');
2735  ob_start();
2736  ?>
2737 <script type="text/javascript">
2738  var FunnelbackSearch = function() {
2739 
2740  return {
2741  clickLog : function(query,rank,url) {
2742  if (window.XMLHttpRequest) {
2743  var xhr = new window.XMLHttpRequest();
2744  } else {
2745  var xhr = new ActiveXObject("Microsoft.XMLHTTP");
2746  }
2747 
2748  var getURL = '<?php echo current_url(); ?>?click=1&click_query='+query+'&click_rank='+rank+'&click_url='+url+'&click_collection=<?php echo $collection; ?>';
2749  xhr.open("GET", getURL, true);
2750  xhr.send(null);
2751  }
2752  };
2753  }();
2754 </script>
2755  <?php
2756  $contents = ob_get_contents();
2757  ob_end_clean();
2758 
2759  return $contents;
2760 
2761  }//end _getSearchPageJavascript()
2762 
2763 
2772  public function _stripURL($url)
2773  {
2774  return str_replace('/search/xml.cgi?', '', $url);
2775 
2776  }//end _stripURL()
2777 
2778 
2787  public function processSearchSummary(&$xml)
2788  {
2789  $default_fluster = Array('category' => Array('type' => Array(), 'topic' => Array(), 'site' => Array()));
2790  $results = Array('summary' => Array(), 'fluster' => $default_fluster, 'spell' => Array(), 'featured' => Array());
2791 
2792  $adv_hosted_search = FALSE;
2793  if ($this->attr('search_type') == 'hosted' && $this->attr('hosted_mode')) {
2794  $response = $xml->getElementsByTagName('response');
2795  $result_packet = $response->item(0)->getElementsByTagName('resultPacket');
2796  $adv_hosted_search = TRUE;
2797  }
2809  if ($adv_hosted_search) {
2810  $mapping_array = Array(
2811  'fullyMatching'=> 'fully_matching',
2812  'estimatedHits'=> 'estimated_hits',
2813  'partiallyMatching'=> 'partially_matching',
2814  'totalMatching'=> 'total_matching',
2815  'numRanks'=> 'num_ranks',
2816  'currStart'=> 'currstart',
2817  'currEnd'=> 'currend',
2818  'prevStart'=> 'prevstart',
2819  'nextStart'=> 'nextstart',
2820  );
2821  $result_summary = $result_packet->item(0)->getElementsByTagName('resultsSummary');
2822  } else {
2823  $result_summary = $xml->getElementsByTagName('results_summary');
2824  }
2825 
2826  for ($i=0; $i<$result_summary->length; $i++) {
2827  if ($result_summary->item($i)->hasChildNodes()) {
2828  foreach ($result_summary->item($i)->childNodes as $summary) {
2829  $name = isset($mapping_array[$summary->nodeName]) ? $mapping_array[$summary->nodeName] : $summary->nodeName;
2830  $value = $summary->nodeValue;
2831  $results['summary'][$name] = (string) $value;
2832  }//end foreach
2833  }//end if
2834  }//end for
2835 
2836 
2848  if ($adv_hosted_search) {
2849  $mapping_array = Array(
2850  'trigger'=> 'bb_trigger',
2851  'link'=> 'bb_link',
2852  'title'=> 'bb_title',
2853  'description'=> 'bb_desc',
2854  );
2855  $feature_pages = $result_packet->item(0)->getElementsByTagName('bestBets');
2856  } else {
2857  $feature_pages = $xml->getElementsByTagName('best_bets');
2858  }
2859  // before FB v9.1, we call it featured_pages
2860  if($feature_pages->length == 0) $feature_pages = $xml->getElementsByTagName('featured_pages');
2861 
2862  if ($feature_pages->length >= 1) {
2863  $tag_name = ($adv_hosted_search) ? 'com.funnelback.publicui.search.model.padre.BestBet' : 'bb';
2864  $featured_pages = $feature_pages->item(0)->getElementsByTagName('bb');
2865  // before FB v9.1, we call it fp
2866  if($featured_pages->length == 0)
2867  $featured_pages = $feature_pages->item(0)->getElementsByTagName('fp');
2868  for ($j=0; $j<$featured_pages->length; $j++) {
2869  $bb = Array();
2870  if ($featured_pages->item($j)->hasChildNodes()) {
2871  foreach ($featured_pages->item($j)->childNodes as $entry) {
2872  $name = (isset($array_mapping[$entry->nodeName])) ? $array_mapping[$entry->nodeName] : $entry->nodeName;
2873  // before FB v9.1, we call it fp_xx, so to make sure it doesn't break existing keywords etc, we have to stick with old names.
2874  switch ($name) {
2875  case 'bb_trigger':
2876  $name = 'fp_trigger';
2877  break;
2878  case 'bb_link':
2879  $name = 'fp_link';
2880  break;
2881  case 'bb_title':
2882  $name = 'fp_title';
2883  break;
2884  case 'bb_desc':
2885  $name = 'fp_desc';
2886  break;
2887  default:
2888  break;
2889  }
2890  $value = $entry->nodeValue;
2891  if ($name != '#text') {
2892  $bb[$name] = $value;
2893  }//end if
2894  }//end for
2895  }//end if
2896  $results['featured'][] = $bb;
2897  }//end for
2898  }//end if
2899 
2918  if ($adv_hosted_search) {
2919  $mapping_array = Array(
2920  'clusterNav'=> 'cluster_nav',
2921  'moreLink'=> 'more_link',
2922  'fewerLink'=> 'fewer_link',
2923  );
2924  $fluster = $result_packet->item(0)->getElementsByTagName('contextualNavigation');
2925  } else {
2926  $fluster = $xml->getElementsByTagName('contextual_navigation');
2927  }
2928  // before FB v9.1, we call it fluster
2929  if($fluster->length == 0) $fluster = $xml->getElementsByTagName('fluster');
2930 
2931  for ($l=0; $l<$fluster->length; $l++) {
2932  // Process the cluster_nav elements
2933  $tag_name = $adv_hosted_search ? 'clusterNav' : 'cluster_nav';
2934  $cluster_nav = $fluster->item($l)->getElementsByTagName($tag_name);
2935  for ($m=0; $m<$cluster_nav->length; $m++) {
2936  $current_nav = Array();
2937  $current_nav['name'] = $cluster_nav->item($m)->nodeValue;
2938  if ($cluster_nav->item($m)->hasAttributes()) {
2939  foreach ($cluster_nav->item($m)->attributes as $attr) {
2940  if ($attr->name == 'url') {
2941  $current_nav[$attr->name] = $this->_stripURL($attr->value);
2942  } else {
2943  $current_nav[$attr->name] = $attr->value;
2944  }//end if
2945  }//end foreach
2946  }//end if
2947  $level = array_get_index($current_nav, 'level', 0);
2948  $results['fluster']['navigation'][$level] = $current_nav;
2949  }//end foreach
2950 
2951  // Process the category elements
2952  $tag_name = $adv_hosted_search ? 'com.funnelback.publicui.search.model.padre.Category' : 'category';
2953  $category = $fluster->item($l)->getElementsByTagName($tag_name);
2954  for ($n=0; $n<$category->length; $n++) {
2955  $value = $category->item($n)->getAttribute('name');
2956  $more = (int) $category->item($n)->getAttribute('more');
2957  if (!empty($more)) {
2958  $results['fluster']['category'][$value]['more'] = TRUE;
2959  } else {
2960  $results['fluster']['category'][$value]['more']= FALSE;
2961  }//end if
2962  if ($category->item($n)->hasChildNodes()) {
2963  foreach ($category->item($n)->childNodes as $cluster) {
2964  // For Funnelback 9.0 and higher, this is the more link
2965  $tag_name = isset($mapping_array[$cluster->nodeName]) ? $mapping_array[$cluster->nodeName] : $cluster->nodeName;
2966  if ($tag_name == 'more_link') {
2967  $results['fluster']['category'][$value]['more'] = TRUE;
2968  }//end if
2969 
2970  // Process the rest
2971  $tag_name = $adv_hosted_search ? 'com.funnelback.publicui.search.model.padre.Cluster' : 'cluster';
2972  if ($cluster->nodeName != $tag_name) continue;
2973  $fluster_cluster = Array();
2974  if ($cluster->hasAttributes()) {
2975  foreach ($cluster->attributes as $attr) {
2976  if ($attr->name == 'href') {
2977  $fluster_cluster[$attr->name] = $this->_stripURL($attr->value);
2978  } else {
2979  $fluster_cluster[$attr->name] = $attr->value;
2980  }//end if
2981  }//end foreach
2982  }//end if
2983  $cluster_name_value = trim((string) $cluster->nodeValue);
2984  if (!empty($cluster_name_value)) {
2985  $fluster_cluster['name'] = $cluster_name_value;
2986  $results['fluster']['category'][$value][] = $fluster_cluster;
2987  }//end if
2988  }//end foreach
2989  }//end if
2990  }//end for
2991  }//end foreach
2992 
3005  $spell = $xml->getElementsByTagName('spell');
3006  for ($o=0; $o<$spell->length; $o++) {
3007  if ($spell->item($o)->hasChildNodes()) {
3008  foreach ($spell->item($o)->childNodes as $spell_value) {
3009  $spell_name = $spell_value->nodeName;
3010  if ($spell_name == 'map') {
3011  $map = Array();
3012  if ($spell_value->hasChildNodes()) {
3013  foreach ($spell_value->childNodes as $map_value) {
3014  $map_name = $map_value->nodeValue;
3015  $map[$map_name] = (string)$map_value->nodeValue;
3016  }//end foreach
3017  }//end if
3018  $results['spell']['map'][] = $map;
3019  } else {
3020  $results['spell'][$spell_name] = (string) $spell_value->nodeValue;
3021  }//end if
3022  }//end foreach
3023  }//end if
3024  }//end for
3025 
3026  return $results;
3027 
3028  }//end processSearchSummary()
3029 
3030 
3039  public function processSearchResults(&$xml)
3040  {
3041  $results = Array();
3042 
3043  $adv_hosted_search = FALSE;
3044  if ($this->attr('search_type') == 'hosted' && $this->attr('hosted_mode')) {
3045  $mapping_array = Array(
3046  'liveUrl' => 'live_url',
3047  'cacheUrl' => 'cache_url',
3048  'fileSize' => 'filesize',
3049  'fileType' => 'filetype',
3050  'docNum' => 'docnum',
3051  'clickTrackingUrl' => 'click_tracking_url',
3052  );
3053  $response = $xml->getElementsByTagName('response');
3054  $resultPacket = $response->item(0)->getElementsByTagName('resultPacket');
3055  $result = $resultPacket->item(0)->getElementsByTagName('results');
3056  $adv_hosted_search = TRUE;
3057  } else {
3058  $result = $xml->getElementsByTagName('results');
3059  }
3060 
3061  for ($p=0; $p<$result->length; $p++) {
3062  if ($result->item($p)->hasChildNodes()) {
3063  foreach ($result->item($p)->childNodes as $single_result) {
3064  $expected_tag = $adv_hosted_search ? 'com.funnelback.publicui.search.model.padre.Result' : 'result';
3065  $name = $single_result->nodeName;
3066  if ($name == $expected_tag) {
3067  $each_result = Array();
3086  if ($single_result->hasChildNodes()) {
3087  foreach ($single_result->childNodes as $value) {
3088  $nodeName = $value->nodeName;
3089  if ($nodeName == 'md' && $value->hasAttribute('f')) {
3090  $nodeName = 'meta_'.$value->getAttribute('f');
3091  }
3092  if ($adv_hosted_search)
3093  $nodeName = (isset($mapping_array[$nodeName])) ? $mapping_array[$nodeName] : $nodeName;
3094  $each_result[$nodeName] = utf8_decode($value->nodeValue);
3095  }//end foreach
3096  }//end if
3097 
3098  // Return a result TODO Unsure about this yet!
3099  $rank = array_get_index($each_result, 'rank', 0);
3100  if (!empty($rank)) {
3101  $results[$rank] = $each_result;
3102  }//end if
3103  }//end if
3104  }//end foreach
3105  }//end if
3106  }//end for
3107 
3108  return $results;
3109 
3110  }//end processSearchResults()
3111 
3112 
3122  private function _sanitizeQueries($queries)
3123  {
3124  if(is_array($queries)) {
3125  foreach($queries as $field => $query) {
3126  $queries[$field] = $this->_sanitizeQueries($query);
3127  }
3128  } else {
3129  // sanitise it by removing '%' from keywords so that
3130  // they dont go ahead and try to fetch it replacement
3131  $keywords = extract_keywords($queries);
3132  foreach ($keywords as $keyword) {
3133  $pattern = '/(%*)'.$keyword.'(%*)/';
3134  $queries = preg_replace($pattern, $keyword, $queries);
3135  }
3136  }
3137 
3138  return $queries;
3139 
3140  }//end _sanitizeQueries()
3141 
3142 
3143 }//end class
3144 
3145 
3158 function funnelback_xml_error_handler($errno, $errstr, $errfile, $errline)
3159 {
3160  if ($errno & (E_USER_ERROR | E_ERROR | E_USER_WARNING | E_WARNING)) {
3161  log_dump('XML ERROR: '.$errstr.'. Error Number:'.$errno.'. Error File:'.$errfile.'. Error Line:'.$errline);
3162  throw new ErrorException($errstr, $errno);
3163  }//end if
3164 
3165 }//end funnelback_xml_error_handler()
3166 
3167 
3168 ?>