/**
 * Perform a thread and post search under MySQL or MySQLi
 *
 * @param array Array of search data
 * @return array Array of search data with results mixed in
 */
function perform_search_mysql($search)
{
    global $mybb, $db, $lang;
    $keywords = clean_keywords($search['keywords']);
    if (!$keywords && !$search['author']) {
        error($lang->error_nosearchterms);
    }
    if ($mybb->settings['minsearchword'] < 1) {
        $mybb->settings['minsearchword'] = 3;
    }
    if ($keywords) {
        // Complex search
        $keywords = " {$keywords} ";
        if (preg_match("# and|or #", $keywords)) {
            $subject_lookin = " AND (";
            $message_lookin = " AND (";
            // Expand the string by double quotes
            $keywords_exp = explode("\"", $keywords);
            $inquote = false;
            foreach ($keywords_exp as $phrase) {
                // If we're not in a double quoted section
                if (!$inquote) {
                    // Expand out based on search operators (and, or)
                    $matches = preg_split("#\\s{1,}(and|or)\\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
                    $count_matches = count($matches);
                    for ($i = 0; $i < $count_matches; ++$i) {
                        $word = trim($matches[$i]);
                        if (empty($word)) {
                            continue;
                        }
                        // If this word is a search operator set the boolean
                        if ($i % 2 && ($word == "and" || $word == "or")) {
                            $boolean = $word;
                        } else {
                            $word = trim($word);
                            // Word is too short - show error message
                            if (my_strlen($word) < $mybb->settings['minsearchword']) {
                                $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
                                error($lang->error_minsearchlength);
                            }
                            // Add terms to search query
                            $subject_lookin .= " {$boolean} LOWER(t.subject) LIKE '%{$word}%'";
                            if ($search['postthread'] == 1) {
                                $message_lookin .= " {$boolean} LOWER(p.message) LIKE '%{$word}%'";
                            }
                        }
                    }
                } else {
                    $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
                    if (my_strlen($phrase) < $mybb->settings['minsearchword']) {
                        $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
                        error($lang->error_minsearchlength);
                    }
                    // Add phrase to search query
                    $subject_lookin .= " {$boolean} LOWER(t.subject) LIKE '%{$phrase}%'";
                    if ($search['postthread'] == 1) {
                        $message_lookin .= " {$boolean} LOWER(p.message) LIKE '%{$phrase}%'";
                    }
                }
                $inquote = !$inquote;
            }
            $subject_lookin .= ")";
            $message_lookin .= ")";
        } else {
            $keywords = str_replace("\"", '', trim($keywords));
            if (my_strlen($keywords) < $mybb->settings['minsearchword']) {
                $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
                error($lang->error_minsearchlength);
            }
            $subject_lookin = " AND LOWER(t.subject) LIKE '%{$keywords}%'";
            if ($search['postthread'] == 1) {
                $message_lookin = " AND LOWER(p.message) LIKE '%{$keywords}%'";
            }
        }
    }
    $post_usersql = '';
    $thread_usersql = '';
    if ($search['author']) {
        $userids = array();
        if ($search['matchusername']) {
            $query = $db->simple_select("users", "uid", "username='******'author']) . "'");
        } else {
            $search['author'] = my_strtolower($search['author']);
            $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%" . $db->escape_string_like($db->escape_string($search['author'])) . "%'");
        }
        while ($user = $db->fetch_array($query)) {
            $userids[] = $user['uid'];
        }
        if (count($userids) < 1) {
            error($lang->error_nosearchresults);
        } else {
            $userids = implode(',', $userids);
            $post_usersql = " AND p.uid IN (" . $userids . ")";
            $thread_usersql = " AND t.uid IN (" . $userids . ")";
        }
    }
    $datecut = '';
    if ($search['postdate']) {
        if ($search['pddir'] == 0) {
            $datecut = "<=";
        } else {
            $datecut = ">=";
        }
        $now = TIME_NOW;
        $datelimit = $now - 86400 * $search['postdate'];
        $datecut .= "'{$datelimit}'";
        $post_datecut = " AND p.dateline {$datecut}";
        $thread_datecut = " AND t.dateline {$datecut}";
    }
    $thread_replycut = '';
    if ($search['numreplies'] != '' && $search['findthreadst']) {
        if (intval($search['findthreadst']) == 1) {
            $thread_replycut = " AND t.replies >= '" . intval($search['numreplies']) . "'";
        } else {
            $thread_replycut = " AND t.replies <= '" . intval($search['numreplies']) . "'";
        }
    }
    $forumin = '';
    $fidlist = array();
    $searchin = array();
    if ($search['forums'] != "all") {
        if (!is_array($search['forums'])) {
            $search['forums'] = array(intval($search['forums']));
        }
        foreach ($search['forums'] as $forum) {
            if (!$searchin[$forum]) {
                $forum = intval($forum);
                switch ($db->type) {
                    case "pgsql":
                        $query = $db->query("\n\t\t\t\t\t\t\tSELECT DISTINCT f.fid \n\t\t\t\t\t\t\tFROM " . TABLE_PREFIX . "forums f \n\t\t\t\t\t\t\tLEFT JOIN " . TABLE_PREFIX . "forumpermissions p ON (f.fid=p.fid AND p.gid='" . $mybb->user['usergroup'] . "')\n\t\t\t\t\t\t\tWHERE (','||parentlist||',' LIKE ',%{$forum}%,') = true AND active!=0 AND (p.fid IS NULL OR p.cansearch=1)\n\t\t\t\t\t\t");
                        break;
                    case "sqlite3":
                    case "sqlite2":
                        $query = $db->query("\n\t\t\t\t\t\t\tSELECT DISTINCT f.fid \n\t\t\t\t\t\t\tFROM " . TABLE_PREFIX . "forums f \n\t\t\t\t\t\t\tLEFT JOIN " . TABLE_PREFIX . "forumpermissions p ON (f.fid=p.fid AND p.gid='" . $mybb->user['usergroup'] . "')\n\t\t\t\t\t\t\tWHERE (','||parentlist||',' LIKE ',%{$forum}%,') > 0 AND active!=0 AND (p.fid = NULL OR p.cansearch=1)\n\t\t\t\t\t\t");
                        break;
                    default:
                        $query = $db->query("\n\t\t\t\t\t\t\tSELECT DISTINCT f.fid \n\t\t\t\t\t\t\tFROM " . TABLE_PREFIX . "forums f \n\t\t\t\t\t\t\tLEFT JOIN " . TABLE_PREFIX . "forumpermissions p ON (f.fid=p.fid AND p.gid='" . $mybb->user['usergroup'] . "')\n\t\t\t\t\t\t\tWHERE INSTR(CONCAT(',',parentlist,','),',{$forum},') > 0 AND active!=0 AND (ISNULL(p.fid) OR p.cansearch=1)\n\t\t\t\t\t\t");
                }
                while ($sforum = $db->fetch_array($query)) {
                    $fidlist[] = $sforum['fid'];
                }
            }
        }
        if (count($fidlist) == 1) {
            $forumin .= " AND t.fid='{$forum}' ";
            $searchin[$fid] = 1;
        } else {
            if (count($fidlist) > 1) {
                $forumin = " AND t.fid IN (" . implode(',', $fidlist) . ")";
            }
        }
    }
    $unsearchforums = get_unsearchable_forums();
    if ($unsearchforums) {
        $permsql = " AND t.fid NOT IN ({$unsearchforums})";
    }
    $inactiveforums = get_inactive_forums();
    if ($inactiveforums) {
        $permsql .= " AND t.fid NOT IN ({$inactiveforums})";
    }
    // Searching a specific thread?
    if ($search['tid']) {
        $tidsql = " AND t.tid='" . intval($search['tid']) . "'";
    }
    $limitsql = '';
    if (intval($mybb->settings['searchhardlimit']) > 0) {
        $limitsql = "LIMIT " . intval($mybb->settings['searchhardlimit']);
    }
    // Searching both posts and thread titles
    $threads = array();
    $posts = array();
    $firstposts = array();
    if ($search['postthread'] == 1) {
        // No need to search subjects when looking for results within a specific thread
        if (!$search['tid']) {
            $query = $db->query("\n\t\t\t\tSELECT t.tid, t.firstpost\n\t\t\t\tFROM " . TABLE_PREFIX . "threads t\n\t\t\t\tWHERE 1=1 {$thread_datecut} {$thread_replycut} {$forumin} {$thread_usersql} {$permsql} AND t.visible >= '0' AND t.closed NOT LIKE 'moved|%' {$subject_lookin}\n\t\t\t\t{$limitsql}\n\t\t\t");
            while ($thread = $db->fetch_array($query)) {
                $threads[$thread['tid']] = $thread['tid'];
                if ($thread['firstpost']) {
                    $posts[$thread['tid']] = $thread['firstpost'];
                }
            }
        }
        $query = $db->query("\n\t\t\tSELECT p.pid, p.tid\n\t\t\tFROM " . TABLE_PREFIX . "posts p\n\t\t\tLEFT JOIN " . TABLE_PREFIX . "threads t ON (t.tid=p.tid)\n\t\t\tWHERE 1=1 {$post_datecut} {$thread_replycut} {$forumin} {$post_usersql} {$permsql} {$tidsql} AND p.visible >= '0' AND t.visible >= '0' AND t.closed NOT LIKE 'moved|%' {$message_lookin}\n\t\t\t{$limitsql}\n\t\t");
        while ($post = $db->fetch_array($query)) {
            $posts[$post['pid']] = $post['pid'];
            $threads[$post['tid']] = $post['tid'];
        }
        if (count($posts) < 1 && count($threads) < 1) {
            error($lang->error_nosearchresults);
        }
        $threads = implode(',', $threads);
        $posts = implode(',', $posts);
    } else {
        $query = $db->query("\n\t\t\tSELECT t.tid, t.firstpost\n\t\t\tFROM " . TABLE_PREFIX . "threads t\n\t\t\tWHERE 1=1 {$thread_datecut} {$thread_replycut} {$forumin} {$thread_usersql} {$permsql} AND t.visible >= '0' {$subject_lookin}\n\t\t\t{$limitsql}\n\t\t");
        while ($thread = $db->fetch_array($query)) {
            $threads[$thread['tid']] = $thread['tid'];
            if ($thread['firstpost']) {
                $firstposts[$thread['tid']] = $thread['firstpost'];
            }
        }
        if (count($threads) < 1) {
            error($lang->error_nosearchresults);
        }
        $threads = implode(',', $threads);
        $firstposts = implode(',', $firstposts);
        if ($firstposts) {
            $query = $db->simple_select("posts", "pid", "pid IN ({$firstposts}) AND visible >= '0' {$limitsql}");
            while ($post = $db->fetch_array($query)) {
                $posts[$post['pid']] = $post['pid'];
            }
            $posts = implode(',', $posts);
        }
    }
    return array("threads" => $threads, "posts" => $posts, "querycache" => '');
}
Exemple #2
0
/**
 * Perform a thread and post search under MySQL or MySQLi
 *
 * @param array Array of search data
 * @return array Array of search data with results mixed in
 */
function perform_search_mysql($search)
{
    global $mybb, $db, $lang, $cache;
    $keywords = clean_keywords($search['keywords']);
    if (!$keywords && !$search['author']) {
        error($lang->error_nosearchterms);
    }
    if ($mybb->settings['minsearchword'] < 1) {
        $mybb->settings['minsearchword'] = 3;
    }
    if ($keywords) {
        // Complex search
        $keywords = " {$keywords} ";
        if (preg_match("#\\s(and|or)\\s#", $keywords)) {
            $subject_lookin = " AND (";
            $message_lookin = " AND (";
            // Expand the string by double quotes
            $keywords_exp = explode("\"", $keywords);
            $inquote = false;
            $boolean = '';
            foreach ($keywords_exp as $phrase) {
                // If we're not in a double quoted section
                if (!$inquote) {
                    // Expand out based on search operators (and, or)
                    $matches = preg_split("#\\s{1,}(and|or)\\s{1,}#", $phrase, -1, PREG_SPLIT_DELIM_CAPTURE);
                    $count_matches = count($matches);
                    for ($i = 0; $i < $count_matches; ++$i) {
                        $word = trim($matches[$i]);
                        if (empty($word)) {
                            continue;
                        }
                        // If this word is a search operator set the boolean
                        if ($i % 2 && ($word == "and" || $word == "or")) {
                            if ($i <= 1 && $subject_lookin == " AND (") {
                                continue;
                            }
                            $boolean = $word;
                        } else {
                            $word = trim($word);
                            // Word is too short - show error message
                            if (my_strlen($word) < $mybb->settings['minsearchword']) {
                                $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
                                error($lang->error_minsearchlength);
                            }
                            // Add terms to search query
                            $subject_lookin .= " {$boolean} LOWER(t.subject) LIKE '%{$word}%'";
                            if ($search['postthread'] == 1) {
                                $message_lookin .= " {$boolean} LOWER(p.message) LIKE '%{$word}%'";
                            }
                            $boolean = 'AND';
                        }
                    }
                } else {
                    $phrase = str_replace(array("+", "-", "*"), '', trim($phrase));
                    if (my_strlen($phrase) < $mybb->settings['minsearchword']) {
                        $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
                        error($lang->error_minsearchlength);
                    }
                    // Add phrase to search query
                    $subject_lookin .= " {$boolean} LOWER(t.subject) LIKE '%{$phrase}%'";
                    if ($search['postthread'] == 1) {
                        $message_lookin .= " {$boolean} LOWER(p.message) LIKE '%{$phrase}%'";
                    }
                    $boolean = 'AND';
                }
                if ($subject_lookin == " AND (") {
                    // There are no search keywords to look for
                    $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
                    error($lang->error_minsearchlength);
                }
                $inquote = !$inquote;
            }
            $subject_lookin .= ")";
            $message_lookin .= ")";
        } else {
            $keywords = str_replace("\"", '', trim($keywords));
            if (my_strlen($keywords) < $mybb->settings['minsearchword']) {
                $lang->error_minsearchlength = $lang->sprintf($lang->error_minsearchlength, $mybb->settings['minsearchword']);
                error($lang->error_minsearchlength);
            }
            $subject_lookin = " AND LOWER(t.subject) LIKE '%{$keywords}%'";
            if ($search['postthread'] == 1) {
                $message_lookin = " AND LOWER(p.message) LIKE '%{$keywords}%'";
            }
        }
    }
    $post_usersql = '';
    $thread_usersql = '';
    if ($search['author']) {
        $userids = array();
        if ($search['matchusername']) {
            $query = $db->simple_select("users", "uid", "username='******'author']) . "'");
        } else {
            $search['author'] = my_strtolower($search['author']);
            $query = $db->simple_select("users", "uid", "LOWER(username) LIKE '%" . $db->escape_string_like($search['author']) . "%'");
        }
        while ($user = $db->fetch_array($query)) {
            $userids[] = $user['uid'];
        }
        if (count($userids) < 1) {
            error($lang->error_nosearchresults);
        } else {
            $userids = implode(',', $userids);
            $post_usersql = " AND p.uid IN (" . $userids . ")";
            $thread_usersql = " AND t.uid IN (" . $userids . ")";
        }
    }
    $datecut = '';
    if ($search['postdate']) {
        if ($search['pddir'] == 0) {
            $datecut = "<=";
        } else {
            $datecut = ">=";
        }
        $now = TIME_NOW;
        $datelimit = $now - 86400 * $search['postdate'];
        $datecut .= "'{$datelimit}'";
        $post_datecut = " AND p.dateline {$datecut}";
        $thread_datecut = " AND t.dateline {$datecut}";
    }
    $thread_replycut = '';
    if ($search['numreplies'] != '' && $search['findthreadst']) {
        if (intval($search['findthreadst']) == 1) {
            $thread_replycut = " AND t.replies >= '" . intval($search['numreplies']) . "'";
        } else {
            $thread_replycut = " AND t.replies <= '" . intval($search['numreplies']) . "'";
        }
    }
    $thread_prefixcut = '';
    $prefixlist = array();
    if ($search['threadprefix'] && $search['threadprefix'][0] != 'any') {
        foreach ($search['threadprefix'] as $threadprefix) {
            $threadprefix = intval($threadprefix);
            $prefixlist[] = $threadprefix;
        }
    }
    if (count($prefixlist) == 1) {
        $thread_prefixcut .= " AND t.prefix='{$threadprefix}' ";
    } else {
        if (count($prefixlist) > 1) {
            $thread_prefixcut = " AND t.prefix IN (" . implode(',', $prefixlist) . ")";
        }
    }
    $forumin = '';
    $fidlist = array();
    $searchin = array();
    if ($search['forums'][0] != "all") {
        if (!is_array($search['forums'])) {
            $search['forums'] = array(intval($search['forums']));
        }
        // Generate a comma separated list of all groups the user belongs to
        $user_groups = $mybb->user['usergroup'];
        if ($mybb->user['additionalgroups']) {
            $user_groups .= "," . $mybb->user['additionalgroups'];
            // Setup some quick permissions for us
            $fcache = $cache->read("forumpermissions");
            $add_groups = explode(",", $mybb->user['additionalgroups']);
        }
        foreach ($search['forums'] as $forum) {
            $forum = intval($forum);
            if (!$searchin[$forum]) {
                if (is_array($add_groups)) {
                    $can_search = 0;
                    foreach ($add_groups as $add_group) {
                        // Check to make sure that we have sufficient permissions to search this forum
                        if (!is_array($fcache[$forum][$add_group]) || $fcache[$forum][$add_group]['cansearch'] == 1 || $mybb->usergroup['cansearch'] == 1) {
                            $can_search = 1;
                        }
                    }
                    if ($can_search == 0) {
                        // We can't search this forum...
                        continue;
                    }
                }
                switch ($db->type) {
                    case "pgsql":
                        $query = $db->simple_select("forums", "DISTINCT fid", "(','||parentlist||',' LIKE ',%{$forum}%,') = true AND active != 0");
                        break;
                    case "sqlite":
                        $query = $db->simple_select("forums", "DISTINCT fid", "(','||parentlist||',' LIKE ',%{$forum}%,') > 0 AND active != 0");
                        break;
                    default:
                        $query = $db->simple_select("forums", "DISTINCT fid", "INSTR(CONCAT(',',parentlist,','),',{$forum},') > 0 AND active != 0");
                }
                while ($sforum = $db->fetch_array($query)) {
                    $fidlist[] = $sforum['fid'];
                }
            }
        }
        if (count($fidlist) == 1) {
            $forumin .= " AND t.fid='{$forum}' ";
            $searchin[$fid] = 1;
        } else {
            if (count($fidlist) > 1) {
                $forumin = " AND t.fid IN (" . implode(',', $fidlist) . ")";
            }
        }
    }
    $permsql = "";
    $onlyusfids = array();
    // Check group permissions if we can't view threads not started by us
    if ($group_permissions = forum_permissions()) {
        foreach ($group_permissions as $fid => $forum_permissions) {
            if ($forum_permissions['canonlyviewownthreads'] == 1) {
                $onlyusfids[] = $fid;
            }
        }
    }
    if (!empty($onlyusfids)) {
        $permsql .= "AND ((t.fid IN(" . implode(',', $onlyusfids) . ") AND t.uid='{$mybb->user['uid']}') OR t.fid NOT IN(" . implode(',', $onlyusfids) . "))";
    }
    $unsearchforums = get_unsearchable_forums();
    if ($unsearchforums) {
        $permsql .= " AND t.fid NOT IN ({$unsearchforums})";
    }
    $inactiveforums = get_inactive_forums();
    if ($inactiveforums) {
        $permsql .= " AND t.fid NOT IN ({$inactiveforums})";
    }
    $visiblesql = $post_visiblesql = $plain_post_visiblesql = "";
    if (isset($search['visible'])) {
        if ($search['visible'] == 1) {
            $visiblesql = " AND t.visible = '1'";
            if ($search['postthread'] == 1) {
                $post_visiblesql = " AND p.visible = '1'";
                $plain_post_visiblesql = " AND visible = '1'";
            }
        } else {
            $visiblesql = " AND t.visible != '1'";
            if ($search['postthread'] == 1) {
                $post_visiblesql = " AND p.visible != '1'";
                $plain_post_visiblesql = " AND visible != '1'";
            }
        }
    }
    // Searching a specific thread?
    if ($search['tid']) {
        $tidsql = " AND t.tid='" . intval($search['tid']) . "'";
    }
    $limitsql = '';
    if (intval($mybb->settings['searchhardlimit']) > 0) {
        $limitsql = "LIMIT " . intval($mybb->settings['searchhardlimit']);
    }
    // Searching both posts and thread titles
    $threads = array();
    $posts = array();
    $firstposts = array();
    if ($search['postthread'] == 1) {
        // No need to search subjects when looking for results within a specific thread
        if (!$search['tid']) {
            $query = $db->query("\n\t\t\t\tSELECT t.tid, t.firstpost\n\t\t\t\tFROM " . TABLE_PREFIX . "threads t\n\t\t\t\tWHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} AND t.closed NOT LIKE 'moved|%' {$subject_lookin}\n\t\t\t\t{$limitsql}\n\t\t\t");
            while ($thread = $db->fetch_array($query)) {
                $threads[$thread['tid']] = $thread['tid'];
                if ($thread['firstpost']) {
                    $posts[$thread['tid']] = $thread['firstpost'];
                }
            }
        }
        $query = $db->query("\n\t\t\tSELECT p.pid, p.tid\n\t\t\tFROM " . TABLE_PREFIX . "posts p\n\t\t\tLEFT JOIN " . TABLE_PREFIX . "threads t ON (t.tid=p.tid)\n\t\t\tWHERE 1=1 {$post_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$post_usersql} {$permsql} {$tidsql} {$visiblesql} {$post_visiblesql} AND t.closed NOT LIKE 'moved|%' {$message_lookin}\n\t\t\t{$limitsql}\n\t\t");
        while ($post = $db->fetch_array($query)) {
            $posts[$post['pid']] = $post['pid'];
            $threads[$post['tid']] = $post['tid'];
        }
        if (count($posts) < 1 && count($threads) < 1) {
            error($lang->error_nosearchresults);
        }
        $threads = implode(',', $threads);
        $posts = implode(',', $posts);
    } else {
        $query = $db->query("\n\t\t\tSELECT t.tid, t.firstpost\n\t\t\tFROM " . TABLE_PREFIX . "threads t\n\t\t\tWHERE 1=1 {$thread_datecut} {$thread_replycut} {$thread_prefixcut} {$forumin} {$thread_usersql} {$permsql} {$visiblesql} {$subject_lookin}\n\t\t\t{$limitsql}\n\t\t");
        while ($thread = $db->fetch_array($query)) {
            $threads[$thread['tid']] = $thread['tid'];
            if ($thread['firstpost']) {
                $firstposts[$thread['tid']] = $thread['firstpost'];
            }
        }
        if (count($threads) < 1) {
            error($lang->error_nosearchresults);
        }
        $threads = implode(',', $threads);
        $firstposts = implode(',', $firstposts);
        if ($firstposts) {
            $query = $db->simple_select("posts", "pid", "pid IN ({$firstposts}) {$plain_post_visiblesql} {$limitsql}");
            while ($post = $db->fetch_array($query)) {
                $posts[$post['pid']] = $post['pid'];
            }
            $posts = implode(',', $posts);
        }
    }
    return array("threads" => $threads, "posts" => $posts, "querycache" => '');
}