* Invision Power Services * IP.Board v3.2.3 * Basic Forum Search * Last Updated: $Date: 2011-09-29 22:09:09 -0400 (Thu, 29 Sep 2011) $ * * * @author $Author: bfarber $ * @copyright (c) 2001 - 2009 Invision Power Services, Inc. * @license This is NULLED! * @package IP.Board * @subpackage Forums * @link http://hatynka.in * @version $Rev: 9570 $ */ if ( ! defined( 'IN_IPB' ) ) { print "

Incorrect access

You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files."; exit(); } class search_engine_forums extends search_engine { /** * Constructor */ public function __construct( ipsRegistry $registry ) { /* Hard limit */ IPSSearchRegistry::set('set.hardLimit', ( ipsRegistry::$settings['search_hardlimit'] ) ? ipsRegistry::$settings['search_hardlimit'] : 200 ); /* Get class forums, used for displaying forum names on results */ if ( ipsRegistry::isClassLoaded('class_forums') !== TRUE ) { $classToLoad = IPSLib::loadLibrary( IPSLib::getAppDir( 'forums' ) . "/sources/classes/forums/class_forums.php", 'class_forums', 'forums' ); ipsRegistry::setClass( 'class_forums', new $classToLoad( ipsRegistry::instance() ) ); ipsRegistry::getClass('class_forums')->strip_invisible = 1; ipsRegistry::getClass('class_forums')->forumsInit(); } /* Load tagging stuff */ if ( ! $registry->isClassLoaded('tags') ) { require_once( IPS_ROOT_PATH . 'sources/classes/tags/bootstrap.php' );/*noLibHook*/ $registry->setClass( 'tags', classes_tags_bootstrap::run( 'forums', 'topics' ) ); } parent::__construct( $registry ); } /** * Perform a search. * Returns an array of a total count (total number of matches) * and an array of IDs ( 0 => 1203, 1 => 928, 2 => 2938 ).. matching the required number based on pagination. The ids returned would be based on the filters and type of search * * So if we had 1000 replies, and we are on page 2 of 25 per page, we'd return 25 items offset by 25 * * @return array */ public function search() { /* INIT */ $sort_by = IPSSearchRegistry::get('in.search_sort_by'); $sort_order = IPSSearchRegistry::get('in.search_sort_order'); $search_term = IPSSearchRegistry::get('in.clean_search_term'); $search_tags = IPSSearchRegistry::get('in.raw_search_tags'); $rows = array(); $c = 0; $got = 0; $sortKey = ''; $sortType = ''; $cType = IPSSearchRegistry::get('contextual.type'); $cId = IPSSearchRegistry::get('contextual.id' ); $topicIds = array(); /* Contextual search */ if ( $cType == 'topic' ) { IPSSearchRegistry::set('opt.searchType', 'content'); IPSSearchRegistry::set('opt.noPostPreview', false); IPSSearchRegistry::set('set.returnType', 'pids' ); } /* If searching tags, we don't show a preview */ if( $search_tags ) { IPSSearchRegistry::set('opt.noPostPreview', true); IPSSearchRegistry::set('set.returnType', 'tids' ); } /* Set up the flag for displaying results for posts and topics */ if ( IPSSearchRegistry::get('opt.searchType') == 'both' || ( IPSSearchRegistry::get('opt.searchType') == 'content' && IPSSearchRegistry::get('opt.noPostPreview') ) ) { IPSSearchRegistry::set('set.searchResultType', 'both' ); } /* Sorting */ switch( $sort_by ) { default: case 'date': $sortKey = ! IPSSearchRegistry::searchTitleOnly() ? 'post_date' : 'last_post'; $sortType = 'numerical'; break; case 'title': $sortKey = 'title'; $sortType = 'string'; break; case 'posts': $sortKey = 'posts'; $sortType = 'numerical'; break; case 'views': $sortKey = 'views'; $sortType = 'numerical'; break; } /* Search in titles */ if ( $search_term OR !($search_tags && $this->settings['tags_enabled']) ) { if ( ! IPSSearchRegistry::searchTitleOnly() ) { /* Do the search */ $this->DB->build( array( 'select' => "p.pid as id, p.post_date, p.topic_id", 'from' => array( 'posts' => 'p' ), 'where' => $this->_buildWhereStatement( $search_term, IPSSearchRegistry::searchTitleOnly(), '', null, ( IPSSearchRegistry::get('opt.searchType') == 'content' || IPSSearchRegistry::get('in.search_author') ) ? false : true ), 'limit' => array(0, IPSSearchRegistry::get('set.hardLimit') + 1), 'order' => $sortKey . ' ' . $sort_order, 'add_join' => array( array( 'select' => 't.title, t.posts, t.views', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=p.topic_id', 'type' => 'left' ) ) ) ); } else { /* Do the search */ $this->DB->build( array( 'select' => "t.tid as id, t.tid as topic_id, t.title, t.posts, t.views, t.last_post", 'from' => 'topics t', 'where' => str_replace( 'p.author_id', 't.starter_id', $this->_buildWhereStatement( $search_term, IPSSearchRegistry::searchTitleOnly() ) ), 'limit' => array(0, IPSSearchRegistry::get('set.hardLimit') + 1), 'order' => 't.'.$sortKey . ' ' . $sort_order ) ); } $DB = $this->DB->execute(); /* Fetch all to sort */ while( $r = $this->DB->fetch( $DB ) ) { $topicIds[] = $r['topic_id']; if ( IPSSearchRegistry::get('opt.noPostPreview') ) { $_rows[ $r['topic_id'] ] = $r; } else { $_rows[ $r['id'] ] = $r; } } } /* Check tags */ if ( $search_tags && $this->settings['tags_enabled'] ) { $tags = $this->registry->tags->search( $search_tags, array( 'meta_parent_id' => $this->request['search_app_filters']['forums']['forums'], 'meta_app' => 'forums', 'meta_area' => 'topics', 'meta_id' => $topicIds, //'sortKey' => 't.' . str_replace( 'post_date', 'topic_firstpost', $sortKey ), 'sortOrder' => $sort_order, /*'joins' => array( 'select' => 't.tid', 'from' => array( 'topics' => 't' ), 'where' => 't.tid=tg.tag_meta_id', 'type' => 'left' )*/ ) ); /* Do the search */ if ( is_array( $tags) && count( $tags ) ) { $_tagIds = array(); $_rows = array(); foreach( $tags as $id => $data ) { $_tagIds[] = $data['tag_meta_id']; } $this->DB->build( array('select' => "t.tid as id, t.tid as topic_id, t.title, t.posts, t.views, t.last_post", 'from' => array( 'topics' => 't' ), 'where' => 't.tid IN (' . implode( ",", $_tagIds ) . ')', 'limit' => array(0, IPSSearchRegistry::get('set.hardLimit') + 1), 'order' => 't.'.str_replace( 'post_date', 'topic_firstpost', $sortKey ) . ' ' . $sort_order, 'add_join' => array( array( 'select' => 'p.pid', 'from' => array( 'posts' => 'p' ), 'where' => 'p.pid=t.topic_firstpost', 'type' => 'left', ) ) ) ); $DB = $this->DB->execute(); /* Fetch all to merge and sort */ while( $r = $this->DB->fetch( $DB ) ) { if ( IPSSearchRegistry::searchTitleOnly() ) { $_rows[ $r['topic_id'] ] = $r; } else { $_rows[ $r['pid'] ] = $r; } } } } /* Fetch count */ $count = count( $_rows ); if ( $count > IPSSearchRegistry::get('set.hardLimit') ) { $count = IPSSearchRegistry::get('set.hardLimit'); IPSSearchRegistry::set('set.resultsCutToLimit', true ); } /* Set vars */ IPSSearch::$ask = $sortKey; IPSSearch::$aso = strtolower( $sort_order ); IPSSearch::$ast = $sortType; /* Sort */ if ( count( $_rows ) ) { usort( $_rows, array("IPSSearch", "usort") ); /* Build result array */ foreach( $_rows as $r ) { $c++; if ( IPSSearchRegistry::get('in.start') AND IPSSearchRegistry::get('in.start') >= $c ) { continue; } $rows[ $got ] = $r['id']; $got++; /* Done? */ if ( IPSSearchRegistry::get('opt.search_per_page') AND $got >= IPSSearchRegistry::get('opt.search_per_page') ) { break; } } } /* Return it */ return array( 'count' => $count, 'resultSet' => $rows ); } /** * Perform the search * Populates $this->_count and $this->_results * * @return nothin' */ public function viewUserContent( $member ) { $sort_by = IPSSearchRegistry::get('in.search_sort_by'); $sort_order = IPSSearchRegistry::get('in.search_sort_order'); switch( IPSSearchRegistry::get('in.userMode') ) { default: case 'all': IPSSearchRegistry::set('opt.searchType', 'both' ); IPSSearchRegistry::set('opt.noPostPreview' , true ); IPSSearchRegistry::set('set.returnType', 'tids' ); break; case 'title': IPSSearchRegistry::set('opt.searchType', 'titles' ); IPSSearchRegistry::set('opt.noPostPreview' , true ); IPSSearchRegistry::set('set.returnType', 'tids' ); break; case 'content': IPSSearchRegistry::set('opt.searchType', 'content' ); IPSSearchRegistry::set('opt.noPostPreview' , false ); IPSSearchRegistry::set('set.returnType', 'pids' ); break; } /* Sorting */ switch( $sort_by ) { default: case 'date': $sortKey = IPSSearchRegistry::get('opt.searchType') == 'content' ? 'p.post_date' : 't.last_post'; $sortType = 'numerical'; break; case 'title': $sortKey = 't.title'; $sortType = 'string'; break; case 'posts': $sortKey = 't.posts'; $sortType = 'numerical'; break; case 'views': $sortKey = 't.views'; $sortType = 'numerical'; break; } /* Init */ $start = IPSSearchRegistry::get('in.start'); $perPage = IPSSearchRegistry::get('opt.search_per_page'); /* Get list of good forum IDs */ $forumIdsOk = $this->registry->class_forums->fetchSearchableForumIds( $this->memberData['member_id'] ); //----------------------------------------- // No forums? //----------------------------------------- if( !count( $forumIdsOk ) ) { return array( 'count' => 0, 'resultSet' => array() ); } $topic_where[] = "t.forum_id IN (" . implode( ",", $forumIdsOk ) . ")"; if ( IPSSearchRegistry::get('in.userMode') != 'title' ) { $where[] = "p.author_id=" . intval( $member['member_id'] ); } if ( $this->settings['search_ucontent_days'] ) { if ( IPSSearchRegistry::get('in.userMode') != 'title' ) { $where[] = "p.post_date > " . ( ( $member['last_post'] ? $member['last_post'] : time() ) - ( 86400 * intval( $this->settings['search_ucontent_days'] ) ) ); } $topic_where[] = "t.last_post > " . ( ( $member['last_post'] ? $member['last_post'] : time() ) - ( 86400 * intval( $this->settings['search_ucontent_days'] ) ) ); } $where[] = "state != 'link'"; /* Set up perms */ $permissions = array(); $permissions['TopicSoftDeleteSee'] = $this->registry->getClass('class_forums')->canSeeSoftDeletedTopics( 0 ); $permissions['canQueue'] = $this->registry->getClass('class_forums')->canQueuePosts( 0 ); $permissions['PostSoftDeleteSee'] = $this->registry->getClass('class_forums')->canSeeSoftDeletedPosts( 0 ); $permissions['SoftDeleteReason'] = $this->registry->getClass('class_forums')->canSeeSoftDeleteReason( 0 ); $permissions['SoftDeleteContent'] = $this->registry->getClass('class_forums')->canSeeSoftDeleteContent( 0 ); /* Exclude some items */ if ( IPSSearchRegistry::get('in.userMode') != 'title' ) { if ( $permissions['SoftDeleteContent'] AND $permissions['PostSoftDeleteSee'] AND $permissions['canQueue'] ) { $where[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'hidden', 'sdeleted'), 'p.'); } else if ( $permissions['SoftDeleteContent'] AND $permissions['PostSoftDeleteSee'] ) { $where[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'sdeleted'), 'p.'); } else if ( $permissions['canQueue'] ) { $where[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'hidden'), 'p.'); } else { $where[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible' ), 'p.' ); } } if ( $permissions['TopicSoftDeleteSee'] AND $permissions['canQueue'] ) { $topic_where[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'hidden', 'sdeleted'), 't.' ); } else if ( $permissions['TopicSoftDeleteSee'] ) { $topic_where[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'sdeleted'), 't.' ); } else if ( $permissions['canQueue'] ) { $topic_where[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'hidden'), 't.' ); } else { $topic_where[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible' ), 't.' ); } /* Manual fetch if user content all */ if ( IPSSearchRegistry::get('in.userMode') == 'all' ) { /* init */ $pids = array(); $this->DB->build( array( 'select' => 't.tid, t.last_post, t.topic_firstpost', 'from' => 'topics t', 'where' => implode( ' AND ', $topic_where ) . " AND t.starter_id=" . intval( $member['member_id'] ), 'order' => $sortKey . ' ' . $sort_order, 'limit' => array(0, 1000 ) ) ); $this->DB->execute(); while( $t = $this->DB->fetch() ) { $pids[ $t['tid'] ] = $t['last_post']; } $where = ( array_merge( (array) $where, (array) $topic_where ) ); $where = implode( " AND ", $where ); /* Now for posts */ $this->DB->build( array( 'select' => 'p.pid', 'from' => array('posts' => 'p' ), 'where' => $where, 'add_join' => array( array( 'select' => 't.tid, t.last_post, t.topic_firstpost', 'from' => array( 'topics' => 't' ), 'where' => 'p.topic_id=t.tid', 'type' => 'left' ) ), 'order' => 'p.pid DESC', 'limit' => array( 0, 1000 ) ) ); $this->DB->execute(); while( $t = $this->DB->fetch() ) { $pids[ $t['tid'] ] = $t['last_post']; } $count = array( 'count' => count( $pids ) ); if ( $count['count'] ) { arsort( $pids, SORT_NUMERIC ); $tids = array_slice( array_keys( $pids ), $start, $perPage, true ); } } else if ( IPSSearchRegistry::get('in.userMode') == 'title' ) { $topic_where[] = "t.starter_id=" . intval( $member['member_id'] ); $where = ( array_merge( (array) $where, (array) $topic_where ) ); $where = implode( " AND ", $where ); /* Fetch the count */ $count = $this->DB->buildAndFetch( array( 'select' => 'COUNT(tid) as count', 'from' => 'topics t', 'where' => $where ) ); /* Fetch the count */ if ( $count['count'] ) { $this->DB->build( array( 'select' => 'tid', 'from' => 'topics t', 'where' => $where, 'order' => $sortKey . ' ' . $sort_order, 'limit' => array( $start, $perPage ) ) ); $inner = $this->DB->execute(); while( $row = $this->DB->fetch( $inner ) ) { $tids[ $row['tid'] ] = $row['tid']; } } } else { $where = ( array_merge( (array) $where, (array) $topic_where ) ); $where = implode( " AND ", $where ); /* Fetch the count */ $count = $this->DB->buildAndFetch( array( 'select' => 'COUNT(tid) as count', 'from' => array('topics' => 't' ), 'where' => $where, 'add_join' => array( array( 'from' => array( 'posts' => 'p' ), 'where' => 'p.topic_id=t.tid', 'type' => 'left' ) ) ) ); /* Fetch the count */ if ( $count['count'] ) { $this->DB->build( array( 'select' => 'tid', 'from' => array('topics' => 't' ), 'where' => $where, 'add_join' => array( array( 'select' => 'p.pid', 'from' => array( 'posts' => 'p' ), 'where' => 'p.topic_id=t.tid', 'type' => 'left' ) ), 'order' => $sortKey . ' ' . $sort_order, 'limit' => array( $start, $perPage ) ) ); $inner = $this->DB->execute(); while( $row = $this->DB->fetch( $inner ) ) { $tids[ $row['pid'] ] = $row['pid']; } } } /* Fix to 1000 results max */ $count['count'] = ( $count['count'] > 1000 ) ? 1000 : $count['count']; /* Return it */ return array( 'count' => $count['count'], 'resultSet' => $tids ); } /** * Perform the viewNewContent search * Forum Version * Populates $this->_count and $this->_results * * @return nothin' */ public function viewNewContent() { $rtids = array(); $oldStamp = $this->registry->getClass('classItemMarking')->fetchOldestUnreadTimestamp( array(), 'forums' ); $check = IPS_UNIX_TIME_NOW - ( 86400 * $this->settings['topic_marking_keep_days'] ); $forumIdsOk = array(); $where = array(); $_tidsOnly = array(); /* Loop through the forums and build a list of forums we're allowed access to */ $bvnp = explode( ',', $this->settings['vnp_block_forums'] ); $start = IPSSearchRegistry::get('in.start'); $perPage = IPSSearchRegistry::get('opt.search_per_page'); $seconds = IPSSearchRegistry::get('in.period_in_seconds'); $followedOnly = $this->memberData['member_id'] ? IPSSearchRegistry::get('in.vncFollowFilterOn' ) : false; $followedForums = array(); $followedTopics = array(); IPSSearchRegistry::set('in.search_sort_by' , 'date' ); IPSSearchRegistry::set('in.search_sort_order' , 'desc' ); IPSSearchRegistry::set('opt.searchType' , 'titles' ); IPSSearchRegistry::set('opt.noPostPreview' , true ); //----------------------------------------- // Only content we have participated in? //----------------------------------------- if( IPSSearchRegistry::get('in.userMode') ) { $_tempResults = $this->viewUserContent( $this->memberData ); if( $_tempResults['count'] ) { $_tidsOnly = array_merge( $_tidsOnly, $_tempResults['resultSet'] ); } else { return array( 'count' => 0, 'resultSet' => array() ); } switch( IPSSearchRegistry::get('in.userMode') ) { default: case 'all': case 'content': IPSSearchRegistry::set('opt.searchType', 'both' ); IPSSearchRegistry::set('opt.noPostPreview' , true ); break; case 'title': IPSSearchRegistry::set('opt.searchType', 'titles' ); IPSSearchRegistry::set('opt.noPostPreview' , false ); break; } } /* Set return type */ IPSSearchRegistry::set('set.returnType', 'tids' ); /* Get list of good forum IDs */ $_forumIdsOk = $this->registry->class_forums->fetchSearchableForumIds( $this->memberData['member_id'], ( $followedOnly ) ? array() : $bvnp ); /* Fetch forum rel ids */ if ( $followedOnly ) { require_once( IPS_ROOT_PATH . 'sources/classes/like/composite.php' );/*noLibHook*/ /* @link http://community.invisionpower.com/tracker/issue-33284-view-new-content-just-items-i-follow */ //$like = classes_like::bootstrap( 'forums', 'forums' ); //$followedForums = $like->getDataByMemberIdAndArea( $this->memberData['member_id'] ); $followedForums = array(); //( $followedForums === null ) ? array() : array_keys( $followedForums ); $like = classes_like::bootstrap( 'forums', 'topics' ); $followedTopics = $like->getDataByMemberIdAndArea( $this->memberData['member_id'] ); $followedTopics = ( $followedTopics === null ) ? array() : array_keys( $followedTopics ); } /* Period filtering */ if ( IPSSearchRegistry::get('in.period_in_seconds') !== false ) { $where[] = "last_post > " . ( IPS_UNIX_TIME_NOW - $seconds ); $forumIdsOk = $_forumIdsOk; } else { if ( intval( $this->memberData['_cache']['gb_mark__forums'] ) > 0 ) { $oldStamp = $this->memberData['_cache']['gb_mark__forums']; } /* Finalize times */ if ( ! $oldStamp OR $oldStamp == IPS_UNIX_TIME_NOW ) { $oldStamp = intval( $this->memberData['last_visit'] ); } /* Older than 3 months.. then limit */ if ( $oldStamp < $check ) { $oldStamp = $check; } foreach( $_forumIdsOk as $id ) { /*if ( $followedOnly && ! in_array( $id, $followedForums ) ) { // We don't want to skip followed topics just because we don't follow the forum continue; }*/ $lMarked = $this->registry->getClass('classItemMarking')->fetchTimeLastMarked( array( 'forumID' => $id ), 'forums' ); $fData = $this->registry->getClass('class_forums')->forumsFetchData( $id ); if ( $fData['last_post'] > $lMarked ) { $forumIdsOk[ $id ] = $id; } } /* If no forums, we're done */ if ( ! count( $forumIdsOk ) ) { /* Return it */ return array( 'count' => 0, 'resultSet' => array() ); } /* Based on oldest timestamp */ $where[] = "last_post > " . $oldStamp; } $forumIdsOk = ( count( $forumIdsOk ) ) ? $forumIdsOk : array( 0 => 0 ); /* Only show VNC results from specified forums? */ if( is_array(IPSSearchRegistry::get('forums.vncForumFilters')) AND count(IPSSearchRegistry::get('forums.vncForumFilters')) ) { $_newIdsOk = array(); foreach( IPSSearchRegistry::get('forums.vncForumFilters') as $forumId ) { if( in_array( $forumId, $forumIdsOk ) ) { $_newIdsOk[] = $forumId; } } $forumIdsOk = $_newIdsOk; } //----------------------------------------- // No forums? //----------------------------------------- if( !count( $forumIdsOk ) ) { return array( 'count' => 0, 'resultSet' => array() ); } $where[] = "forum_id IN (" . implode( ",", $forumIdsOk ) . ")"; /* Add in last bits */ $where[] = "state != 'link'"; /* Set up perms */ $permissions['TopicSoftDeleteSee'] = $this->registry->getClass('class_forums')->canSeeSoftDeletedTopics( 0 ); $permissions['canQueue'] = $this->registry->getClass('class_forums')->canQueuePosts( 0 ); if ( $permissions['TopicSoftDeleteSee'] AND $permissions['canQueue'] ) { $permWhere = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'hidden', 'sdeleted') ); } else if ( $permissions['TopicSoftDeleteSee'] ) { $permWhere = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'sdeleted') ); } else if ( $permissions['canQueue'] ) { $permWhere = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'hidden') ); } else { $permWhere = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible' ) ); } /* add perm */ $where[] = $permWhere; $_ffWhere = ''; /* Followed topics only? */ if ( $followedOnly ) { if ( ! count( $followedTopics ) && ! count( $followedForums ) ) { return array( 'count' => 0, 'resultSet' => array() ); } $_tidsOnly = array_merge( $_tidsOnly, $followedTopics ); if ( count( $followedForums ) ) { $_ffWhere = ' OR forum_id IN (' . implode( ',', $followedForums ) . ') '; } } /* This method allows us to have just one "tid IN()" clause, instead of two, depending on scenario */ if( count($_tidsOnly) AND count($followedTopics) ) { /* Only look for tids in both arrays */ $_both = array_intersect( $_tidsOnly, $followedTopics ); if( count($_both) ) { $where[] = "( tid IN(" . implode( ',', $_both ) . ')' . $_ffWhere . ' )'; } } else if( count($_tidsOnly) ) { $where[] = "( tid IN(" . implode( ',', $_tidsOnly ) . ')' . $_ffWhere . ' )'; } else if( count($followedTopics) ) { $where[] = "( tid IN(" . implode( ',', $followedTopics ) . ')' . $_ffWhere . ' )'; } $where = implode( " AND ", $where ); /* Fetch the count */ $count = $this->DB->buildAndFetch( array( 'select' => 'count(*) as count', 'from' => 'topics', 'where' => $where ) ); /* Fetch the count */ if ( $count['count'] ) { $limit = ( IPSSearchRegistry::get('in.period') != 'unread' ) ? array( $start, $perPage ) : array( 0, 1200 ); $this->DB->build( array( 'select' => 'tid, forum_id, last_post', 'from' => 'topics', 'where' => $where, 'order' => 'last_post DESC', 'limit' => $limit ) ); $inner = $this->DB->execute(); while( $row = $this->DB->fetch( $inner ) ) { $rtids[ $row['tid'] ] = $row; } } /* Set up some vars */ IPSSearchRegistry::set('set.resultCutToDate', $oldStamp ); if( IPSSearchRegistry::get('in.period') == 'unread' ) { $filter = $this->registry->class_forums->postProcessVncTids( $rtids, array( $start, $perPage ) ); $data['count'] = $filter['count']; $data['resultSet'] = $filter['tids']; } else { $data = array( 'count' => $count['count'], 'resultSet' => array_keys( $rtids) ); } /* Return it */ return $data; } /** * Builds the where portion of a search string * * @param string $search_term The string to use in the search * @param bool $content_title_only Search only title records * @param string $order Order by data * @param bool $onlyPosts Enforce posts only * @param bool $noForums Don't check forums that posts are in * @return string */ protected function _buildWhereStatement( $search_term, $content_title_only=false, $order='', $onlyPosts=null, $noForums=false ) { /* INI */ $where_clause = array(); $onlyPosts = ( $onlyPosts !== null ) ? $onlyPosts : ( IPSSearchRegistry::get('opt.searchType') == 'content' ); $sort_by = IPSSearchRegistry::get('in.search_sort_by'); $sort_order = IPSSearchRegistry::get('in.search_sort_order'); $sortKey = ''; $sortType = ''; $cType = IPSSearchRegistry::get('contextual.type'); $cId = IPSSearchRegistry::get('contextual.id' ); $search_tags = IPSSearchRegistry::get('in.raw_search_tags'); /* Loop through the forums and build a list of forums we're allowed access to */ $forumIdsOk = array(); $forumIdsBad = array(); if ( ! empty( ipsRegistry::$request['search_app_filters']['forums']['forums'] ) AND count( ipsRegistry::$request['search_app_filters']['forums']['forums'] ) ) { foreach( ipsRegistry::$request['search_app_filters']['forums']['forums'] as $forum_id ) { if( $forum_id ) { $data = $this->registry->class_forums->forum_by_id[ $forum_id ]; /* Check for sub forums */ $children = ipsRegistry::getClass( 'class_forums' )->forumsGetChildren( $forum_id ); foreach( $children as $kid ) { if( ! in_array( $kid, ipsRegistry::$request['search_app_filters']['forums']['forums'] ) ) { if( ! $this->registry->permissions->check( 'read', $this->registry->class_forums->forum_by_id[ $kid ] ) ) { $forumIdsBad[] = $kid; continue; } /* Can read, but is it password protected, etc? */ if ( ! $this->registry->class_forums->forumsCheckAccess( $kid, 0, 'forum', array(), true ) ) { $forumIdsBad[] = $kid; continue; } if ( ! $this->registry->class_forums->forum_by_id[ $kid ]['sub_can_post'] OR ! $this->registry->class_forums->forum_by_id[ $kid ]['can_view_others'] ) { $forumIdsBad[] = $kid; continue; } $forumIdsOk[] = $kid; } } /* Can we read? */ if ( ! $this->registry->permissions->check( 'view', $data ) ) { $forumIdsBad[] = $forum_id; continue; } /* Can read, but is it password protected, etc? */ if ( ! $this->registry->class_forums->forumsCheckAccess( $forum_id, 0, 'forum', array(), true ) ) { $forumIdsBad[] = $forum_id; continue; } if ( ( ! $data['sub_can_post'] OR ! $data['can_view_others'] ) AND !$this->memberData['g_access_cp'] ) { $forumIdsBad[] = $forum_id; continue; } $forumIdsOk[] = $forum_id; } } } if ( ! count($forumIdsOk) ) { /* Get list of good forum IDs */ $forumIdsOk = $this->registry->class_forums->fetchSearchableForumIds(); } /* Add allowed forums */ if ( $noForums !== true ) { $forumIdsOk = ( count( $forumIdsOk ) ) ? $forumIdsOk : array( 0 => 0 ); /* Contextual */ if ( $cType == 'forum' AND $cId AND in_array( $cId, $forumIdsOk ) ) { $where_clause[] = "t.forum_id=" . $cId; } else { $where_clause[] = "t.forum_id IN (" . implode( ",", $forumIdsOk ) . ")"; } } /* Topic contextual */ if ( $cType == 'topic' AND $cId ) { $where_clause[] = "t.tid=" . $cId; } /* Exclude some items */ $permissions = array(); $permissions['TopicSoftDeleteSee'] = $this->registry->getClass('class_forums')->canSeeSoftDeletedTopics( 0 ); $permissions['canQueue'] = $this->registry->getClass('class_forums')->canQueuePosts( 0 ); $permissions['PostSoftDeleteSee'] = $this->registry->getClass('class_forums')->canSeeSoftDeletedPosts( 0 ); $permissions['SoftDeleteReason'] = $this->registry->getClass('class_forums')->canSeeSoftDeleteReason( 0 ); $permissions['SoftDeleteContent'] = $this->registry->getClass('class_forums')->canSeeSoftDeleteContent( 0 ); if ( ! $content_title_only ) { if ( $permissions['SoftDeleteContent'] AND $permissions['PostSoftDeleteSee'] AND $permissions['canQueue'] ) { $where_clause[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'hidden', 'sdeleted'), 'p.'); } else if ( $permissions['SoftDeleteContent'] AND $permissions['PostSoftDeleteSee'] ) { $where_clause[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'sdeleted'), 'p.'); } else if ( $permissions['canQueue'] ) { $where_clause[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'hidden'), 'p.'); } else { $where_clause[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible' ), 'p.' ); } } if ( $permissions['SoftDeleteContent'] AND $permissions['TopicSoftDeleteSee'] AND $permissions['canQueue'] ) { $where_clause[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'hidden', 'sdeleted'), 't.'); } else if ( $permissions['SoftDeleteContent'] AND $permissions['TopicSoftDeleteSee'] ) { $where_clause[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'sdeleted'), 't.'); } else if ( $permissions['canQueue'] ) { $where_clause[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible', 'hidden'), 't.'); } else { $where_clause[] = $this->registry->class_forums->fetchTopicHiddenQuery(array('visible' ), 't.' ); } if( $search_term ) { $search_term = str_replace( '"', '"', $search_term ); if( $content_title_only ) { $where_clause[] = $this->DB->buildSearchStatement( 't.title', $search_term, true, false, ipsRegistry::$settings['use_fulltext'] ); IPSSearchRegistry::set('set.returnType', 'tids' ); } else { if ( $onlyPosts ) { $where_clause[] = $this->DB->buildSearchStatement( 'p.post', $search_term, true, false, ipsRegistry::$settings['use_fulltext'] ); IPSSearchRegistry::set('set.returnType', 'pids' ); } else { IPSSearchRegistry::set('set.returnType', 'pids' ); /* Sorting */ switch( $sort_by ) { default: case 'date': $sortKey = 'last_post'; $sortType = 'numerical'; break; case 'title': $sortKey = 'title'; $sortType = 'string'; break; case 'posts': $sortKey = 'posts'; $sortType = 'numerical'; break; case 'views': $sortKey = 'views'; $sortType = 'numerical'; break; } /* Set vars */ IPSSearch::$ask = $sortKey; IPSSearch::$aso = strtolower( $sort_order ); IPSSearch::$ast = $sortType; /* Find topic ids that match */ $tids = array( 0 => 0 ); $pids = array( 0 => 0 ); $this->DB->build( array('select' => "t.tid, t.last_post, t.forum_id", 'from' => 'topics t', 'where' => str_replace( 'p.author_id', 't.starter_id', $this->_buildWhereStatement( $search_term, true, $order, null ) ), 'order' => 't.' . $sortKey . ' ' . $sort_order, 'limit' => array(0, IPSSearchRegistry::get('set.hardLimit')) ) ); $i = $this->DB->execute(); /* Grab the results */ while( $row = $this->DB->fetch( $i ) ) { $_rows[ $row['tid'] ] = $row; } /* Sort */ if ( count( $_rows ) ) { usort( $_rows, array("IPSSearch", "usort") ); foreach( $_rows as $id => $row ) { $tids[] = $row['tid']; } } /* Now get the Pids */ if ( count( $tids ) > 1 ) { $this->DB->build( array('select' => 'pid', 'from' => 'posts', 'where' => 'topic_id IN ('. implode( ',', $tids ) . ') AND new_topic=1' ) ); $i = $this->DB->execute(); while( $row = $this->DB->fetch() ) { $pids[ $row['pid'] ] = $row['pid']; } } /* Set vars */ IPSSearch::$ask = ( $sortKey == 'last_post' ) ? 'post_date' : $sortKey; IPSSearch::$aso = strtolower( $sort_order ); IPSSearch::$ast = $sortType; $this->DB->build( array( 'select' => "p.pid, p.queued", 'from' => array( 'posts' => 'p' ), 'where' => $this->_buildWhereStatement( $search_term, false, $order, true ), 'order' => IPSSearch::$ask . ' ' . IPSSearch::$aso, 'limit' => array(0, IPSSearchRegistry::get('set.hardLimit')), 'add_join' => array( array( 'select' => 't.approved, t.forum_id', 'from' => array( 'topics' => 't' ), 'where' => 'p.topic_id=t.tid', 'type' => 'left' ) ) ) ); $i = $this->DB->execute(); /* Grab the results */ while( $row = $this->DB->fetch( $i ) ) { $_prows[ $row['pid'] ] = $row; } /* Sort */ if ( count( $_prows ) ) { usort( $_prows, array("IPSSearch", "usort") ); foreach( $_prows as $id => $row ) { $pids[ $row['pid'] ] = $row['pid']; } } $where_clause[] = '( p.pid IN (' . implode( ',', $pids ) .') )'; } } } /* No moved topic links */ $where_clause[] = "t.state != 'link'"; /* Date Restrict */ if( $this->search_begin_timestamp && $this->search_end_timestamp ) { $where_clause[] = $this->DB->buildBetween( $content_title_only ? "t.last_post" : "p.post_date", $this->search_begin_timestamp, $this->search_end_timestamp ); } else { if( $this->search_begin_timestamp ) { $where_clause[] = $content_title_only ? "t.last_post > {$this->search_begin_timestamp}" : "p.post_date > {$this->search_begin_timestamp}"; } if( $this->search_end_timestamp ) { $where_clause[] = $content_title_only ? "t.last_post < {$this->search_end_timestamp}" : "p.post_date < {$this->search_end_timestamp}"; } } /* Add in AND where conditions */ if( isset( $this->whereConditions['AND'] ) && count( $this->whereConditions['AND'] ) ) { $where_clause = array_merge( $where_clause, $this->whereConditions['AND'] ); } /* ADD in OR where conditions */ if( isset( $this->whereConditions['OR'] ) && count( $this->whereConditions['OR'] ) ) { $where_clause[] = '( ' . implode( ' OR ', $this->whereConditions['OR'] ) . ' )'; } /* Build and return the string */ return implode( " AND ", $where_clause ); } /** * Remap standard columns (Apps can override ) * * @param string $column sql table column for this condition * @return string column * @return @e void */ public function remapColumn( $column ) { $column = $column == 'member_id' ? ( IPSSearchRegistry::get('opt.searchTitleOnly') ? 't.starter_id' : 'p.author_id' ) : $column; $column = $column == 'content_title' ? 't.title' : $column; $column = $column == 'type_id' ? 't.forum_id' : $column; return $column; } /** * Returns an array used in the searchplugin's setCondition method * * @param array $data Array of forums to view * @return array Array with column, operator, and value keys, for use in the setCondition call */ public function buildFilterSQL( $data ) { /* INIT */ $return = array(); /* Set up some defaults */ IPSSearchRegistry::set( 'opt.noPostPreview' , true ); //IPSSearchRegistry::set( 'opt.searchType', 'both' ); /* Make default search type topics */ if( isset( $data ) && is_array( $data ) && count( $data ) ) { foreach( $data as $field => $_data ) { /* CONTENT ONLY */ if ( $field == 'noPreview' AND $_data['noPreview'] == 0 ) { IPSSearchRegistry::set( 'opt.noPostPreview', false ); } /* POST COUNT */ if ( $field == 'pCount' AND intval( $_data['pCount'] ) > 0 ) { $return[] = array( 'column' => 't.posts', 'operator' => '>=', 'value' => intval( $_data['pCount'] ) ); } /* TOPIC VIEWS */ if ( $field == 'pViews' AND intval( $_data ) > 0 ) { $return[] = array( 'column' => 't.views', 'operator' => '>=', 'value' => intval( $_data['pViews'] ) ); } } return $return; } else { return ''; } } }