/** * 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() { $start = intval(IPSSearchRegistry::get('in.start')); $perPage = IPSSearchRegistry::get('opt.search_per_page'); $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_type = IPSSearchRegistry::get('opt.searchType'); $search_tags = IPSSearchRegistry::get('in.raw_search_tags'); $search_ids = array(); $groupby = false; $cType = IPSSearchRegistry::get('contextual.type'); $cId = IPSSearchRegistry::get('contextual.id'); /* Contextual search */ if ($cType == 'topic') { $search_type = 'content'; IPSSearchRegistry::set('opt.searchType', 'content'); IPSSearchRegistry::set('opt.noPostPreview', false); } /* If searching tags, we don't show a preview */ if ($search_tags) { IPSSearchRegistry::set('opt.noPostPreview', true); IPSSearchRegistry::set('opt.searchType', 'titles'); $search_type = 'titles'; } /* Permissions */ $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); /* Sorting */ switch ($sort_by) { default: case 'date': $sortKey = 'last_post'; $sortKeyPost = 'post_date'; break; case 'title': $sortKeyPost = $sortKey = 'tordinal'; break; case 'posts': $sortKeyPost = $sortKey = 'posts'; break; case 'views': $sortKeyPost = $sortKey = 'views'; break; } /* Limit Results */ $this->sphinxClient->SetLimits(intval($start), $perPage); /* Loop through the forums and build a list of forums we're allowed access to */ if (is_array($this->searchForumIds) and count($this->searchForumIds)) { $forumIdsOk = $this->searchForumIds; } else { $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 */ $forumIdsOk = count($forumIdsOk) ? $forumIdsOk : array(0 => 0); /* Contextual */ if ($cType == 'forum' and $cId and in_array($cId, $forumIdsOk)) { $this->sphinxClient->SetFilter('forum_id', array($cId)); } else { $this->sphinxClient->SetFilter('forum_id', $forumIdsOk); } /* Topic contextual */ if ($cType == 'topic' and $cId) { $this->sphinxClient->SetFilter('tid', array($cId)); } /* Just show topics started by a member if we're search titles + member (#35289) */ if ($search_type == 'titles' && IPSSearchRegistry::get('in.search_author_id')) { $this->sphinxClient->SetFilter('starter_id', array(IPSSearchRegistry::get('in.search_author_id'))); } /* Exclude some items */ if ($search_type != 'titles') { if ($permissions['SoftDeleteContent'] and $permissions['PostSoftDeleteSee'] and $permissions['canQueue']) { $this->sphinxClient->SetFilter('queued', array(0, 1, 2)); } else { if ($permissions['SoftDeleteContent'] and $permissions['PostSoftDeleteSee']) { $this->sphinxClient->SetFilter('queued', array(0, 2)); } else { if ($permissions['canQueue']) { $this->sphinxClient->SetFilter('queued', array(0, 1)); } else { $this->sphinxClient->SetFilter('queued', array(0)); } } } } if ($permissions['SoftDeleteContent'] and $permissions['TopicSoftDeleteSee'] and $permissions['canQueue']) { $this->sphinxClient->SetFilter('approved', array(0, 1)); $this->sphinxClient->SetFilter('soft_deleted', array(0, 1)); } else { if ($permissions['SoftDeleteContent'] and $permissions['TopicSoftDeleteSee']) { $this->sphinxClient->SetFilter('approved', array(1)); $this->sphinxClient->SetFilter('soft_deleted', array(0, 1)); } else { if ($permissions['canQueue']) { $this->sphinxClient->SetFilter('soft_deleted', array(0)); $this->sphinxClient->SetFilter('approved', array(0, 1)); } else { $this->sphinxClient->SetFilter('soft_deleted', array(0)); $this->sphinxClient->SetFilter('approved', array(1)); } } } /* Archive search? */ if ($this->searchArchives) { $this->sphinxClient->SetFilter('archive_status', array(1)); } else { $this->sphinxClient->SetFilter('archive_status', array(0)); } /* Additional filters */ if (IPSSearchRegistry::get('opt.pCount')) { $this->sphinxClient->SetFilterRange('posts', intval(IPSSearchRegistry::get('opt.pCount')), 1500000000); } if (IPSSearchRegistry::get('opt.pViews')) { $this->sphinxClient->SetFilterRange('views', intval(IPSSearchRegistry::get('opt.pViews')), 1500000000); } /* Date limit */ if ($this->search_begin_timestamp) { if (!$this->search_end_timestamp) { $this->search_end_timestamp = time() + 100; } if ($search_type == 'titles') { $this->sphinxClient->SetFilterRange('start_date', $this->search_begin_timestamp, $this->search_end_timestamp); } else { $this->sphinxClient->SetFilterRange('post_date', $this->search_begin_timestamp, $this->search_end_timestamp); } } if (IPSSearchRegistry::get('opt.noPostPreview') or $search_type == 'titles') { $groupby = true; } /* Check tags */ $tagIds = array(); 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', 'isViewable' => true, 'sortOrder' => $sort_order)); foreach ($tags as $id => $data) { $tagIds[] = $data['tag_id']; } if ($search_term) { if (count($tagIds)) { $this->sphinxClient->SetFilter('tag_id', $tagIds); } } else { if (!$tagIds) { return array('count' => 0, 'resultSet' => array()); } else { /* We have tags but no search term, so just return the tids now */ IPSSearchRegistry::set('set.returnType', 'tids'); $tids = array(); $this->DB->build(array('select' => 'c.tag_meta_id', 'from' => array('core_tags' => 'c'), 'where' => 'c.tag_id IN (' . implode(',', $tagIds) . ')', 'order' => 'c.tag_added DESC', 'limit' => array(0, 1000), 'add_join' => array(array("select" => 't.title, t.posts, t.views, t.last_post', "from" => array('topics' => 't'), "where" => "c.tag_meta_id=t.tid", 'type' => 'left')))); $this->DB->execute(); $rows = array(); while ($row = $this->DB->fetch()) { $rows[] = $row; } /* Sorting */ switch ($sort_by) { default: case 'date': $sortKey = !IPSSearchRegistry::searchTitleOnly() ? $this->table['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; } IPSSearch::$ask = 'last_post'; IPSSearch::$aso = strtolower($sort_order); IPSSearch::$ast = 'numerical'; usort($rows, array("IPSSearch", "usort")); $c = 0; $got = 0; foreach ($rows as $row) { $c++; if (IPSSearchRegistry::get('in.start') and IPSSearchRegistry::get('in.start') >= $c) { continue; } $tids[] = $row['tag_meta_id']; $got++; /* Done? */ if (IPSSearchRegistry::get('opt.search_per_page') and $got >= IPSSearchRegistry::get('opt.search_per_page')) { break; } } return array('count' => count($rows), 'resultSet' => $tids); } } } /* Set sort order */ if ($sort_order == 'asc') { $this->sphinxClient->SetSortMode(SPH_SORT_ATTR_ASC, $sortKey); } else { $this->sphinxClient->SetSortMode(SPH_SORT_ATTR_DESC, $sortKey); } /* Generate sphinx search query */ switch ($search_type) { case 'titles': /* Group by */ if ($groupby) { /* @link http://community.invisionpower.com/topic/335036-sphinx-vncactive-content-sorting/ @link http://community.invisionpower.com/tracker/issue-34481-sphinx-sorting-broken/*/ $this->sphinxClient->SetGroupDistinct("tid"); $this->sphinxClient->SetGroupBy('tid', SPH_GROUPBY_ATTR, $sortKey . ' ' . $sort_order); } $_s = $search_term ? '@title ' . $search_term : ''; break; case 'content': /* Group by */ if ($groupby) { $this->sphinxClient->SetSortMode(SPH_SORT_EXTENDED, $sortKeyPost . ' DESC'); $this->sphinxClient->SetGroupBy('tid', SPH_GROUPBY_ATTR, $sortKey . ' ' . $sort_order); IPSSearchRegistry::set('set.searchResultType', 'both'); } $_s = $search_term ? '@' . $this->table['post'] . ' ' . $search_term : ''; break; case 'both': default: /* Group by */ if ($groupby) { $this->sphinxClient->SetSortMode(SPH_SORT_EXTENDED, $sortKeyPost . ' DESC'); $this->sphinxClient->SetGroupBy('tid', SPH_GROUPBY_ATTR, $sortKey . ' ' . $sort_order); } IPSSearchRegistry::set('set.searchResultType', 'both'); $_s = ($search_term and strstr($search_term, '"')) ? '@' . $this->table['post'] . ' ' . $search_term . ' | @title ' . $search_term : ($search_term ? '@(' . $this->table['post'] . ',title) ' . $search_term : ''); break; } /* Perform search */ $result = $this->sphinxClient->Query($_s, $this->settings['sphinx_prefix'] . $this->table['forums_search_posts_main'] . ', ' . $this->settings['sphinx_prefix'] . $this->table['forums_search_posts_delta']); /* Log errors */ $this->logSphinxWarnings(); /* Get result ids */ if (is_array($result['matches']) && count($result['matches'])) { $c = 0; foreach ($result['matches'] as $res) { $search_ids[] = $search_type == 'titles' && IPSSearchRegistry::get('set.searchResultType') != 'both' ? $res['attrs']['tid'] : $res['attrs']['search_id']; } } /* Set return type */ if ($search_type == 'titles' && IPSSearchRegistry::get('set.searchResultType') != 'both') { IPSSearchRegistry::set('set.returnType', 'tids'); } else { IPSSearchRegistry::set('set.returnType', 'pids'); } /* Return it */ return array('count' => intval($result['total_found']) > 1000 ? 1000 : $result['total_found'], 'resultSet' => $search_ids); }
/** * Formats / grabs extra data for results * Takes an array of IDS (can be IDs from anything) and returns an array of expanded data. * * @param array $ids Ids * @return array */ public function processResultsComments($ids) { /* INIT */ $sort_order = IPSSearchRegistry::get('in.search_sort_order'); $search_term = IPSSearchRegistry::get('in.clean_search_term'); $content_title_only = IPSSearchRegistry::get('opt.searchType') == 'content' ? false : true; $members = array(); $results = array(); $statusIds = array(); $replyIds = IPSSearchRegistry::get('_internal.replyIds'); $replyData = IPSSearchRegistry::get('_internal.replyData'); $replies = array(); $sortKey = ''; /* Got some? */ if (count($ids)) { /* Set vars */ IPSSearch::$ask = 'status_date'; IPSSearch::$aso = strtolower($sort_order); IPSSearch::$ast = 'numerical'; /* Get the status updates */ $this->DB->build(array('select' => "s.*", 'from' => array('member_status_updates' => 's'), 'where' => 's.status_id IN( ' . implode(',', $ids) . ')', 'add_join' => array_merge(array(array('select' => 'm.member_id as owner_id, m.members_display_name as owner_display_name, m.members_seo_name as owner_seo_name', 'from' => array('members' => 'm'), 'where' => 'm.member_id=s.status_member_id', 'type' => 'left'), array('select' => 'mem.member_id as author_id, mem.members_display_name as author_display_name, mem.members_seo_name as author_seo_name', 'from' => array('members' => 'mem'), 'where' => 'mem.member_id=s.status_author_id', 'type' => 'left'))))); /* Grab data */ $this->DB->execute(); /* Grab the results */ while ($row = $this->DB->fetch()) { $statusIds[$row['status_id']] = $row; } /* Sort */ if (count($statusIds)) { usort($statusIds, array("IPSSearch", "usort")); foreach ($statusIds as $id => $row) { /* Do we have any reply data? */ if (!empty($replyData[$id])) { $row = array_merge($row, $replyData[$id]); } /* Get author data? */ if (!empty($row['status_author_id'])) { $members[$row['status_author_id']] = $row['status_author_id']; } if (!empty($row['status_member_id'])) { $members[$row['status_member_id']] = $row['status_member_id']; } if (!empty($row['reply_member_id'])) { $members[$row['reply_member_id']] = $row['reply_member_id']; } $results[$row['status_id']] = $row; } } /* Need to load members? */ if (count($members)) { $mems = IPSMember::load($members, 'all'); foreach ($results as $id => $r) { $_status_member = IPSMember::buildDisplayData($mems[$r['status_member_id']], array('reputation' => 0, 'warn' => 0)); $_status_author = IPSMember::buildDisplayData($mems[$r['status_author_id']], array('reputation' => 0, 'warn' => 0)); $results[$id]['status_member'] = $_status_member; $results[$id]['status_author'] = $_status_author; if (!empty($r['reply_member_id'])) { $results[$id]['reply_author'] = IPSMember::buildDisplayData($mems[$r['reply_member_id']], array('reputation' => 0, 'warn' => 0)); } } } } return $results; }
/** * Formats / grabs extra data for results * Takes an array of IDS (can be IDs from anything) and returns an array of expanded data. * * @param array $ids Ids * @param array $followData Retrieve the follow meta data * @return array */ public function processResults($ids, $followData = array()) { /* 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'); $content_title_only = IPSSearchRegistry::searchTitleOnly(); $_post_joins = array(); $members = array(); $results = array(); $topicIds = array(); $dots = array(); $sortKey = ''; $sortType = ''; $_sdTids = array(); $_sdPids = array(); /* Set up some basic permissions */ $permissions['PostSoftDeleteSee'] = $this->registry->getClass('class_forums')->canSeeSoftDeletedPosts(0); $permissions['TopicSoftDeleteSee'] = $this->registry->getClass('class_forums')->canSeeSoftDeletedTopics(0); $permissions['canQueue'] = $this->registry->getClass('class_forums')->canQueuePosts(0); $permissions['SoftDeleteReason'] = $this->registry->getClass('class_forums')->canSeeSoftDeleteReason(0); $permissions['SoftDeleteContent'] = $this->registry->getClass('class_forums')->canSeeSoftDeleteContent(0); $permissions['PostSoftDeleteRestore'] = $this->registry->getClass('class_forums')->can_Un_SoftDeletePosts(0); $permissions['TopicSoftDeleteRestore'] = $this->registry->getClass('class_forums')->can_Un_SoftDeleteTopics(0); /* Got some? */ if (count($ids)) { /* Cache? */ if (IPSContentCache::isEnabled()) { if (IPSContentCache::fetchSettingValue('post')) { $_post_joins[] = IPSContentCache::join('post', 'p.' . $this->table['pid']); } if (IPSContentCache::fetchSettingValue('sig')) { $_post_joins[] = IPSContentCache::join('sig', 'p.' . $this->table['author_id'], 'ccb', 'left', 'ccb.cache_content as cache_content_sig, ccb.cache_updated as cache_updated_sig'); } } if ($this->registry->tags->isEnabled()) { $_post_joins[] = $this->registry->tags->getCacheJoin(array('meta_id_field' => 't.tid')); } /* Sorting */ switch ($sort_by) { default: case 'date': $sortKey = IPSSearchRegistry::get('set.returnType') == 'tids' ? 'last_post' : $this->table['post_date']; $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; /* If we are search in titles only, then the ID array will be TIDs */ if (IPSSearchRegistry::get('set.returnType') == 'tids') { $k = 'tid'; $this->DB->build(array('select' => "t.*", 'from' => array('topics' => 't'), 'where' => 't.tid IN( ' . implode(',', $ids) . ')', 'add_join' => array_merge(array(array('select' => 'p.*', 'from' => array($this->table['_table_'] => 'p'), 'where' => 'p.' . $this->table['pid'] . '=t.topic_firstpost', 'type' => 'left'), array('select' => 'm.member_id, m.members_display_name, m.members_seo_name', 'from' => array('members' => 'm'), 'where' => 'm.member_id=p.' . $this->table['author_id'], 'type' => 'left')), $_post_joins))); } else { $k = $this->table['pid']; $this->DB->build(array('select' => "p.*", 'from' => array($this->table['_table_'] => 'p'), 'where' => 'p.' . $this->table['pid'] . ' IN( ' . implode(',', $ids) . ')', 'add_join' => array_merge(array(array('select' => 't.*', 'from' => array('topics' => 't'), 'where' => 't.tid=p.' . $this->table['topic_id'], 'type' => 'left'), array('select' => 'm.member_id, m.members_display_name, m.members_seo_name', 'from' => array('members' => 'm'), 'where' => 'm.member_id=p.' . $this->table['author_id'], 'type' => 'left')), $_post_joins))); } /* Grab data */ $this->DB->execute(); /* Grab the results */ while ($row = $this->DB->fetch()) { $_rows[$row[$k]] = $this->searchArchives ? $this->archiveReader->archiveToNativeFields($row) : $row; } /* Get the 'follow' meta data? */ if (count($followData)) { $followData = classes_like_meta::get($followData); /* Merge the data from the follow class into the results */ foreach ($followData as $_formatted) { $_rows[$_formatted['like_rel_id']]['_followData'] = $_formatted; } } /* Sort */ if (count($_rows)) { usort($_rows, array("IPSSearch", "usort")); foreach ($_rows as $id => $row) { /* Prevent member from stepping on it */ $row['topic_title'] = $row['title']; /* Get author data? */ if ($k == 'tid') { if (!empty($row['last_poster_id'])) { $members[$row['last_poster_id']] = $row['last_poster_id']; } } else { if (!empty($row['author_id'])) { $members[$row['author_id']] = $row['author_id']; } } /* Topic ids? */ if (!empty($row['topic_id'])) { $topicIds[$row['topic_id']] = $row['topic_id']; } /* If we're using sphinx, check forum permissions again as the 15 minute delta rebuild could expose a moved topic before deltas rebuild. We don't need to do this for SQL search as the results are delivered live and lets face it, we can do without the load */ if ($this->settings['search_method'] != 'traditional') { /* Can we read? */ if (!$this->registry->permissions->check('view', $this->registry->class_forums->forum_by_id[$row['forum_id']])) { continue; } /* Can read, but is it password protected, etc? */ if (!$this->registry->class_forums->forumsCheckAccess($row['forum_id'], 0, 'forum', array(), true)) { continue; } } $row['cleanSearchTerm'] = urlencode($search_term); $row['topicPrefix'] = $row['pinned'] ? $this->registry->getClass('output')->getTemplate('forum')->topicPrefixWrap($this->lang->words['pre_pinned']) : ''; $row['_isVisible'] = $this->registry->getClass('class_forums')->fetchHiddenTopicType($row) == 'visible' ? true : false; $row['_isHidden'] = $this->registry->getClass('class_forums')->fetchHiddenTopicType($row) == 'hidden' ? true : false; $row['_isDeleted'] = $this->registry->getClass('class_forums')->fetchHiddenTopicType($row) == 'sdelete' ? true : false; $row['_p_isVisible'] = $this->registry->getClass('class_forums')->fetchHiddenType($row) == 'visible' ? true : false; $row['_p_isHidden'] = $this->registry->getClass('class_forums')->fetchHiddenType($row) == 'hidden' ? true : false; $row['_p_isDeleted'] = $this->registry->getClass('class_forums')->fetchHiddenType($row) == 'sdelete' ? true : false; /* Hidden and we do not have permission? */ if ($row['_isHidden'] and !$permissions['canQueue']) { continue; } /* Is the topic deleted? If so, then the first post will appear as such */ if ($row['_isDeleted'] and $permissions['TopicSoftDeleteSee']) { $row['_p_isDeleted'] = true; $_sdPids[$row['pid']] = $row['pid']; } /* Collect TIDS of soft deleted topics */ if ($row['_isDeleted']) { if ($permissions['TopicSoftDeleteSee']) { $_sdTids[$row['tid']] = $row['tid']; } else { continue; } } /* Collect TIDS of soft deleted topics */ if ($row['_p_isDeleted']) { if ($permissions['PostSoftDeleteSee']) { $_sdPids[$row['pid']] = $row['pid']; } else { continue; } } /* Tags */ if (!empty($row['tag_cache_key'])) { $row['tags'] = $this->registry->tags->formatCacheJoinData($row); } $results[$k == 'tid' ? $row['tid'] : $row['pid']] = $this->genericizeResults($row); } } /* Need to load members? */ if (count($members)) { $mems = IPSMember::load($members, 'all'); $mems[0] = array(); foreach ($results as $id => $r) { $_memberIdColumn = IPSSearchRegistry::get('set.returnType') == 'tids' ? 'last_poster_id' : 'author_id'; if (isset($mems[$r[$_memberIdColumn]])) { $mems[$r[$_memberIdColumn]]['m_posts'] = $mems[$r[$_memberIdColumn]]['posts']; unset($mems[$r[$_memberIdColumn]]['last_post']); if (isset($r['cache_content_sig'])) { $mems[$r[$_memberIdColumn]]['cache_content'] = $r['cache_content_sig']; $mems[$r[$_memberIdColumn]]['cache_updated'] = $r['cache_updated_sig']; } $_mem = IPSMember::buildDisplayData($mems[$r[$_memberIdColumn]], array('reputation' => 0, 'warn' => 0)); unset($_mem['cache_content'], $_mem['cache_updated']); $results[$id]['_realPosts'] = $results[$id]['posts']; $results[$id] = array_merge($results[$id], $_mem); $results[$id]['posts'] = $results[$id]['_realPosts']; } } } /* Generate 'dot' folder icon */ if ($this->settings['show_user_posted'] and count($topicIds)) { $_queued = $this->registry->class_forums->fetchPostHiddenQuery(array('visible'), ''); $this->DB->build(array('select' => 'author_id, topic_id', 'from' => 'posts', 'where' => $_queued . ' AND author_id=' . $this->memberData['member_id'] . ' AND topic_id IN(' . implode(',', $topicIds) . ')')); $this->DB->execute(); while ($p = $this->DB->fetch()) { $dots[$p['topic_id']] = 1; } /* Merge into results */ foreach ($results as $id => $r) { if (isset($dots[$r['topic_id']])) { $results[$id]['_hasPosted'] = 1; } } } /* Got any deleted items */ if (count($_sdTids)) { $sData = IPSDeleteLog::fetchEntries($_sdTids, 'topic', false); if (count($sData)) { foreach ($results as $id => $data) { if (isset($_sdTids[$data['tid']])) { $results[$id]['sData'] = $sData[$data['tid']]; $results[$id]['permissions'] = $permissions; } } } } /* Got any deleted items */ if (count($_sdPids)) { $sData = IPSDeleteLog::fetchEntries($_sdPids, 'post', false); if (count($sData)) { foreach ($results as $id => $data) { if (isset($_sdPids[$data['pid']]) and !isset($results[$id]['sData'])) { $results[$id]['sData'] = $sData[$data['pid']]; $results[$id]['permissions'] = $permissions; } } } } } return $results; }
/** * 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'), $this->table['_prefix_']); } else { if ($permissions['SoftDeleteContent'] and $permissions['PostSoftDeleteSee']) { $where_clause[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'sdeleted'), $this->table['_prefix_']); } else { if ($permissions['canQueue']) { $where_clause[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible', 'hidden'), $this->table['_prefix_']); } else { $where_clause[] = $this->registry->class_forums->fetchPostHiddenQuery(array('visible'), $this->table['_prefix_']); } } } } 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.'); } } } /* Live or archived? */ if ($this->searchArchives) { $where_clause[] = $this->registry->class_forums->fetchTopicArchiveQuery(array('working', 'archived'), 't.'); } else { $where_clause[] = $this->registry->class_forums->fetchTopicArchiveQuery(array('not', 'exclude'), '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.' . $this->table['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.' . $this->table['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' => $this->table['pid'], 'from' => $this->table['_table_'], 'where' => $this->table['topic_id'] . ' IN (' . implode(',', $tids) . ') AND ' . $this->table['new_topic'] . '=1')); $i = $this->DB->execute(); while ($row = $this->DB->fetch()) { $pids[$row[$this->table['pid']]] = $row[$this->table['pid']]; } } /* Set vars */ IPSSearch::$ask = $sortKey == 'last_post' ? $this->table['post_date'] : $sortKey; IPSSearch::$aso = strtolower($sort_order); IPSSearch::$ast = $sortType; $this->DB->build(array('select' => "p.{$this->table['pid']}, p.{$this->table['queued']}", 'from' => array($this->table['_table_'] => '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.' . $this->table['topic_id'] . '=t.tid', 'type' => 'left')))); $i = $this->DB->execute(); /* Grab the results */ while ($row = $this->DB->fetch($i)) { $_prows[$row[$this->table['pid']]] = $row; } /* Sort */ if (count($_prows)) { usort($_prows, array("IPSSearch", "usort")); foreach ($_prows as $id => $row) { $pids[$row[$this->table['pid']]] = $row[$this->table['pid']]; } } $where_clause[] = '( p.' . $this->table['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." . $this->table['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." . $this->table['post_date'] . " > {$this->search_begin_timestamp}"; } if ($this->search_end_timestamp) { $where_clause[] = $content_title_only ? "t.last_post < {$this->search_end_timestamp}" : "p." . $this->table['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); }
/** * Builds the where portion of a search string * * @param string $search_term The string to use in the search * @param bool $searchType Search only title records * @return string */ protected function _buildCommentsWhereStatement($search_term, $searchType = null) { /* INI */ $where_clause = array(); $searchType = $searchType === null ? IPSSearchRegistry::get('opt.searchType') : $searchType; $sort_order = IPSSearchRegistry::get('in.search_sort_order'); if ($search_term) { if ($searchType == 'titles') { $where_clause[] = $this->DB->buildSearchStatement('s.status_content', $search_term, true, false, false); } else { if ($searchType == 'content') { $where_clause[] = $this->DB->buildSearchStatement('r.reply_content', $search_term, true, false, false); } else { /* Set vars */ IPSSearch::$ask = 'status_date'; IPSSearch::$aso = strtolower($sort_order); IPSSearch::$ast = 'numerical'; /* Find topic ids that match */ $tids = array(); $pids = array(); $this->DB->build(array('select' => "s.status_id, s.status_date", 'from' => 'member_status_updates s', 'where' => $this->_buildCommentsWhereStatement($search_term, 'titles'), 'order' => 's.status_date ' . $sort_order, 'limit' => array(0, IPSSearchRegistry::get('set.hardLimit')))); $i = $this->DB->execute(); /* Grab the results */ while ($row = $this->DB->fetch($i)) { $_rows[$row['status_id']] = $row; } /* Sort */ if (count($_rows)) { usort($_rows, array("IPSSearch", "usort")); foreach ($_rows as $id => $row) { $tids[] = $row['status_id']; } } /* Set vars */ IPSSearch::$ask = 'reply_date'; IPSSearch::$aso = strtolower($sort_order); IPSSearch::$ast = 'numerical'; $this->DB->build(array('select' => "r.reply_id, r.reply_date, r.reply_status_id as status_id", 'from' => array('member_status_replies' => 'r'), 'add_join' => array(array('select' => 's.status_id, s.status_member_id, s.status_author_id', 'from' => array('member_status_updates' => 's'), 'where' => 's.status_id=r.reply_status_id', 'type' => 'left')), 'where' => $this->_buildCommentsWhereStatement($search_term, 'content'), 'order' => IPSSearch::$ask . ' ' . IPSSearch::$aso, 'limit' => array(0, IPSSearchRegistry::get('set.hardLimit')))); $i = $this->DB->execute(); /* Grab the results */ while ($row = $this->DB->fetch($i)) { $tids[] = $row['status_id']; $pids[] = $row['reply_id']; } if (count($pids)) { IPSSearchRegistry::set('_internal.replyIds', $pids); } $where_clause[] = '( s.status_id IN (' . (count($tids) ? implode(',', $tids) : 0) . ') )'; } } } /* 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']) . ' )'; } /* Date Restrict */ if ($this->search_begin_timestamp && $this->search_end_timestamp) { $where_clause[] = $this->DB->buildBetween($searchType == 'content' ? "r.reply_date" : "s.status_date", $this->search_begin_timestamp, $this->search_end_timestamp); } else { if ($this->search_begin_timestamp) { $where_clause[] = $searchType == 'content' ? "r.reply_date > {$this->search_begin_timestamp}" : "s.status_date > {$this->search_begin_timestamp}"; } if ($this->search_end_timestamp) { $where_clause[] = $searchType == 'content' ? "r.reply_date < {$this->search_end_timestamp}" : "s.status_date < {$this->search_end_timestamp}"; } } /* Build and return the string */ return implode(" AND ", $where_clause); }