/joomla/plugins/search/gw_search.php
PHP | 396 lines | 256 code | 62 blank | 78 comment | 16 complexity | 2101b9d520870f26e476932c18b67cf8 MD5 | raw file
- <?php
- /**
- * @version $Id$
- * @package Joomla
- * @subpackage Glossword Search
- * @copyright  Dmitry N. Shilnikov, 2002-2010
- * @license GNU/GPL, see http://code.google.com/p/glossword/
- */
- defined( '_JEXEC' ) or die( 'Restricted access' );
- $mainframe->registerEvent( 'onSearch', 'plgSearchGlossword' );
- $mainframe->registerEvent( 'onSearchAreas', 'plgSearchGlosswordAreas' );
- JPlugin::loadLanguage( 'plg_search_glossword' );
- define( 'GW_AREAOFSEARCH', JText::_( 'AREAOFSEARCH' ) );
- /**
- * @return array An array of search areas
- */
- function &plgSearchGlosswordAreas()
- {
- static $areas = array(
- 'gw_search' => GW_AREAOFSEARCH
- );
- return $areas;
- }
- /* */
- function search_index__filter_si( &$o, $s )
- {
- #$s = $this->rm_specials( $s );
- $s = search_index__str_normalize( $o, $s );
- $s = search_index__text_si( $o, trim( $s ) );
- return $s;
- }
- function search_index__text_si( &$o, $s )
- {
- /* Do lowercase */
- # $s = $o->oCase->lc( $s );
-
- /* Mask non-ASCII characters */
- $s = preg_replace( "/([\\xc0-\\xff][\\x80-\\xbf]*)/e", "'U8' . bin2hex( \"$1\" )", $s );
-
- /* Mask MySQL stopwords */
- $s = search_index__mask_stopwords( $s );
-
- return $s;
- }
- /* */
- function search_index__str_normalize( &$o, $s )
- {
- $jo_db =& JFactory::getDBO();
-
- /* Do lowercase */
- $s = $o->oCase->lc( $s );
- /* Use PECL extension */
- if ( class_exists( 'Normalizer' ) )
- {
- return Normalizer::normalize( $s, Normalizer::FORM_C );
- }
- /* */
- preg_match_all( "/./u", $s, $ar );
- $ar = $ar[0];
- $ar_c_crc = array();
- /* For each character */
- foreach ($ar AS $k => &$v )
- {
- /* Use values as key */
- /* PHP-bug: sometimes a string keys becomes interger */
- $ar_c_crc[$v] = sprintf( "%u", crc32( $v ) );
- }
- unset( $v );
- if ( empty( $ar_c_crc ) ){ return $s; }
- /* */
- $query = 'SELECT `str_from`, `str_to`'
- . ' FROM '.$o->V->db_name.'.'.$o->V->table_prefix.'unicode_normalization '
- . ' WHERE `crc32u` IN ('. implode(',', array_values( $ar_c_crc ) ).')';
- $jo_db->setQuery( $query );
- $ar_sql = $jo_db->loadAssocList();
- if ( is_null( $ar_sql ) ){ $ar_sql = array(); }
- /* Normalize text */
- foreach ($ar_sql AS $k => &$v )
- {
- $s = str_replace( urldecode( $v['str_from'] ), urldecode( $v['str_to'] ), $s );
- unset( $ar_sql[$k] );
- }
- unset( $v );
- return $s;
- }
- function search_index__mask_stopwords( $s )
- {
- return preg_replace( '/\b([a-z]+)/', '_\\1', $s );
- }
- function search_index__get_crc_u( $s )
- {
- return sprintf( "%u", crc32( $s ) );
- }
- /* replacement for urlencode */
- function ohtml_urlencode( $s )
- {
- /* Encode special characters first */
- $s = str_replace( array( ',', '/', '+' ), array( '%2C', '%2F', '%2B' ), $s );
- $s = urlencode( $s );
- /* Restore separators for #area */
- $s = str_replace( array( '%01%01', '%02%02' ), array( ',', '.' ), $s );
- return $s;
- }
- /* */
- function &plgSearchGlossword( $q, $phrase='', $ordering='', $areas=null )
- {
- global $mainframe;
- $jo_db =& JFactory::getDBO();
- #$jo_user =& JFactory::getUser();
- #$jo_cfg =& JFactory::getConfig();
- $jo_component = &JComponentHelper::getComponent('com_glossword');
- $jo_menu = &JSite::getMenu();
- $jo_items = $jo_menu->getItems('componentid', $jo_component->id, true);
- #require_once( JPATH_SITE.DS.'components'.DS.'com_content'.DS.'helpers'.DS.'route.php' );
-
- if ( is_array( $areas ) )
- {
- if ( !array_intersect( $areas, array_keys( plgSearchGlosswordAreas() ) ) )
- {
- return array();
- }
- }
-
- /* Load plugin parameters */
- $jo_plugin =& JPluginHelper::getPlugin( 'search', 'gw_search' );
- $pluginParams = new JParameter( $jo_plugin->params );
-
- $offset = JRequest::getVar( 'start', 0, '', 'int' );
- $per_page = JRequest::getVar( 'limit', $pluginParams->get( 'int_per_page' ), '', 'int' );
-
- /* Load component configuration */
- $query = 'SELECT * FROM #__gw_config';
- $jo_db->setQuery( $query );
- $ar_sql = $jo_db->loadAssocList();
- if ( is_null( $ar_sql ) ){ $ar_sql = array(); }
-
- $ar_cfg = array();
- foreach ( $ar_sql as $k => $v )
- {
- $ar_cfg[$v['setting_key']] = $v['setting_value'];
- }
-
- require_once( $ar_cfg['path_core_abs'].'/gw_config.php' );
-
- /* */
- $_SERVER['REQUEST_TIME'] = isset( $_SERVER['REQUEST_TIME'] ) ? $_SERVER['REQUEST_TIME'] : mktime();
- $o = crc32( $_SERVER['REQUEST_TIME'] );
-
- ${$o} = new site_db_config();
-
- ${$o}->a( 'path_includes', $ar_cfg['path_core_abs'].'/'.${$o}->V->path_includes );
- foreach ( $ar_cfg as $setting_key => $setting_value )
- {
- ${$o}->a( $setting_key, $setting_value );
- }
-
- /* */
- include_once( ${$o}->V->path_includes.'/class.case.php' );
- ${$o}->oCase = new gwv_casemap;
- ${$o}->oCase->is_use_mbstring = 1;
- $q = preg_replace( "/ {2,}/", ' ', $q );
- $q = trim( $q );
-
- $q_si = search_index__filter_si( ${$o}, $q );
- /* Need to test. Could not be equal. */
- $ar_words_sql = explode( ' ', $q_si );
- $ar_words_q = explode( ' ', $q );
-
- /* 11 Apr 2008: Enable search with asterisk for Chinese, Japanese and Korean characters */
- foreach ( $ar_words_q as $k => $word )
- {
- if ( preg_match( '/[\x{3040}-\x{312F}|\x{3400}-\x{9FFF}|\x{AC00}-\x{D7AF}]/u', $word, $ar_matches ) )
- {
- $ar_words_sql[$k] .= '*';
- }
- }
-
- /* Switch search modes */
- switch ( $phrase )
- {
- case 'any':
- $sql_against = implode( ' ', $ar_words_sql );
- break;
- case 'exact':
- $sql_against = '"'.implode( ' ', $ar_words_sql ).'"';
- break;
- default:
- $sql_against = '+'.implode( ' +', $ar_words_sql );
- break;
- }
-
- /**
- * ----------------------------------------------
- * Count Item IDs
- * ----------------------------------------------
- */
- $query = 'SELECT csi.id_item ';
- #$query .= "\n".', MATCH(csi.contents_si) AGAINST(\''. $jo_db->getEscaped( $sql_against ).'\' IN BOOLEAN MODE) score ';
- $query .= "\n".' FROM '.${$o}->V->db_name.'.'.${$o}->V->table_prefix.'contents_si csi';
- $query .= "\n".' WHERE ';
- $query .= "\n".' MATCH(csi.contents_si) AGAINST(\''.$jo_db->getEscaped( $sql_against ).'\' IN BOOLEAN MODE)';
- $query .= "\n".' GROUP BY csi.id_item ';
- $jo_db->setQuery( $query, 0, $pluginParams->get( 'int_search_max' ) );
- $jo_db->query();
- $cnt_records = $jo_db->getNumRows();
-
- /**
- * ----------------------------------------------
- * Select Item IDs
- * ----------------------------------------------
- */
- $jo_db->setQuery( 'SET SQL_BIG_SELECTS=1' );
- $jo_db->query();
-
- $query = 'SELECT csi.id_item';
- /* 1.9.3: Custom alphabetic order */
- $ar_join = array();
- for ( $i = 1; $i <= 8; $i++ )
- {
- $query .= ', az'.$i.'.int_sort';
- $ar_join[$i] = "\n".'LEFT JOIN '.${$o}->V->db_name.'.'.${$o}->V->table_prefix.'az_letters az'.$i.' ON ';
- $ar_join[$i] .= 'az'.$i.'.uc_crc32u = c.contents_'.$i.' AND c.id_lang = az'.$i.'.id_lang';
- }
- $query .= "\n".' FROM '.${$o}->V->db_name.'.'.${$o}->V->table_prefix.'contents_si csi, ';
- $query .= ${$o}->V->db_name.'.'.${$o}->V->table_prefix.'items i, '.${$o}->V->db_name.'.'.${$o}->V->table_prefix.'contents c';
- $query .= implode( ' ', $ar_join );
- $query .= "\n".' WHERE ';
- $query .= "\n".' MATCH(csi.contents_si) AGAINST(\''.$jo_db->getEscaped( $sql_against ).'\' IN BOOLEAN MODE)';
- $query .= ' AND i.id_item = c.id_item ';
- $query .= ' AND i.id_item = csi.id_item ';
- $query .= "\n".' GROUP BY csi.id_item ';
-
- $ar_order = array( 'c.id_lang' );
- /* Switch sorting modes */
- switch ( $ordering )
- {
- case 'newest':
- $ar_order[] = 'i.item_cdate DESC';
- break;
- case 'oldest':
- $ar_order[] = 'i.item_cdate ASC';
- break;
- case 'popular':
- $ar_order[] = 'i.cnt_hits DESC';
- break;
- default:
- break;
- }
- /* 1.9.3: Custom alphabetic order */
- for ( $i = 1; $i <= 8; $i++ )
- {
- $ar_order[] = 'az'.$i.'.int_sort, c.contents_so';
- }
- $query .= "\n".'ORDER BY '.implode( ', ', $ar_order );
-
- #$query .= ' HAVING score > 0 ';
- #$query .= ' ORDER BY score DESC ';
-
- /* Can't use pagination for requests because of Joomla */
- /* Using `int_search_max` instead */
- /* @todo: workaround */
- #$jo_db->setQuery( $query, $offset, $per_page );
- $jo_db->setQuery( $query, 0, $pluginParams->get( 'int_search_max' ) );
- $ar_sql = $jo_db->loadAssocList();
- if ( is_null( $ar_sql ) ){ $ar_sql = array(); }
- $ar_item_ids = array();
- foreach ( $ar_sql as $ar_v )
- {
- $ar_item_ids[] = $ar_v['id_item'];
- }
-
- if ( empty( $ar_item_ids ) )
- {
- return array();
- }
- /**
- * ----------------------------------------------
- * Select Items
- * ----------------------------------------------
- */
- $ar_sql_items = array();
- if ( !empty( $ar_item_ids ) )
- {
- $query = 'SELECT uri.item_uri, i.id_item, i.item_id_user_created, i.item_cdate, c.contents_value_cached, c.id_field ';
- $query .= "\n".' FROM '.${$o}->V->db_name.'.'.${$o}->V->table_prefix.'items i, ';
- $query .= ${$o}->V->db_name.'.'.${$o}->V->table_prefix.'contents c, ';
- $query .= ${$o}->V->db_name.'.'.${$o}->V->table_prefix.'items_uri uri, ';
- $query .= ${$o}->V->db_name.'.'.${$o}->V->table_prefix.'map_field_to_fieldset mftf ';
- $query .= "\n".' WHERE i.id_item = c.id_item ';
- $query .= ' AND i.id_item = uri.id_item ';
- $query .= ' AND mftf.id_field = c.id_field ';
- $query .= ' AND mftf.id_fieldset = \'1\' ';
- $query .= ' AND i.id_item IN ('. implode( ', ', $ar_item_ids ).') ';
- $ar_order_by = array();
- foreach ( $ar_item_ids as $id_item_in )
- {
- $ar_order_by[] = 'i.id_item = "'.$id_item_in.'" DESC';
- }
- $ar_order_by[] = 'mftf.int_sort ASC';
- $query .= "\n".' ORDER BY '. implode( ', ', $ar_order_by );
-
- $jo_db->setQuery( $query );
- $ar_sql_items = $jo_db->loadAssocList();
- if ( is_null( $ar_sql_items ) ){ $ar_sql_items = array(); }
- }
- /* Re-arrange */
- $ar_items = array();
- foreach ( $ar_sql_items as $k => $ar_v)
- {
- $ar_items[$ar_v['id_item']][$ar_v['id_field']] = $ar_v;
- unset( $ar_sql_items[$k] );
- }
- /* */
- $cnt = 0;
- $oResults[0] = (object) 'results';
- foreach ( $ar_items as $id_item => $ar_fields_content)
- {
- $ar_str_item_title = array();
- $ar_str_item_descr = array();
- foreach ( $ar_fields_content as $id_field => $ar_v)
- {
- switch ( $id_field )
- {
- case 1:
- $ar_str_item_title[] = $ar_v['contents_value_cached'];
- break;
- /* More to come */
- default:
- $ar_str_item_descr[] = $ar_v['contents_value_cached'];
- break;
- }
- }
- /* Item title */
- $str_item = implode( ' ', $ar_str_item_title );
-
- /* Hyperlink to item */
- $href_area = 'a.search,q.'. ohtml_urlencode( $str_item ). ',t.items';
- $href_area = urlencode( $href_area );
-
- $href = JRoute::_( 'index.php?option='.$jo_component->option.'&Itemid='.$jo_items->id.'&arg[area]='.$href_area.'&view=default' );
- /* Item description */
- $str_descr = strip_tags( implode( ' ', $ar_str_item_descr ) );
- /* */
- $oResults[$cnt]->browsernav = 0;
- $oResults[$cnt]->section = GW_AREAOFSEARCH;
-
- $oResults[$cnt]->href = $href;
- $oResults[$cnt]->text = $str_descr;
- $oResults[$cnt]->title = strip_tags( $str_item );
-
- #$oResults[$cnt]->title .= ' [href='.htmlspecialchars( $oResults[$cnt]->href ).']';
- #show_date
- $oResults[$cnt]->created = $ar_v['item_cdate'];
- ++$cnt;
- }
- #print '<pre>'.__FILE__.' '.__LINE__.'<br />';
- #print_r( $oResults );
- #print '</pre>';
- #print '<div>$cnt_records='.$cnt_records.'</div>';
- #print '<div>$per_page='.$per_page.'</div>';
- return $oResults;
- }
- ?>