コード例 #1
0
ファイル: SearchAPI-Sphinxql.php プロジェクト: norv/EosAlpha
 public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
 {
     global $modSettings;
     $subwords = text2words($word, null, false);
     $fulltextWord = count($subwords) === 1 ? $word : '"' . $word . '"';
     $wordsSearch['indexed_words'][] = $fulltextWord;
     if ($isExcluded) {
         $wordsExclude[] = $fulltextWord;
     }
 }
コード例 #2
0
ファイル: SearchAPI-Sphinx.php プロジェクト: norv/EosAlpha
 public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
 {
     global $modSettings, $smcFunc;
     $subwords = text2words($word, $this->min_word_length, false);
     // Excluded phrases don't benefit from being split into subwords.
     if (count($subwords) > 1 && $isExcluded) {
         return;
     } else {
         foreach ($subwords as $subword) {
             if (commonAPI::strlen($subword) >= $this->min_word_length && !in_array($subword, $this->bannedWords)) {
                 $wordsSearch['indexed_words'][] = $subword;
                 if ($isExcluded) {
                     $wordsExclude[] = $subword;
                 }
             }
         }
     }
 }
コード例 #3
0
 public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
 {
     global $modSettings, $smcFunc;
     $subwords = text2words($word, $this->min_word_length, true);
     if (empty($modSettings['search_force_index'])) {
         $wordsSearch['words'][] = $word;
     }
     // Excluded phrases don't benefit from being split into subwords.
     if (count($subwords) > 1 && $isExcluded) {
         continue;
     } else {
         foreach ($subwords as $subword) {
             if ($smcFunc['strlen']($subword) >= $this->min_word_length && !in_array($subword, $this->bannedWords)) {
                 $wordsSearch['indexed_words'][] = $subword;
                 if ($isExcluded) {
                     $wordsExclude[] = $subword;
                 }
             }
         }
     }
 }
コード例 #4
0
ファイル: RepairBoards.php プロジェクト: VBGAMER45/SMFMods
function findForumErrors()
{
    global $db_prefix, $context, $txt;
    // This may take some time...
    @set_time_limit(600);
    $to_fix = !empty($_SESSION['repairboards_to_fix']) ? $_SESSION['repairboards_to_fix'] : array();
    $context['repair_errors'] = isset($_SESSION['repairboards_to_fix2']) ? $_SESSION['repairboards_to_fix2'] : array();
    $_GET['step'] = empty($_GET['step']) ? 0 : (int) $_GET['step'];
    $_GET['substep'] = empty($_GET['substep']) ? 0 : (int) $_GET['substep'];
    if ($_GET['step'] <= 0) {
        // Make a last-ditch-effort check to get rid of topics with zeros..
        $result = db_query("\n\t\t\tSELECT COUNT(*)\n\t\t\tFROM {$db_prefix}topics\n\t\t\tWHERE ID_TOPIC = 0", __FILE__, __LINE__);
        list($zeroTopics) = mysql_fetch_row($result);
        mysql_free_result($result);
        // This is only going to be 1 or 0, but...
        $result = db_query("\n\t\t\tSELECT COUNT(*)\n\t\t\tFROM {$db_prefix}messages\n\t\t\tWHERE ID_MSG = 0", __FILE__, __LINE__);
        list($zeroMessages) = mysql_fetch_row($result);
        mysql_free_result($result);
        if (!empty($zeroTopics) || !empty($zeroMessages)) {
            $context['repair_errors'][] = $txt['repair_zero_ids'];
            $to_fix[] = 'zero_ids';
        }
        $_GET['step'] = 1;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 1) {
        // Find messages that don't have existing topics.
        $result = db_query("\n\t\t\tSELECT m.ID_TOPIC, m.ID_MSG\n\t\t\tFROM {$db_prefix}messages AS m\n\t\t\t\tLEFT JOIN {$db_prefix}topics AS t ON (t.ID_TOPIC = m.ID_TOPIC)\n\t\t\tWHERE t.ID_TOPIC IS NULL\n\t\t\tORDER BY m.ID_TOPIC, m.ID_MSG", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($result)) {
            $context['repair_errors'][] = sprintf($txt['repair_missing_topics'], $row['ID_MSG'], $row['ID_TOPIC']);
        }
        if (mysql_num_rows($result) != 0) {
            $to_fix[] = 'missing_topics';
        }
        mysql_free_result($result);
        $_GET['step'] = 2;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 2) {
        // Find messages that don't have existing topics.
        $result = db_query("\n\t\t\tSELECT m.ID_TOPIC, m.ID_MSG\n\t\t\tFROM {$db_prefix}messages AS m\n\t\t\t\tLEFT JOIN {$db_prefix}topics AS t ON (t.ID_TOPIC = m.ID_TOPIC)\n\t\t\tWHERE t.ID_TOPIC IS NULL\n\t\t\tORDER BY m.ID_TOPIC, m.ID_MSG", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($result)) {
            $context['repair_errors'][] = sprintf($txt['repair_missing_topics'], $row['ID_MSG'], $row['ID_TOPIC']);
        }
        if (mysql_num_rows($result) != 0) {
            $to_fix[] = 'missing_topics';
        }
        mysql_free_result($result);
        $_GET['step'] = 3;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 3) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_TOPIC)\n\t\t\tFROM {$db_prefix}topics", __FILE__, __LINE__);
        list($topics) = mysql_fetch_row($result);
        mysql_free_result($result);
        // Find topics with no messages.
        for (; $_GET['substep'] < $topics; $_GET['substep'] += 1000) {
            pauseRepairProcess($to_fix, $topics);
            $result = db_query("\n\t\t\t\tSELECT t.ID_TOPIC, COUNT(m.ID_MSG) AS numMsg\n\t\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\t\tLEFT JOIN {$db_prefix}messages AS m ON (m.ID_TOPIC = t.ID_TOPIC)\n\t\t\t\tWHERE t.ID_TOPIC BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 999\n\t\t\t\tGROUP BY t.ID_TOPIC\n\t\t\t\tHAVING numMsg = 0", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_messages'], $row['ID_TOPIC']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_messages';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 4;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 4) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_TOPIC)\n\t\t\tFROM {$db_prefix}topics", __FILE__, __LINE__);
        list($topics) = mysql_fetch_row($result);
        mysql_free_result($result);
        // Find topics with incorrect ID_FIRST_MSG/ID_LAST_MSG/numReplies.
        for (; $_GET['substep'] < $topics; $_GET['substep'] += 1000) {
            pauseRepairProcess($to_fix, $topics);
            $result = db_query("\n\t\t\t\tSELECT\n\t\t\t\t\tt.ID_TOPIC, t.ID_FIRST_MSG, t.ID_LAST_MSG, t.numReplies,\n\t\t\t\t\tMIN(m.ID_MSG) AS myID_FIRST_MSG, MAX(m.ID_MSG) AS myID_LAST_MSG,\n\t\t\t\t\tCOUNT(m.ID_MSG) - 1 AS myNumReplies\n\t\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\t\tLEFT JOIN {$db_prefix}messages AS m ON (m.ID_TOPIC = t.ID_TOPIC)\n\t\t\t\tWHERE t.ID_TOPIC BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 999\n\t\t\t\tGROUP BY t.ID_TOPIC\n\t\t\t\tHAVING ID_FIRST_MSG != myID_FIRST_MSG OR ID_LAST_MSG != myID_LAST_MSG OR numReplies != myNumReplies\n\t\t\t\tORDER BY t.ID_TOPIC", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                if ($row['ID_FIRST_MSG'] != $row['myID_FIRST_MSG']) {
                    $context['repair_errors'][] = sprintf($txt['repair_stats_topics_1'], $row['ID_TOPIC'], $row['ID_FIRST_MSG']);
                }
                if ($row['ID_LAST_MSG'] != $row['myID_LAST_MSG']) {
                    $context['repair_errors'][] = sprintf($txt['repair_stats_topics_2'], $row['ID_TOPIC'], $row['ID_LAST_MSG']);
                }
                if ($row['numReplies'] != $row['myNumReplies']) {
                    $context['repair_errors'][] = sprintf($txt['repair_stats_topics_3'], $row['ID_TOPIC'], $row['numReplies']);
                }
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'stats_topics';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 5;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 5) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_TOPIC)\n\t\t\tFROM {$db_prefix}topics", __FILE__, __LINE__);
        list($topics) = mysql_fetch_row($result);
        mysql_free_result($result);
        // Find topics with nonexistent boards.
        for (; $_GET['substep'] < $topics; $_GET['substep'] += 1000) {
            pauseRepairProcess($to_fix, $topics);
            $result = db_query("\n\t\t\t\tSELECT t.ID_TOPIC, t.ID_BOARD\n\t\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\t\tLEFT JOIN {$db_prefix}boards AS b ON (b.ID_BOARD = t.ID_BOARD)\n\t\t\t\tWHERE b.ID_BOARD IS NULL\n\t\t\t\t\tAND t.ID_TOPIC BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 999\n\t\t\t\tORDER BY t.ID_BOARD, t.ID_TOPIC", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_boards'], $row['ID_TOPIC'], $row['ID_BOARD']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_boards';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 6;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 6) {
        // Find boards with nonexistent categories.
        $result = db_query("\n\t\t\tSELECT b.ID_BOARD, b.ID_CAT\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\t\tLEFT JOIN {$db_prefix}categories AS c ON (c.ID_CAT = b.ID_CAT)\n\t\t\tWHERE c.ID_CAT IS NULL\n\t\t\tORDER BY b.ID_CAT, b.ID_BOARD", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($result)) {
            $context['repair_errors'][] = sprintf($txt['repair_missing_categories'], $row['ID_BOARD'], $row['ID_CAT']);
        }
        if (mysql_num_rows($result) != 0) {
            $to_fix[] = 'missing_categories';
        }
        mysql_free_result($result);
        $_GET['step'] = 7;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 7) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MSG)\n\t\t\tFROM {$db_prefix}messages", __FILE__, __LINE__);
        list($messages) = mysql_fetch_row($result);
        mysql_free_result($result);
        // Find messages with nonexistent members.
        for (; $_GET['substep'] < $messages; $_GET['substep'] += 2000) {
            pauseRepairProcess($to_fix, $messages);
            $result = db_query("\n\t\t\t\tSELECT m.ID_MSG, m.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}messages AS m\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = m.ID_MEMBER)\n\t\t\t\tWHERE mem.ID_MEMBER IS NULL\n\t\t\t\t\tAND m.ID_MEMBER != 0\n\t\t\t\t\tAND m.ID_MSG BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 1999\n\t\t\t\tORDER BY m.ID_MSG", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_posters'], $row['ID_MSG'], $row['ID_MEMBER']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_posters';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 8;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 8) {
        // Find boards with nonexistent parents.
        $result = db_query("\n\t\t\tSELECT b.ID_BOARD, b.ID_PARENT\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\t\tLEFT JOIN {$db_prefix}boards AS p ON (p.ID_BOARD = b.ID_PARENT)\n\t\t\tWHERE b.ID_PARENT != 0\n\t\t\t\tAND (p.ID_BOARD IS NULL OR p.ID_BOARD = b.ID_BOARD)\n\t\t\tORDER BY b.ID_PARENT, b.ID_BOARD", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($result)) {
            $context['repair_errors'][] = sprintf($txt['repair_missing_parents'], $row['ID_BOARD'], $row['ID_PARENT']);
        }
        if (mysql_num_rows($result) != 0) {
            $to_fix[] = 'missing_parents';
        }
        mysql_free_result($result);
        $_GET['step'] = 9;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 9) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_POLL)\n\t\t\tFROM {$db_prefix}topics", __FILE__, __LINE__);
        list($polls) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $polls; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $polls);
            $result = db_query("\n\t\t\t\tSELECT t.ID_POLL, t.ID_TOPIC\n\t\t\t\tFROM {$db_prefix}topics AS t\n\t\t\t\t\tLEFT JOIN {$db_prefix}polls AS p ON (p.ID_POLL = t.ID_POLL)\n\t\t\t\tWHERE t.ID_POLL != 0\n\t\t\t\t\tAND t.ID_POLL BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND p.ID_POLL IS NULL\n\t\t\t\tGROUP BY t.ID_POLL", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_polls'], $row['ID_TOPIC'], $row['ID_POLL']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_polls';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 10;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 10) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_TOPIC)\n\t\t\tFROM {$db_prefix}calendar", __FILE__, __LINE__);
        list($topics) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $topics; $_GET['substep'] += 1000) {
            pauseRepairProcess($to_fix, $topics);
            $result = db_query("\n\t\t\t\tSELECT cal.ID_TOPIC, cal.ID_EVENT\n\t\t\t\tFROM {$db_prefix}calendar AS cal\n\t\t\t\t\tLEFT JOIN {$db_prefix}topics AS t ON (t.ID_TOPIC = cal.ID_TOPIC)\n\t\t\t\tWHERE cal.ID_TOPIC != 0\n\t\t\t\t\tAND cal.ID_TOPIC BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 999\n\t\t\t\t\tAND t.ID_TOPIC IS NULL\n\t\t\t\tORDER BY cal.ID_TOPIC", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_calendar_topics'], $row['ID_EVENT'], $row['ID_TOPIC']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_calendar_topics';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 11;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 11) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}members", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 250) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT lt.ID_TOPIC\n\t\t\t\tFROM {$db_prefix}log_topics AS lt\n\t\t\t\t\tLEFT JOIN {$db_prefix}topics AS t ON (t.ID_TOPIC = lt.ID_TOPIC)\n\t\t\t\tWHERE t.ID_TOPIC IS NULL\n\t\t\t\t\tAND lt.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 249", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_topics'], $row['ID_TOPIC']);
            }
            if (mysql_num_rows($result) != 0 && !in_array('missing_log_topics', $to_fix)) {
                $to_fix[] = 'missing_log_topics';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 12;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 12) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}log_topics", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 150) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT lt.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}log_topics AS lt\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = lt.ID_MEMBER)\n\t\t\t\tWHERE mem.ID_MEMBER IS NULL\n\t\t\t\t\tAND lt.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 149\n\t\t\t\tGROUP BY lt.ID_MEMBER", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_topics_members'], $row['ID_MEMBER']);
            }
            if (mysql_num_rows($result) != 0 && !in_array('missing_log_topics_members', $to_fix)) {
                $to_fix[] = 'missing_log_topics_members';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 13;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 13) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}log_boards", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT lb.ID_BOARD\n\t\t\t\tFROM {$db_prefix}log_boards AS lb\n\t\t\t\t\tLEFT JOIN {$db_prefix}boards AS b ON (b.ID_BOARD = lb.ID_BOARD)\n\t\t\t\tWHERE b.ID_BOARD IS NULL\n\t\t\t\t\tAND lb.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\tGROUP BY lb.ID_BOARD", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_boards'], $row['ID_BOARD']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_log_boards';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 14;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 14) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}log_boards", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT lb.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}log_boards AS lb\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = lb.ID_MEMBER)\n\t\t\t\tWHERE mem.ID_MEMBER IS NULL\n\t\t\t\t\tAND lb.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\tGROUP BY lb.ID_MEMBER", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_boards_members'], $row['ID_MEMBER']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_log_boards_members';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 15;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 15) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}log_mark_read", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT lmr.ID_BOARD\n\t\t\t\tFROM {$db_prefix}log_mark_read AS lmr\n\t\t\t\t\tLEFT JOIN {$db_prefix}boards AS b ON (b.ID_BOARD = lmr.ID_BOARD)\n\t\t\t\tWHERE b.ID_BOARD IS NULL\n\t\t\t\t\tAND lmr.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\tGROUP BY lmr.ID_BOARD", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_mark_read'], $row['ID_BOARD']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_log_mark_read';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 16;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 16) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}log_mark_read", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT lmr.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}log_mark_read AS lmr\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = lmr.ID_MEMBER)\n\t\t\t\tWHERE mem.ID_MEMBER IS NULL\n\t\t\t\t\tAND lmr.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\tGROUP BY lmr.ID_MEMBER", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_mark_read_members'], $row['ID_MEMBER']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_log_mark_read_members';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 17;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 17) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_PM)\n\t\t\tFROM {$db_prefix}pm_recipients", __FILE__, __LINE__);
        list($pms) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $pms; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $pms);
            $result = db_query("\n\t\t\t\tSELECT pmr.ID_PM\n\t\t\t\tFROM {$db_prefix}pm_recipients AS pmr\n\t\t\t\t\tLEFT JOIN {$db_prefix}personal_messages AS pm ON (pm.ID_PM = pmr.ID_PM)\n\t\t\t\tWHERE pm.ID_PM IS NULL\n\t\t\t\t\tAND pmr.ID_PM BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\tGROUP BY pmr.ID_PM", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_pms'], $row['ID_PM']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_pms';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 18;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 18) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}pm_recipients", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT pmr.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}pm_recipients AS pmr\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = pmr.ID_MEMBER)\n\t\t\t\tWHERE pmr.ID_MEMBER != 0\n\t\t\t\t\tAND pmr.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND mem.ID_MEMBER IS NULL\n\t\t\t\tGROUP BY pmr.ID_MEMBER", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_recipients'], $row['ID_MEMBER']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_recipients';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 19;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 19) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_PM)\n\t\t\tFROM {$db_prefix}personal_messages", __FILE__, __LINE__);
        list($pms) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $pms; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $pms);
            $result = db_query("\n\t\t\t\tSELECT pm.ID_PM, pm.ID_MEMBER_FROM\n\t\t\t\tFROM {$db_prefix}personal_messages AS pm\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = pm.ID_MEMBER_FROM)\n\t\t\t\tWHERE pm.ID_MEMBER_FROM != 0\n\t\t\t\t\tAND pm.ID_PM BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND mem.ID_MEMBER IS NULL", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_senders'], $row['ID_PM'], $row['ID_MEMBER_FROM']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_senders';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 20;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 20) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}log_notify", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $members);
            $result = db_query("\n\t\t\t\tSELECT ln.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}log_notify AS ln\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = ln.ID_MEMBER)\n\t\t\t\tWHERE ln.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND mem.ID_MEMBER IS NULL\n\t\t\t\tGROUP BY ln.ID_MEMBER", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_notify_members'], $row['ID_MEMBER']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_notify_members';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 21;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 21) {
        $request = db_query("\n\t\t\tSELECT t.ID_TOPIC, fm.subject\n\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}messages AS fm)\n\t\t\t\tLEFT JOIN {$db_prefix}log_search_subjects AS lss ON (lss.ID_TOPIC = t.ID_TOPIC)\n\t\t\tWHERE fm.ID_MSG = t.ID_FIRST_MSG\n\t\t\t\tAND lss.ID_TOPIC IS NULL", __FILE__, __LINE__);
        $found_error = false;
        while ($row = mysql_fetch_assoc($request)) {
            if (count(text2words($row['subject'])) != 0) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_cached_subject'], $row['ID_TOPIC']);
                $found_error = true;
            }
        }
        mysql_free_result($request);
        if ($found_error) {
            $to_fix[] = 'missing_cached_subject';
        }
        $_GET['step'] = 22;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 22) {
        $request = db_query("\n\t\t\tSELECT lss.word\n\t\t\tFROM {$db_prefix}log_search_subjects AS lss\n\t\t\t\tLEFT JOIN {$db_prefix}topics AS t ON (t.ID_TOPIC = lss.ID_TOPIC)\n\t\t\tWHERE t.ID_TOPIC IS NULL", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($request)) {
            $context['repair_errors'][] = sprintf($txt['repair_missing_topic_for_cache'], htmlspecialchars($row['word']));
        }
        if (mysql_num_rows($request) != 0) {
            $to_fix[] = 'missing_topic_for_cache';
        }
        mysql_free_result($request);
        $_GET['step'] = 23;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 23) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_MEMBER)\n\t\t\tFROM {$db_prefix}log_polls", __FILE__, __LINE__);
        list($members) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $members; $_GET['substep'] += 500) {
            $result = db_query("\n\t\t\t\tSELECT lp.ID_POLL, lp.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}log_polls AS lp\n\t\t\t\t\tLEFT JOIN {$db_prefix}members AS mem ON (mem.ID_MEMBER = lp.ID_MEMBER)\n\t\t\t\tWHERE lp.ID_MEMBER BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND mem.ID_MEMBER IS NULL\n\t\t\t\tGROUP BY lp.ID_MEMBER", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_poll_member'], $row['ID_POLL'], $row['ID_MEMBER']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_member_vote';
            }
            mysql_free_result($result);
            pauseRepairProcess($to_fix, $members);
        }
        $_GET['step'] = 24;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    if ($_GET['step'] <= 24) {
        $result = db_query("\n\t\t\tSELECT MAX(ID_POLL)\n\t\t\tFROM {$db_prefix}log_polls", __FILE__, __LINE__);
        list($polls) = mysql_fetch_row($result);
        mysql_free_result($result);
        for (; $_GET['substep'] < $polls; $_GET['substep'] += 500) {
            pauseRepairProcess($to_fix, $polls);
            $result = db_query("\n\t\t\t\tSELECT lp.ID_POLL, lp.ID_MEMBER\n\t\t\t\tFROM {$db_prefix}log_polls AS lp\n\t\t\t\t\tLEFT JOIN {$db_prefix}polls AS p ON (p.ID_POLL = lp.ID_POLL)\n\t\t\t\tWHERE lp.ID_POLL BETWEEN {$_GET['substep']} AND {$_GET['substep']} + 499\n\t\t\t\t\tAND p.ID_POLL IS NULL\n\t\t\t\tGROUP BY lp.ID_POLL", __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $context['repair_errors'][] = sprintf($txt['repair_missing_log_poll_vote'], $row['ID_MEMBER'], $row['ID_POLL']);
            }
            if (mysql_num_rows($result) != 0) {
                $to_fix[] = 'missing_log_poll_vote';
            }
            mysql_free_result($result);
        }
        $_GET['step'] = 25;
        $_GET['substep'] = 0;
        pauseRepairProcess($to_fix);
    }
    return $to_fix;
}
コード例 #5
0
ファイル: ManageSearch.php プロジェクト: Glyph13/SMF2.1
/**
 * Create a custom search index for the messages table.
 * Called by ?action=admin;area=managesearch;sa=createmsgindex.
 * Linked from the EditSearchMethod screen.
 * Requires the admin_forum permission.
 * Depending on the size of the message table, the process is divided in steps.
 *
 * @uses ManageSearch template, 'create_index', 'create_index_progress', and 'create_index_done'
 *  sub-templates.
 */
function CreateMessageIndex()
{
    global $modSettings, $context, $smcFunc, $db_prefix, $txt;
    // Scotty, we need more time...
    @set_time_limit(600);
    if (function_exists('apache_reset_timeout')) {
        @apache_reset_timeout();
    }
    $context[$context['admin_menu_name']]['current_subsection'] = 'method';
    $context['page_title'] = $txt['search_index_custom'];
    $messages_per_batch = 50;
    $index_properties = array(2 => array('column_definition' => 'small', 'step_size' => 1000000), 4 => array('column_definition' => 'medium', 'step_size' => 1000000, 'max_size' => 16777215), 5 => array('column_definition' => 'large', 'step_size' => 100000000, 'max_size' => 2000000000));
    if (isset($_REQUEST['resume']) && !empty($modSettings['search_custom_index_resume'])) {
        $context['index_settings'] = unserialize($modSettings['search_custom_index_resume']);
        $context['start'] = (int) $context['index_settings']['resume_at'];
        unset($context['index_settings']['resume_at']);
        $context['step'] = 1;
    } else {
        $context['index_settings'] = array('bytes_per_word' => isset($_REQUEST['bytes_per_word']) && isset($index_properties[$_REQUEST['bytes_per_word']]) ? (int) $_REQUEST['bytes_per_word'] : 2);
        $context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
        $context['step'] = isset($_REQUEST['step']) ? (int) $_REQUEST['step'] : 0;
        // admin timeouts are painful when building these long indexes
        if ($_SESSION['admin_time'] + 3300 < time() && $context['step'] >= 1) {
            $_SESSION['admin_time'] = time();
        }
    }
    if ($context['step'] !== 0) {
        checkSession('request');
    }
    // Step 0: let the user determine how they like their index.
    if ($context['step'] === 0) {
        $context['sub_template'] = 'create_index';
    }
    // Step 1: insert all the words.
    if ($context['step'] === 1) {
        $context['sub_template'] = 'create_index_progress';
        if ($context['start'] === 0) {
            db_extend();
            $tables = $smcFunc['db_list_tables'](false, $db_prefix . 'log_search_words');
            if (!empty($tables)) {
                $smcFunc['db_search_query']('drop_words_table', '
					DROP TABLE {db_prefix}log_search_words', array());
            }
            $smcFunc['db_create_word_search']($index_properties[$context['index_settings']['bytes_per_word']]['column_definition']);
            // Temporarily switch back to not using a search index.
            if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom') {
                updateSettings(array('search_index' => ''));
            }
            // Don't let simultanious processes be updating the search index.
            if (!empty($modSettings['search_custom_index_config'])) {
                updateSettings(array('search_custom_index_config' => ''));
            }
        }
        $num_messages = array('done' => 0, 'todo' => 0);
        $request = $smcFunc['db_query']('', '
			SELECT id_msg >= {int:starting_id} AS todo, COUNT(*) AS num_messages
			FROM {db_prefix}messages
			GROUP BY todo', array('starting_id' => $context['start']));
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $num_messages[empty($row['todo']) ? 'done' : 'todo'] = $row['num_messages'];
        }
        if (empty($num_messages['todo'])) {
            $context['step'] = 2;
            $context['percentage'] = 80;
            $context['start'] = 0;
        } else {
            // Number of seconds before the next step.
            $stop = time() + 3;
            while (time() < $stop) {
                $inserts = array();
                $request = $smcFunc['db_query']('', '
					SELECT id_msg, body
					FROM {db_prefix}messages
					WHERE id_msg BETWEEN {int:starting_id} AND {int:ending_id}
					LIMIT {int:limit}', array('starting_id' => $context['start'], 'ending_id' => $context['start'] + $messages_per_batch - 1, 'limit' => $messages_per_batch));
                $forced_break = false;
                $number_processed = 0;
                while ($row = $smcFunc['db_fetch_assoc']($request)) {
                    // In theory it's possible for one of these to take friggin ages so add more timeout protection.
                    if ($stop < time()) {
                        $forced_break = true;
                        break;
                    }
                    $number_processed++;
                    foreach (text2words($row['body'], $context['index_settings']['bytes_per_word'], true) as $id_word) {
                        $inserts[] = array($id_word, $row['id_msg']);
                    }
                }
                $num_messages['done'] += $number_processed;
                $num_messages['todo'] -= $number_processed;
                $smcFunc['db_free_result']($request);
                $context['start'] += $forced_break ? $number_processed : $messages_per_batch;
                if (!empty($inserts)) {
                    $smcFunc['db_insert']('ignore', '{db_prefix}log_search_words', array('id_word' => 'int', 'id_msg' => 'int'), $inserts, array('id_word', 'id_msg'));
                }
                if ($num_messages['todo'] === 0) {
                    $context['step'] = 2;
                    $context['start'] = 0;
                    break;
                } else {
                    updateSettings(array('search_custom_index_resume' => serialize(array_merge($context['index_settings'], array('resume_at' => $context['start'])))));
                }
            }
            // Since there are still two steps to go, 80% is the maximum here.
            $context['percentage'] = round($num_messages['done'] / ($num_messages['done'] + $num_messages['todo']), 3) * 80;
        }
    } elseif ($context['step'] === 2) {
        if ($context['index_settings']['bytes_per_word'] < 4) {
            $context['step'] = 3;
        } else {
            $stop_words = $context['start'] === 0 || empty($modSettings['search_stopwords']) ? array() : explode(',', $modSettings['search_stopwords']);
            $stop = time() + 3;
            $context['sub_template'] = 'create_index_progress';
            $max_messages = ceil(60 * $modSettings['totalMessages'] / 100);
            while (time() < $stop) {
                $request = $smcFunc['db_query']('', '
					SELECT id_word, COUNT(id_word) AS num_words
					FROM {db_prefix}log_search_words
					WHERE id_word BETWEEN {int:starting_id} AND {int:ending_id}
					GROUP BY id_word
					HAVING COUNT(id_word) > {int:minimum_messages}', array('starting_id' => $context['start'], 'ending_id' => $context['start'] + $index_properties[$context['index_settings']['bytes_per_word']]['step_size'] - 1, 'minimum_messages' => $max_messages));
                while ($row = $smcFunc['db_fetch_assoc']($request)) {
                    $stop_words[] = $row['id_word'];
                }
                $smcFunc['db_free_result']($request);
                updateSettings(array('search_stopwords' => implode(',', $stop_words)));
                if (!empty($stop_words)) {
                    $smcFunc['db_query']('', '
						DELETE FROM {db_prefix}log_search_words
						WHERE id_word in ({array_int:stop_words})', array('stop_words' => $stop_words));
                }
                $context['start'] += $index_properties[$context['index_settings']['bytes_per_word']]['step_size'];
                if ($context['start'] > $index_properties[$context['index_settings']['bytes_per_word']]['max_size']) {
                    $context['step'] = 3;
                    break;
                }
            }
            $context['percentage'] = 80 + round($context['start'] / $index_properties[$context['index_settings']['bytes_per_word']]['max_size'], 3) * 20;
        }
    }
    // Step 3: remove words not distinctive enough.
    if ($context['step'] === 3) {
        $context['sub_template'] = 'create_index_done';
        updateSettings(array('search_index' => 'custom', 'search_custom_index_config' => serialize($context['index_settings'])));
        $smcFunc['db_query']('', '
			DELETE FROM {db_prefix}settings
			WHERE variable = {string:search_custom_index_resume}', array('search_custom_index_resume' => 'search_custom_index_resume'));
    }
}
コード例 #6
0
ファイル: RemoveTopic.php プロジェクト: Glyph13/SMF2.1
/**
 * Remove a specific message (including permission checks).
 * - normally, local and global should be the localCookies and globalCookies settings, respectively.
 * - uses boardurl to determine these two things.
 *
 * @param int $message The message id
 * @param bool $decreasePostCount if true users' post count will be reduced
 * @return array an array to set the cookie on with domain and path in it, in that order
 */
function removeMessage($message, $decreasePostCount = true)
{
    global $board, $sourcedir, $modSettings, $user_info, $smcFunc, $context;
    if (empty($message) || !is_numeric($message)) {
        return false;
    }
    $request = $smcFunc['db_query']('', '
		SELECT
			m.id_member, m.icon, m.poster_time, m.subject,' . (empty($modSettings['search_custom_index_config']) ? '' : ' m.body,') . '
			m.approved, t.id_topic, t.id_first_msg, t.id_last_msg, t.num_replies, t.id_board,
			t.id_member_started AS id_member_poster,
			b.count_posts
		FROM {db_prefix}messages AS m
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
		WHERE m.id_msg = {int:id_msg}
		LIMIT 1', array('id_msg' => $message));
    if ($smcFunc['db_num_rows']($request) == 0) {
        return false;
    }
    $row = $smcFunc['db_fetch_assoc']($request);
    $smcFunc['db_free_result']($request);
    if (empty($board) || $row['id_board'] != $board) {
        $delete_any = boardsAllowedTo('delete_any');
        if (!in_array(0, $delete_any) && !in_array($row['id_board'], $delete_any)) {
            $delete_own = boardsAllowedTo('delete_own');
            $delete_own = in_array(0, $delete_own) || in_array($row['id_board'], $delete_own);
            $delete_replies = boardsAllowedTo('delete_replies');
            $delete_replies = in_array(0, $delete_replies) || in_array($row['id_board'], $delete_replies);
            if ($row['id_member'] == $user_info['id']) {
                if (!$delete_own) {
                    if ($row['id_member_poster'] == $user_info['id']) {
                        if (!$delete_replies) {
                            fatal_lang_error('cannot_delete_replies', 'permission');
                        }
                    } else {
                        fatal_lang_error('cannot_delete_own', 'permission');
                    }
                } elseif (($row['id_member_poster'] != $user_info['id'] || !$delete_replies) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + $modSettings['edit_disable_time'] * 60 < time()) {
                    fatal_lang_error('modify_post_time_passed', false);
                }
            } elseif ($row['id_member_poster'] == $user_info['id']) {
                if (!$delete_replies) {
                    fatal_lang_error('cannot_delete_replies', 'permission');
                }
            } else {
                fatal_lang_error('cannot_delete_any', 'permission');
            }
        }
        // Can't delete an unapproved message, if you can't see it!
        if ($modSettings['postmod_active'] && !$row['approved'] && $row['id_member'] != $user_info['id'] && !(in_array(0, $delete_any) || in_array($row['id_board'], $delete_any))) {
            $approve_posts = boardsAllowedTo('approve_posts');
            if (!in_array(0, $approve_posts) && !in_array($row['id_board'], $approve_posts)) {
                return false;
            }
        }
    } else {
        // Check permissions to delete this message.
        if ($row['id_member'] == $user_info['id']) {
            if (!allowedTo('delete_own')) {
                if ($row['id_member_poster'] == $user_info['id'] && !allowedTo('delete_any')) {
                    isAllowedTo('delete_replies');
                } elseif (!allowedTo('delete_any')) {
                    isAllowedTo('delete_own');
                }
            } elseif (!allowedTo('delete_any') && ($row['id_member_poster'] != $user_info['id'] || !allowedTo('delete_replies')) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + $modSettings['edit_disable_time'] * 60 < time()) {
                fatal_lang_error('modify_post_time_passed', false);
            }
        } elseif ($row['id_member_poster'] == $user_info['id'] && !allowedTo('delete_any')) {
            isAllowedTo('delete_replies');
        } else {
            isAllowedTo('delete_any');
        }
        if ($modSettings['postmod_active'] && !$row['approved'] && $row['id_member'] != $user_info['id'] && !allowedTo('delete_own')) {
            isAllowedTo('approve_posts');
        }
    }
    // Close any moderation reports for this message.
    $smcFunc['db_query']('', '
		UPDATE {db_prefix}log_reported
		SET closed = {int:is_closed}
		WHERE id_msg = {int:id_msg}', array('is_closed' => 1, 'id_msg' => $message));
    if ($smcFunc['db_affected_rows']() != 0) {
        require_once $sourcedir . '/ModerationCenter.php';
        updateSettings(array('last_mod_report_action' => time()));
        recountOpenReports();
    }
    // Delete the *whole* topic, but only if the topic consists of one message.
    if ($row['id_first_msg'] == $message) {
        if (empty($board) || $row['id_board'] != $board) {
            $remove_any = boardsAllowedTo('remove_any');
            $remove_any = in_array(0, $remove_any) || in_array($row['id_board'], $remove_any);
            if (!$remove_any) {
                $remove_own = boardsAllowedTo('remove_own');
                $remove_own = in_array(0, $remove_own) || in_array($row['id_board'], $remove_own);
            }
            if ($row['id_member'] != $user_info['id'] && !$remove_any) {
                fatal_lang_error('cannot_remove_any', 'permission');
            } elseif (!$remove_any && !$remove_own) {
                fatal_lang_error('cannot_remove_own', 'permission');
            }
        } else {
            // Check permissions to delete a whole topic.
            if ($row['id_member'] != $user_info['id']) {
                isAllowedTo('remove_any');
            } elseif (!allowedTo('remove_any')) {
                isAllowedTo('remove_own');
            }
        }
        // ...if there is only one post.
        if (!empty($row['num_replies'])) {
            fatal_lang_error('delFirstPost', false);
        }
        removeTopics($row['id_topic']);
        return true;
    }
    // Deleting a recycled message can not lower anyone's post count.
    if ($row['icon'] == 'recycled') {
        $decreasePostCount = false;
    }
    // This is the last post, update the last post on the board.
    if ($row['id_last_msg'] == $message) {
        // Find the last message, set it, and decrease the post count.
        $request = $smcFunc['db_query']('', '
			SELECT id_msg, id_member
			FROM {db_prefix}messages
			WHERE id_topic = {int:id_topic}
				AND id_msg != {int:id_msg}
			ORDER BY ' . ($modSettings['postmod_active'] ? 'approved DESC, ' : '') . 'id_msg DESC
			LIMIT 1', array('id_topic' => $row['id_topic'], 'id_msg' => $message));
        $row2 = $smcFunc['db_fetch_assoc']($request);
        $smcFunc['db_free_result']($request);
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}topics
			SET
				id_last_msg = {int:id_last_msg},
				id_member_updated = {int:id_member_updated}' . (!$modSettings['postmod_active'] || $row['approved'] ? ',
				num_replies = CASE WHEN num_replies = {int:no_replies} THEN 0 ELSE num_replies - 1 END' : ',
				unapproved_posts = CASE WHEN unapproved_posts = {int:no_unapproved} THEN 0 ELSE unapproved_posts - 1 END') . '
			WHERE id_topic = {int:id_topic}', array('id_last_msg' => $row2['id_msg'], 'id_member_updated' => $row2['id_member'], 'no_replies' => 0, 'no_unapproved' => 0, 'id_topic' => $row['id_topic']));
    } else {
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}topics
			SET ' . ($row['approved'] ? '
				num_replies = CASE WHEN num_replies = {int:no_replies} THEN 0 ELSE num_replies - 1 END' : '
				unapproved_posts = CASE WHEN unapproved_posts = {int:no_unapproved} THEN 0 ELSE unapproved_posts - 1 END') . '
			WHERE id_topic = {int:id_topic}', array('no_replies' => 0, 'no_unapproved' => 0, 'id_topic' => $row['id_topic']));
    }
    // Default recycle to false.
    $recycle = false;
    // If recycle topics has been set, make a copy of this message in the recycle board.
    // Make sure we're not recycling messages that are already on the recycle board.
    if (!empty($modSettings['recycle_enable']) && $row['id_board'] != $modSettings['recycle_board'] && $row['icon'] != 'recycled') {
        // Check if the recycle board exists and if so get the read status.
        $request = $smcFunc['db_query']('', '
			SELECT (IFNULL(lb.id_msg, 0) >= b.id_msg_updated) AS is_seen, id_last_msg
			FROM {db_prefix}boards AS b
				LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member})
			WHERE b.id_board = {int:recycle_board}', array('current_member' => $user_info['id'], 'recycle_board' => $modSettings['recycle_board']));
        if ($smcFunc['db_num_rows']($request) == 0) {
            fatal_lang_error('recycle_no_valid_board');
        }
        list($isRead, $last_board_msg) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        // Is there an existing topic in the recycle board to group this post with?
        $request = $smcFunc['db_query']('', '
			SELECT id_topic, id_first_msg, id_last_msg
			FROM {db_prefix}topics
			WHERE id_previous_topic = {int:id_previous_topic}
				AND id_board = {int:recycle_board}', array('id_previous_topic' => $row['id_topic'], 'recycle_board' => $modSettings['recycle_board']));
        list($id_recycle_topic, $first_topic_msg, $last_topic_msg) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        // Insert a new topic in the recycle board if $id_recycle_topic is empty.
        if (empty($id_recycle_topic)) {
            $smcFunc['db_insert']('', '{db_prefix}topics', array('id_board' => 'int', 'id_member_started' => 'int', 'id_member_updated' => 'int', 'id_first_msg' => 'int', 'id_last_msg' => 'int', 'unapproved_posts' => 'int', 'approved' => 'int', 'id_previous_topic' => 'int'), array($modSettings['recycle_board'], $row['id_member'], $row['id_member'], $message, $message, 0, 1, $row['id_topic']), array('id_topic'));
        }
        // Capture the ID of the new topic...
        $topicID = empty($id_recycle_topic) ? $smcFunc['db_insert_id']('{db_prefix}topics', 'id_topic') : $id_recycle_topic;
        // If the topic creation went successful, move the message.
        if ($topicID > 0) {
            $smcFunc['db_query']('', '
				UPDATE {db_prefix}messages
				SET
					id_topic = {int:id_topic},
					id_board = {int:recycle_board},
					icon = {string:recycled},
					approved = {int:is_approved}
				WHERE id_msg = {int:id_msg}', array('id_topic' => $topicID, 'recycle_board' => $modSettings['recycle_board'], 'id_msg' => $message, 'recycled' => 'recycled', 'is_approved' => 1));
            // Take any reported posts with us...
            $smcFunc['db_query']('', '
				UPDATE {db_prefix}log_reported
				SET
					id_topic = {int:id_topic},
					id_board = {int:recycle_board}
				WHERE id_msg = {int:id_msg}', array('id_topic' => $topicID, 'recycle_board' => $modSettings['recycle_board'], 'id_msg' => $message));
            // Mark recycled topic as read.
            if (!$user_info['is_guest']) {
                $smcFunc['db_insert']('replace', '{db_prefix}log_topics', array('id_topic' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($topicID, $user_info['id'], $modSettings['maxMsgID']), array('id_topic', 'id_member'));
            }
            // Mark recycle board as seen, if it was marked as seen before.
            if (!empty($isRead) && !$user_info['is_guest']) {
                $smcFunc['db_insert']('replace', '{db_prefix}log_boards', array('id_board' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($modSettings['recycle_board'], $user_info['id'], $modSettings['maxMsgID']), array('id_board', 'id_member'));
            }
            // Add one topic and post to the recycle bin board.
            $smcFunc['db_query']('', '
				UPDATE {db_prefix}boards
				SET
					num_topics = num_topics + {int:num_topics_inc},
					num_posts = num_posts + 1' . ($message > $last_board_msg ? ', id_last_msg = {int:id_merged_msg}' : '') . '
				WHERE id_board = {int:recycle_board}', array('num_topics_inc' => empty($id_recycle_topic) ? 1 : 0, 'recycle_board' => $modSettings['recycle_board'], 'id_merged_msg' => $message));
            // Lets increase the num_replies, and the first/last message ID as appropriate.
            if (!empty($id_recycle_topic)) {
                $smcFunc['db_query']('', '
					UPDATE {db_prefix}topics
					SET num_replies = num_replies + 1' . ($message > $last_topic_msg ? ', id_last_msg = {int:id_merged_msg}' : '') . ($message < $first_topic_msg ? ', id_first_msg = {int:id_merged_msg}' : '') . '
					WHERE id_topic = {int:id_recycle_topic}', array('id_recycle_topic' => $id_recycle_topic, 'id_merged_msg' => $message));
            }
            // Make sure this message isn't getting deleted later on.
            $recycle = true;
            // Make sure we update the search subject index.
            updateStats('subject', $topicID, $row['subject']);
        }
        // If it wasn't approved don't keep it in the queue.
        if (!$row['approved']) {
            $smcFunc['db_query']('', '
				DELETE FROM {db_prefix}approval_queue
				WHERE id_msg = {int:id_msg}
					AND id_attach = {int:id_attach}', array('id_msg' => $message, 'id_attach' => 0));
        }
    }
    $smcFunc['db_query']('', '
		UPDATE {db_prefix}boards
		SET ' . ($row['approved'] ? '
			num_posts = CASE WHEN num_posts = {int:no_posts} THEN 0 ELSE num_posts - 1 END' : '
			unapproved_posts = CASE WHEN unapproved_posts = {int:no_unapproved} THEN 0 ELSE unapproved_posts - 1 END') . '
		WHERE id_board = {int:id_board}', array('no_posts' => 0, 'no_unapproved' => 0, 'id_board' => $row['id_board']));
    // If the poster was registered and the board this message was on incremented
    // the member's posts when it was posted, decrease his or her post count.
    if (!empty($row['id_member']) && $decreasePostCount && empty($row['count_posts']) && $row['approved']) {
        updateMemberData($row['id_member'], array('posts' => '-'));
    }
    // Only remove posts if they're not recycled.
    if (!$recycle) {
        // Remove the message!
        $smcFunc['db_query']('', '
			DELETE FROM {db_prefix}messages
			WHERE id_msg = {int:id_msg}', array('id_msg' => $message));
        if (!empty($modSettings['search_custom_index_config'])) {
            $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
            $words = text2words($row['body'], $customIndexSettings['bytes_per_word'], true);
            if (!empty($words)) {
                $smcFunc['db_query']('', '
					DELETE FROM {db_prefix}log_search_words
					WHERE id_word IN ({array_int:word_list})
						AND id_msg = {int:id_msg}', array('word_list' => $words, 'id_msg' => $message));
            }
        }
        // Delete attachment(s) if they exist.
        require_once $sourcedir . '/ManageAttachments.php';
        $attachmentQuery = array('attachment_type' => 0, 'id_msg' => $message);
        removeAttachments($attachmentQuery);
        // Allow mods to remove message related data of their own (likes, maybe?)
        call_integration_hook('integrate_remove_message', array($message));
    }
    // Update the pesky statistics.
    updateStats('message');
    updateStats('topic');
    updateSettings(array('calendar_updated' => time()));
    // And now to update the last message of each board we messed with.
    require_once $sourcedir . '/Subs-Post.php';
    if ($recycle) {
        updateLastMessages(array($row['id_board'], $modSettings['recycle_board']));
    } else {
        updateLastMessages($row['id_board']);
    }
    return false;
}
コード例 #7
0
ファイル: Subs-Post.php プロジェクト: AhoyLemon/ballpit
function modifyPost(&$msgOptions, &$topicOptions, &$posterOptions)
{
    global $user_info, $modSettings, $smcFunc, $context;
    $topicOptions['poll'] = isset($topicOptions['poll']) ? (int) $topicOptions['poll'] : null;
    $topicOptions['lock_mode'] = isset($topicOptions['lock_mode']) ? $topicOptions['lock_mode'] : null;
    $topicOptions['sticky_mode'] = isset($topicOptions['sticky_mode']) ? $topicOptions['sticky_mode'] : null;
    // This is longer than it has to be, but makes it so we only set/change what we have to.
    $messages_columns = array();
    if (isset($posterOptions['name'])) {
        $messages_columns['poster_name'] = $posterOptions['name'];
    }
    if (isset($posterOptions['email'])) {
        $messages_columns['poster_email'] = $posterOptions['email'];
    }
    if (isset($msgOptions['icon'])) {
        $messages_columns['icon'] = $msgOptions['icon'];
    }
    if (isset($msgOptions['subject'])) {
        $messages_columns['subject'] = $msgOptions['subject'];
    }
    if (isset($msgOptions['body'])) {
        $messages_columns['body'] = $msgOptions['body'];
        if (!empty($modSettings['search_custom_index_config'])) {
            $request = $smcFunc['db_query']('', '
				SELECT body
				FROM {db_prefix}messages
				WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id']));
            list($old_body) = $smcFunc['db_fetch_row']($request);
            $smcFunc['db_free_result']($request);
        }
    }
    if (!empty($msgOptions['modify_time'])) {
        $messages_columns['modified_time'] = $msgOptions['modify_time'];
        $messages_columns['modified_name'] = $msgOptions['modify_name'];
        $messages_columns['id_msg_modified'] = $modSettings['maxMsgID'];
    }
    if (isset($msgOptions['smileys_enabled'])) {
        $messages_columns['smileys_enabled'] = empty($msgOptions['smileys_enabled']) ? 0 : 1;
    }
    // Which columns need to be ints?
    $messageInts = array('modified_time', 'id_msg_modified', 'smileys_enabled');
    $update_parameters = array('id_msg' => $msgOptions['id']);
    foreach ($messages_columns as $var => $val) {
        $messages_columns[$var] = $var . ' = {' . (in_array($var, $messageInts) ? 'int' : 'string') . ':var_' . $var . '}';
        $update_parameters['var_' . $var] = $val;
    }
    // Nothing to do?
    if (empty($messages_columns)) {
        return true;
    }
    // Change the post.
    $smcFunc['db_query']('', '
		UPDATE {db_prefix}messages
		SET ' . implode(', ', $messages_columns) . '
		WHERE id_msg = {int:id_msg}', $update_parameters);
    // Lock and or sticky the post.
    if ($topicOptions['sticky_mode'] !== null || $topicOptions['lock_mode'] !== null || $topicOptions['poll'] !== null) {
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}topics
			SET
				is_sticky = {raw:is_sticky},
				locked = {raw:locked},
				id_poll = {raw:id_poll}
			WHERE id_topic = {int:id_topic}', array('is_sticky' => $topicOptions['sticky_mode'] === null ? 'is_sticky' : (int) $topicOptions['sticky_mode'], 'locked' => $topicOptions['lock_mode'] === null ? 'locked' : (int) $topicOptions['lock_mode'], 'id_poll' => $topicOptions['poll'] === null ? 'id_poll' : (int) $topicOptions['poll'], 'id_topic' => $topicOptions['id']));
    }
    // Mark the edited post as read.
    if (!empty($topicOptions['mark_as_read']) && !$user_info['is_guest']) {
        // Since it's likely they *read* it before editing, let's try an UPDATE first.
        $smcFunc['db_query']('', '
			UPDATE {db_prefix}log_topics
			SET id_msg = {int:id_msg}
			WHERE id_member = {int:current_member}
				AND id_topic = {int:id_topic}', array('current_member' => $user_info['id'], 'id_msg' => $modSettings['maxMsgID'], 'id_topic' => $topicOptions['id']));
        $flag = $smcFunc['db_affected_rows']() != 0;
        if (empty($flag)) {
            $smcFunc['db_insert']('ignore', '{db_prefix}log_topics', array('id_topic' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($topicOptions['id'], $user_info['id'], $modSettings['maxMsgID']), array('id_topic', 'id_member'));
        }
    }
    // If there's a custom search index, it needs to be modified...
    if (isset($msgOptions['body']) && !empty($modSettings['search_custom_index_config'])) {
        $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
        $stopwords = empty($modSettings['search_stopwords']) ? array() : explode(',', $modSettings['search_stopwords']);
        $old_index = text2words($old_body, $customIndexSettings['bytes_per_word'], true);
        $new_index = text2words($msgOptions['body'], $customIndexSettings['bytes_per_word'], true);
        // Calculate the words to be added and removed from the index.
        $removed_words = array_diff(array_diff($old_index, $new_index), $stopwords);
        $inserted_words = array_diff(array_diff($new_index, $old_index), $stopwords);
        // Delete the removed words AND the added ones to avoid key constraints.
        if (!empty($removed_words)) {
            $removed_words = array_merge($removed_words, $inserted_words);
            $smcFunc['db_query']('', '
				DELETE FROM {db_prefix}log_search_words
				WHERE id_msg = {int:id_msg}
					AND id_word IN ({array_int:removed_words})', array('removed_words' => $removed_words, 'id_msg' => $msgOptions['id']));
        }
        // Add the new words to be indexed.
        if (!empty($inserted_words)) {
            $inserts = array();
            foreach ($inserted_words as $word) {
                $inserts[] = array($word, $msgOptions['id']);
            }
            $smcFunc['db_insert']('insert', '{db_prefix}log_search_words', array('id_word' => 'string', 'id_msg' => 'int'), $inserts, array('id_word', 'id_msg'));
        }
    }
    if (isset($msgOptions['subject'])) {
        // Only update the subject if this was the first message in the topic.
        $request = $smcFunc['db_query']('', '
			SELECT id_topic
			FROM {db_prefix}topics
			WHERE id_first_msg = {int:id_first_msg}
			LIMIT 1', array('id_first_msg' => $msgOptions['id']));
        if ($smcFunc['db_num_rows']($request) == 1) {
            updateStats('subject', $topicOptions['id'], $msgOptions['subject']);
        }
        $smcFunc['db_free_result']($request);
    }
    // Finally, if we are setting the approved state we need to do much more work :(
    if ($modSettings['postmod_active'] && isset($msgOptions['approved'])) {
        approvePosts($msgOptions['id'], $msgOptions['approved']);
    }
    return true;
}
コード例 #8
0
ファイル: Subs.backup.2.php プロジェクト: AhoyLemon/ballpit
function updateStats($type, $parameter1 = null, $parameter2 = null)
{
    global $sourcedir, $modSettings, $smcFunc;
    switch ($type) {
        case 'member':
            $changes = array('memberlist_updated' => time());
            // #1 latest member ID, #2 the real name for a new registration.
            if (is_numeric($parameter1)) {
                $changes['latestMember'] = $parameter1;
                $changes['latestRealName'] = $parameter2;
                updateSettings(array('totalMembers' => true), true);
            } else {
                // Update the latest activated member (highest id_member) and count.
                $result = $smcFunc['db_query']('', '
				SELECT COUNT(*), MAX(id_member)
				FROM {db_prefix}members
				WHERE is_activated = {int:is_activated}', array('is_activated' => 1));
                list($changes['totalMembers'], $changes['latestMember']) = $smcFunc['db_fetch_row']($result);
                $smcFunc['db_free_result']($result);
                // Get the latest activated member's display name.
                $result = $smcFunc['db_query']('', '
				SELECT real_name
				FROM {db_prefix}members
				WHERE id_member = {int:id_member}
				LIMIT 1', array('id_member' => (int) $changes['latestMember']));
                list($changes['latestRealName']) = $smcFunc['db_fetch_row']($result);
                $smcFunc['db_free_result']($result);
                // Are we using registration approval?
                if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2 || !empty($modSettings['approveAccountDeletion'])) {
                    // Update the amount of members awaiting approval - ignoring COPPA accounts, as you can't approve them until you get permission.
                    $result = $smcFunc['db_query']('', '
					SELECT COUNT(*)
					FROM {db_prefix}members
					WHERE is_activated IN ({array_int:activation_status})', array('activation_status' => array(3, 4)));
                    list($changes['unapprovedMembers']) = $smcFunc['db_fetch_row']($result);
                    $smcFunc['db_free_result']($result);
                }
            }
            updateSettings($changes);
            break;
        case 'message':
            if ($parameter1 === true && $parameter2 !== null) {
                updateSettings(array('totalMessages' => true, 'maxMsgID' => $parameter2), true);
            } else {
                // SUM and MAX on a smaller table is better for InnoDB tables.
                $result = $smcFunc['db_query']('', '
				SELECT SUM(num_posts + unapproved_posts) AS total_messages, MAX(id_last_msg) AS max_msg_id
				FROM {db_prefix}boards
				WHERE redirect = {string:blank_redirect}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
					AND id_board != {int:recycle_board}' : ''), array('recycle_board' => isset($modSettings['recycle_board']) ? $modSettings['recycle_board'] : 0, 'blank_redirect' => ''));
                $row = $smcFunc['db_fetch_assoc']($result);
                $smcFunc['db_free_result']($result);
                updateSettings(array('totalMessages' => $row['total_messages'] === null ? 0 : $row['total_messages'], 'maxMsgID' => $row['max_msg_id'] === null ? 0 : $row['max_msg_id']));
            }
            break;
        case 'subject':
            // Remove the previous subject (if any).
            $smcFunc['db_query']('', '
			DELETE FROM {db_prefix}log_search_subjects
			WHERE id_topic = {int:id_topic}', array('id_topic' => (int) $parameter1));
            // Insert the new subject.
            if ($parameter2 !== null) {
                $parameter1 = (int) $parameter1;
                $parameter2 = text2words($parameter2);
                $inserts = array();
                foreach ($parameter2 as $word) {
                    $inserts[] = array($word, $parameter1);
                }
                if (!empty($inserts)) {
                    $smcFunc['db_insert']('ignore', '{db_prefix}log_search_subjects', array('word' => 'string', 'id_topic' => 'int'), $inserts, array('word', 'id_topic'));
                }
            }
            break;
        case 'topic':
            if ($parameter1 === true) {
                updateSettings(array('totalTopics' => true), true);
            } else {
                // Get the number of topics - a SUM is better for InnoDB tables.
                // We also ignore the recycle bin here because there will probably be a bunch of one-post topics there.
                $result = $smcFunc['db_query']('', '
				SELECT SUM(num_topics + unapproved_topics) AS total_topics
				FROM {db_prefix}boards' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
				WHERE id_board != {int:recycle_board}' : ''), array('recycle_board' => !empty($modSettings['recycle_board']) ? $modSettings['recycle_board'] : 0));
                $row = $smcFunc['db_fetch_assoc']($result);
                $smcFunc['db_free_result']($result);
                updateSettings(array('totalTopics' => $row['total_topics'] === null ? 0 : $row['total_topics']));
            }
            break;
        case 'postgroups':
            // Parameter two is the updated columns: we should check to see if we base groups off any of these.
            if ($parameter2 !== null && !in_array('posts', $parameter2)) {
                return;
            }
            if (($postgroups = cache_get_data('updateStats:postgroups', 360)) == null) {
                // Fetch the postgroups!
                $request = $smcFunc['db_query']('', '
				SELECT id_group, min_posts
				FROM {db_prefix}membergroups
				WHERE min_posts != {int:min_posts}', array('min_posts' => -1));
                $postgroups = array();
                while ($row = $smcFunc['db_fetch_assoc']($request)) {
                    $postgroups[$row['id_group']] = $row['min_posts'];
                }
                $smcFunc['db_free_result']($request);
                // Sort them this way because if it's done with MySQL it causes a filesort :(.
                arsort($postgroups);
                cache_put_data('updateStats:postgroups', $postgroups, 360);
            }
            // Oh great, they've screwed their post groups.
            if (empty($postgroups)) {
                return;
            }
            // Set all membergroups from most posts to least posts.
            $conditions = '';
            foreach ($postgroups as $id => $min_posts) {
                $conditions .= '
					WHEN posts >= ' . $min_posts . (!empty($lastMin) ? ' AND posts <= ' . $lastMin : '') . ' THEN ' . $id;
                $lastMin = $min_posts;
            }
            // A big fat CASE WHEN... END is faster than a zillion UPDATE's ;).
            $smcFunc['db_query']('', '
			UPDATE {db_prefix}members
			SET id_post_group = CASE ' . $conditions . '
					ELSE 0
				END' . ($parameter1 != null ? '
			WHERE ' . (is_array($parameter1) ? 'id_member IN ({array_int:members})' : 'id_member = {int:members}') : ''), array('members' => $parameter1));
            break;
        default:
            trigger_error('updateStats(): Invalid statistic type \'' . $type . '\'', E_USER_NOTICE);
    }
}
コード例 #9
0
ファイル: Subs-Post.php プロジェクト: norv/EosAlpha
function modifyPost(&$msgOptions, &$topicOptions, &$posterOptions)
{
    global $user_info, $modSettings, $context, $sourcedir;
    $topicOptions['poll'] = isset($topicOptions['poll']) ? (int) $topicOptions['poll'] : null;
    $topicOptions['lock_mode'] = isset($topicOptions['lock_mode']) ? $topicOptions['lock_mode'] : null;
    $topicOptions['sticky_mode'] = isset($topicOptions['sticky_mode']) ? $topicOptions['sticky_mode'] : null;
    $tagged_users = array();
    $context['can_tag_users'] = allowedTo('tag_users');
    if (isset($msgOptions['body'])) {
        $tagged_users = handleUserTags($msgOptions['body']);
    }
    // This is longer than it has to be, but makes it so we only set/change what we have to.
    $messages_columns = array();
    if (isset($posterOptions['name'])) {
        $messages_columns['poster_name'] = $posterOptions['name'];
    }
    if (isset($posterOptions['email'])) {
        $messages_columns['poster_email'] = $posterOptions['email'];
    }
    if (isset($msgOptions['icon'])) {
        $messages_columns['icon'] = $msgOptions['icon'];
    }
    if (isset($msgOptions['subject'])) {
        $messages_columns['subject'] = $msgOptions['subject'];
    }
    if (isset($msgOptions['body'])) {
        $messages_columns['body'] = $msgOptions['body'];
        if (!empty($modSettings['search_custom_index_config'])) {
            $request = smf_db_query('
				SELECT body, smileys_enabled
				FROM {db_prefix}messages
				WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id']));
            list($old_body, $old_smileys_enabled) = mysql_fetch_row($request);
            mysql_free_result($request);
        }
    }
    if (isset($msgOptions['locked'])) {
        $messages_columns['locked'] = $msgOptions['locked'];
    }
    if (!empty($msgOptions['modify_time'])) {
        $messages_columns['modified_time'] = $msgOptions['modify_time'];
        $messages_columns['modified_name'] = $msgOptions['modify_name'];
        $messages_columns['id_msg_modified'] = $modSettings['maxMsgID'];
    }
    if (isset($msgOptions['smileys_enabled'])) {
        $messages_columns['smileys_enabled'] = empty($msgOptions['smileys_enabled']) ? 0 : 1;
        $smileys_enabled = $msgOptions['smileys_enabled'];
    } else {
        if (isset($msgOptions['body'])) {
            $smileys_enabled = $old_smileys_enabled;
        }
    }
    // Which columns need to be ints?
    $messageInts = array('modified_time', 'id_msg_modified', 'smileys_enabled');
    $update_parameters = array('id_msg' => $msgOptions['id']);
    foreach ($messages_columns as $var => $val) {
        $messages_columns[$var] = $var . ' = {' . (in_array($var, $messageInts) ? 'int' : 'string') . ':var_' . $var . '}';
        $update_parameters['var_' . $var] = $val;
    }
    // Nothing to do?
    if (empty($messages_columns)) {
        return true;
    }
    // Change the post.
    smf_db_query('
		UPDATE {db_prefix}messages
		SET ' . implode(', ', $messages_columns) . '
		WHERE id_msg = {int:id_msg}', $update_parameters);
    /*
     * delete cached posts (they will update at the next view)
     */
    if (isset($msgOptions['body'])) {
        smf_db_query('DELETE FROM {db_prefix}messages_cache WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id']));
        CacheAPI::clearCacheByPrefix('parse:' . trim($msgOptions['id']) . '-');
    } else {
        $context['no_astream'] = true;
    }
    $context['no_astream'] = isset($context['no_astream']) ? $context['no_astream'] : 0;
    // Lock and or sticky the post.
    if ($topicOptions['sticky_mode'] !== null || $topicOptions['lock_mode'] !== null || $topicOptions['poll'] !== null) {
        smf_db_query('
			UPDATE {db_prefix}topics
			SET
				is_sticky = {raw:is_sticky},
				locked = {raw:locked},
				id_poll = {raw:id_poll}
			WHERE id_topic = {int:id_topic}', array('is_sticky' => $topicOptions['sticky_mode'] === null ? 'is_sticky' : (int) $topicOptions['sticky_mode'], 'locked' => $topicOptions['lock_mode'] === null ? 'locked' : (int) $topicOptions['lock_mode'], 'id_poll' => $topicOptions['poll'] === null ? 'id_poll' : (int) $topicOptions['poll'], 'id_topic' => $topicOptions['id']));
    }
    if (isset($topicOptions['id_first_msg']) && $msgOptions['id'] == $topicOptions['id_first_msg']) {
        if (isset($topicOptions['topic_prefix'])) {
            smf_db_query('
				UPDATE {db_prefix}topics
				SET
					id_prefix = {int:id_prefix}
				WHERE id_topic = {int:id_topic}', array('id_prefix' => $topicOptions['topic_prefix'], 'id_topic' => $topicOptions['id']));
        }
        if (isset($topicOptions['topic_layout'])) {
            smf_db_query('
				UPDATE {db_prefix}topics
				SET
					id_layout = {int:id_layout}
				WHERE id_topic = {int:id_topic}', array('id_layout' => $topicOptions['topic_layout'], 'id_topic' => $topicOptions['id']));
        }
    }
    // Mark the edited post as read.
    if (!empty($topicOptions['mark_as_read']) && !$user_info['is_guest']) {
        // Since it's likely they *read* it before editing, let's try an UPDATE first.
        smf_db_query('
			UPDATE {db_prefix}log_topics
			SET id_msg = {int:id_msg}
			WHERE id_member = {int:current_member}
				AND id_topic = {int:id_topic}', array('current_member' => $user_info['id'], 'id_msg' => $modSettings['maxMsgID'], 'id_topic' => $topicOptions['id']));
        $flag = smf_db_affected_rows() != 0;
        if (empty($flag)) {
            smf_db_insert('ignore', '{db_prefix}log_topics', array('id_topic' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($topicOptions['id'], $user_info['id'], $modSettings['maxMsgID']), array('id_topic', 'id_member'));
        }
    }
    if (count($tagged_users) > 0) {
        notifyTaggedUsers($tagged_users, array('id_topic' => $topicOptions['id'], 'id_message' => $msgOptions['id']));
    }
    // If there's a custom search index, it needs to be modified...
    if (isset($msgOptions['body']) && !empty($modSettings['search_custom_index_config'])) {
        $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
        $stopwords = empty($modSettings['search_stopwords']) ? array() : explode(',', $modSettings['search_stopwords']);
        $old_index = text2words($old_body, $customIndexSettings['bytes_per_word'], true);
        $new_index = text2words($msgOptions['body'], $customIndexSettings['bytes_per_word'], true);
        // Calculate the words to be added and removed from the index.
        $removed_words = array_diff(array_diff($old_index, $new_index), $stopwords);
        $inserted_words = array_diff(array_diff($new_index, $old_index), $stopwords);
        // Delete the removed words AND the added ones to avoid key constraints.
        if (!empty($removed_words)) {
            $removed_words = array_merge($removed_words, $inserted_words);
            smf_db_query('
				DELETE FROM {db_prefix}log_search_words
				WHERE id_msg = {int:id_msg}
					AND id_word IN ({array_int:removed_words})', array('removed_words' => $removed_words, 'id_msg' => $msgOptions['id']));
        }
        // Add the new words to be indexed.
        if (!empty($inserted_words)) {
            $inserts = array();
            foreach ($inserted_words as $word) {
                $inserts[] = array($word, $msgOptions['id']);
            }
            smf_db_insert('insert', '{db_prefix}log_search_words', array('id_word' => 'string', 'id_msg' => 'int'), $inserts, array('id_word', 'id_msg'));
        }
    }
    if (isset($msgOptions['subject'])) {
        // Only update the subject if this was the first message in the topic.
        $request = smf_db_query('
			SELECT id_topic
			FROM {db_prefix}topics
			WHERE id_first_msg = {int:id_first_msg}
			LIMIT 1', array('id_first_msg' => $msgOptions['id']));
        if (mysql_num_rows($request) == 1) {
            updateStats('subject', $topicOptions['id'], $msgOptions['subject']);
            // Added by Related Topics
            if (isset($modSettings['have_related_topics']) && $modSettings['have_related_topics']) {
                require_once $sourcedir . '/lib/Subs-Related.php';
                relatedUpdateTopics($topicOptions['id']);
            }
            // Related Topics END
        }
        mysql_free_result($request);
    }
    // Finally, if we are setting the approved state we need to do much more work :(
    if ($modSettings['postmod_active'] && isset($msgOptions['approved'])) {
        approvePosts($msgOptions['id'], $msgOptions['approved']);
    }
    // record in activity stream
    if ($modSettings['astream_active'] && !$context['no_astream']) {
        require_once $sourcedir . '/lib/Subs-Activities.php';
        aStreamAdd($user_info['id'], ACT_MODIFY_POST, array('member_name' => $user_info['name'], 'topic_title' => $msgOptions['subject']), $topicOptions['board'], $topicOptions['id'], $msgOptions['id'], $msgOptions['id_owner']);
    }
    return true;
}
コード例 #10
0
ファイル: Subs.php プロジェクト: bbon/mjncms
function updateStats($type, $parameter1 = null, $parameter2 = null)
{
    global $db_prefix, $sourcedir, $modSettings;
    switch ($type) {
        case 'member':
            $changes = array('memberlist_updated' => time());
            // Are we using registration approval?
            if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 2) {
                // Update the latest activated member (highest ID_MEMBER) and count.
                $result = db_query("\n\t\t\t\tSELECT COUNT(*), MAX(ID_MEMBER)\n\t\t\t\tFROM {$db_prefix}members\n\t\t\t\tWHERE is_activated = 1", __FILE__, __LINE__);
                list($changes['totalMembers'], $changes['latestMember']) = mysql_fetch_row($result);
                mysql_free_result($result);
                // Get the latest activated member's display name.
                $result = db_query("\n\t\t\t\tSELECT realName\n\t\t\t\tFROM {$db_prefix}members\n\t\t\t\tWHERE ID_MEMBER = " . (int) $changes['latestMember'] . "\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
                list($changes['latestRealName']) = mysql_fetch_row($result);
                mysql_free_result($result);
                // Update the amount of members awaiting approval - ignoring COPPA accounts, as you can't approve them until you get permission.
                $result = db_query("\n\t\t\t\tSELECT COUNT(*)\n\t\t\t\tFROM {$db_prefix}members\n\t\t\t\tWHERE is_activated IN (3, 4)", __FILE__, __LINE__);
                list($changes['unapprovedMembers']) = mysql_fetch_row($result);
                mysql_free_result($result);
            } elseif ($parameter1 !== null && $parameter1 !== false) {
                $changes['latestMember'] = $parameter1;
                $changes['latestRealName'] = $parameter2;
                updateSettings(array('totalMembers' => true), true);
            } elseif ($parameter1 !== false) {
                // Update the latest member (highest ID_MEMBER) and count.
                $result = db_query("\n\t\t\t\tSELECT COUNT(*), MAX(ID_MEMBER)\n\t\t\t\tFROM {$db_prefix}members", __FILE__, __LINE__);
                list($changes['totalMembers'], $changes['latestMember']) = mysql_fetch_row($result);
                mysql_free_result($result);
                // Get the latest member's display name.
                $result = db_query("\n\t\t\t\tSELECT realName\n\t\t\t\tFROM {$db_prefix}members\n\t\t\t\tWHERE ID_MEMBER = " . (int) $changes['latestMember'] . "\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
                list($changes['latestRealName']) = mysql_fetch_row($result);
                mysql_free_result($result);
            }
            updateSettings($changes);
            break;
        case 'message':
            if ($parameter1 === true && $parameter2 !== null) {
                updateSettings(array('totalMessages' => true, 'maxMsgID' => $parameter2), true);
            } else {
                // SUM and MAX on a smaller table is better for InnoDB tables.
                $result = db_query("\n\t\t\t\tSELECT SUM(numPosts) AS totalMessages, MAX(ID_LAST_MSG) AS maxMsgID\n\t\t\t\tFROM {$db_prefix}boards", __FILE__, __LINE__);
                $row = mysql_fetch_assoc($result);
                mysql_free_result($result);
                updateSettings(array('totalMessages' => $row['totalMessages'], 'maxMsgID' => $row['maxMsgID'] === null ? 0 : $row['maxMsgID']));
            }
            break;
        case 'subject':
            // Remove the previous subject (if any).
            db_query("\n\t\t\tDELETE FROM {$db_prefix}log_search_subjects\n\t\t\tWHERE ID_TOPIC = " . (int) $parameter1, __FILE__, __LINE__);
            // Insert the new subject.
            if ($parameter2 !== null) {
                $parameter1 = (int) $parameter1;
                $parameter2 = text2words($parameter2);
                $inserts = array();
                foreach ($parameter2 as $word) {
                    $inserts[] = "'{$word}', {$parameter1}";
                }
                if (!empty($inserts)) {
                    db_query("\n\t\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_search_subjects\n\t\t\t\t\t\t(word, ID_TOPIC)\n\t\t\t\t\tVALUES (" . implode('),
						(', array_unique($inserts)) . ")", __FILE__, __LINE__);
                }
            }
            break;
        case 'topic':
            if ($parameter1 === true) {
                updateSettings(array('totalTopics' => true), true);
            } else {
                // Get the number of topics - a SUM is better for InnoDB tables.
                // We also ignore the recycle bin here because there will probably be a bunch of one-post topics there.
                $result = db_query("\n\t\t\t\tSELECT SUM(numTopics) AS totalTopics\n\t\t\t\tFROM {$db_prefix}boards" . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? "\n\t\t\t\tWHERE ID_BOARD != {$modSettings['recycle_board']}" : ''), __FILE__, __LINE__);
                $row = mysql_fetch_assoc($result);
                mysql_free_result($result);
                updateSettings(array('totalTopics' => $row['totalTopics']));
            }
            break;
        case 'calendar':
            require_once $sourcedir . '/Calendar.php';
            // Calculate the YYYY-MM-DD of the lowest and highest days.
            $low_date = strftime('%Y-%m-%d', forum_time(false) - 24 * 3600);
            $high_date = strftime('%Y-%m-%d', forum_time(false) + $modSettings['cal_days_for_index'] * 24 * 3600);
            $holidays = calendarHolidayArray($low_date, $high_date);
            $bday = calendarBirthdayArray($low_date, $high_date);
            $events = calendarEventArray($low_date, $high_date, false);
            // Cache the results in the settings.
            updateSettings(array('cal_today_updated' => strftime('%Y%m%d', forum_time(false)), 'cal_today_holiday' => addslashes(serialize($holidays)), 'cal_today_birthday' => addslashes(serialize($bday)), 'cal_today_event' => addslashes(serialize($events))));
            break;
        case 'postgroups':
            // Parameter two is the updated columns: we should check to see if we base groups off any of these.
            if ($parameter2 !== null && !in_array('posts', $parameter2)) {
                return;
            }
            if (($postgroups = cache_get_data('updateStats:postgroups', 360)) == null) {
                // Fetch the postgroups!
                $request = db_query("\n\t\t\t\tSELECT ID_GROUP, minPosts\n\t\t\t\tFROM {$db_prefix}membergroups\n\t\t\t\tWHERE minPosts != -1", __FILE__, __LINE__);
                $postgroups = array();
                while ($row = mysql_fetch_assoc($request)) {
                    $postgroups[$row['ID_GROUP']] = $row['minPosts'];
                }
                mysql_free_result($request);
                // Sort them this way because if it's done with MySQL it causes a filesort :(.
                arsort($postgroups);
                cache_put_data('updateStats:postgroups', $postgroups, 360);
            }
            // Oh great, they've screwed their post groups.
            if (empty($postgroups)) {
                return;
            }
            // Set all membergroups from most posts to least posts.
            $conditions = '';
            foreach ($postgroups as $id => $minPosts) {
                $conditions .= '
					WHEN posts >= ' . $minPosts . (!empty($lastMin) ? ' AND posts <= ' . $lastMin : '') . ' THEN ' . $id;
                $lastMin = $minPosts;
            }
            // A big fat CASE WHEN... END is faster than a zillion UPDATE's ;).
            db_query("\n\t\t\tUPDATE {$db_prefix}members\n\t\t\tSET ID_POST_GROUP = CASE{$conditions}\n\t\t\t\t\tELSE 0\n\t\t\t\tEND" . ($parameter1 != null ? "\n\t\t\tWHERE {$parameter1}" : ''), __FILE__, __LINE__);
            break;
        default:
            trigger_error('updateStats(): Invalid statistic type \'' . $type . '\'', E_USER_NOTICE);
    }
}
コード例 #11
0
ファイル: Search.php プロジェクト: chenhao6593/smf
function PlushSearch2()
{
    global $scripturl, $modSettings, $sourcedir, $txt, $db_connection;
    global $user_info, $context, $options, $messages_request, $boards_can;
    global $excludedWords, $participants, $smcFunc, $search_versions, $searchAPI;
    if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) {
        fatal_lang_error('loadavg_search_disabled', false);
    }
    // No, no, no... this is a bit hard on the server, so don't you go prefetching it!
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Forbidden');
        die;
    }
    $weight_factors = array('frequency', 'age', 'length', 'subject', 'first_message', 'sticky');
    $weight = array();
    $weight_total = 0;
    foreach ($weight_factors as $weight_factor) {
        $weight[$weight_factor] = empty($modSettings['search_weight_' . $weight_factor]) ? 0 : (int) $modSettings['search_weight_' . $weight_factor];
        $weight_total += $weight[$weight_factor];
    }
    // Zero weight.  Weightless :P.
    if (empty($weight_total)) {
        fatal_lang_error('search_invalid_weights');
    }
    // These vars don't require an interface, they're just here for tweaking.
    $recentPercentage = 0.3;
    $humungousTopicPosts = 200;
    $maxMembersToSearch = 500;
    $maxMessageResults = empty($modSettings['search_max_results']) ? 0 : $modSettings['search_max_results'] * 5;
    // Start with no errors.
    $context['search_errors'] = array();
    // Number of pages hard maximum - normally not set at all.
    $modSettings['search_max_results'] = empty($modSettings['search_max_results']) ? 200 * $modSettings['search_results_per_page'] : (int) $modSettings['search_max_results'];
    // Maximum length of the string.
    $context['search_string_limit'] = 100;
    loadLanguage('Search');
    if (!isset($_REQUEST['xml'])) {
        loadTemplate('Search');
    } else {
        $context['sub_template'] = 'results';
    }
    // Are you allowed?
    isAllowedTo('search_posts');
    require_once $sourcedir . '/Display.php';
    require_once $sourcedir . '/Subs-Package.php';
    // Search has a special database set.
    db_extend('search');
    // Load up the search API we are going to use.
    $modSettings['search_index'] = empty($modSettings['search_index']) ? 'standard' : $modSettings['search_index'];
    if (!file_exists($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php')) {
        fatal_lang_error('search_api_missing');
    }
    loadClassFile('SearchAPI-' . ucwords($modSettings['search_index']) . '.php');
    // Create an instance of the search API and check it is valid for this version of SMF.
    $search_class_name = $modSettings['search_index'] . '_search';
    $searchAPI = new $search_class_name();
    if (!$searchAPI || $searchAPI->supportsMethod('isValid') && !$searchAPI->isValid() || !matchPackageVersion($search_versions['forum_version'], $searchAPI->min_smf_version . '-' . $searchAPI->version_compatible)) {
        // Log the error.
        loadLanguage('Errors');
        log_error(sprintf($txt['search_api_not_compatible'], 'SearchAPI-' . ucwords($modSettings['search_index']) . '.php'), 'critical');
        loadClassFile('SearchAPI-Standard.php');
        $searchAPI = new standard_search();
    }
    // $search_params will carry all settings that differ from the default search parameters.
    // That way, the URLs involved in a search page will be kept as short as possible.
    $search_params = array();
    if (isset($_REQUEST['params'])) {
        // Due to IE's 2083 character limit, we have to compress long search strings
        $temp_params = base64_decode(str_replace(array('-', '_', '.'), array('+', '/', '='), $_REQUEST['params']));
        // Test for gzuncompress failing
        $temp_params2 = @gzuncompress($temp_params);
        $temp_params = explode('|"|', !empty($temp_params2) ? $temp_params2 : $temp_params);
        foreach ($temp_params as $i => $data) {
            @(list($k, $v) = explode('|\'|', $data));
            $search_params[$k] = $v;
        }
        if (isset($search_params['brd'])) {
            $search_params['brd'] = empty($search_params['brd']) ? array() : explode(',', $search_params['brd']);
        }
    }
    // Store whether simple search was used (needed if the user wants to do another query).
    if (!isset($search_params['advanced'])) {
        $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1;
    }
    // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'.
    if (!empty($search_params['searchtype']) || !empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2) {
        $search_params['searchtype'] = 2;
    }
    // Minimum age of messages. Default to zero (don't set param in that case).
    if (!empty($search_params['minage']) || !empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0) {
        $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage'];
    }
    // Maximum age of messages. Default to infinite (9999 days: param not set).
    if (!empty($search_params['maxage']) || !empty($_REQUEST['maxage']) && $_REQUEST['maxage'] < 9999) {
        $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage'];
    }
    // Searching a specific topic?
    if (!empty($_REQUEST['topic'])) {
        $search_params['topic'] = (int) $_REQUEST['topic'];
        $search_params['show_complete'] = true;
    } elseif (!empty($search_params['topic'])) {
        $search_params['topic'] = (int) $search_params['topic'];
    }
    if (!empty($search_params['minage']) || !empty($search_params['maxage'])) {
        $request = $smcFunc['db_query']('', '
			SELECT ' . (empty($search_params['maxage']) ? '0, ' : 'IFNULL(MIN(id_msg), -1), ') . (empty($search_params['minage']) ? '0' : 'IFNULL(MAX(id_msg), -1)') . '
			FROM {db_prefix}messages
			WHERE 1=1' . ($modSettings['postmod_active'] ? '
				AND approved = {int:is_approved_true}' : '') . (empty($search_params['minage']) ? '' : '
				AND poster_time <= {int:timestamp_minimum_age}') . (empty($search_params['maxage']) ? '' : '
				AND poster_time >= {int:timestamp_maximum_age}'), array('timestamp_minimum_age' => empty($search_params['minage']) ? 0 : time() - 86400 * $search_params['minage'], 'timestamp_maximum_age' => empty($search_params['maxage']) ? 0 : time() - 86400 * $search_params['maxage'], 'is_approved_true' => 1));
        list($minMsgID, $maxMsgID) = $smcFunc['db_fetch_row']($request);
        if ($minMsgID < 0 || $maxMsgID < 0) {
            $context['search_errors']['no_messages_in_time_frame'] = true;
        }
        $smcFunc['db_free_result']($request);
    }
    // Default the user name to a wildcard matching every user (*).
    if (!empty($search_params['userspec']) || !empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*') {
        $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec'];
    }
    // If there's no specific user, then don't mention it in the main query.
    if (empty($search_params['userspec'])) {
        $userQuery = '';
    } else {
        $userString = strtr($smcFunc['htmlspecialchars']($search_params['userspec'], ENT_QUOTES), array('&quot;' => '"'));
        $userString = strtr($userString, array('%' => '\\%', '_' => '\\_', '*' => '%', '?' => '_'));
        preg_match_all('~"([^"]+)"~', $userString, $matches);
        $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString)));
        for ($k = 0, $n = count($possible_users); $k < $n; $k++) {
            $possible_users[$k] = trim($possible_users[$k]);
            if (strlen($possible_users[$k]) == 0) {
                unset($possible_users[$k]);
            }
        }
        // Create a list of database-escaped search names.
        $realNameMatches = array();
        foreach ($possible_users as $possible_user) {
            $realNameMatches[] = $smcFunc['db_quote']('{string:possible_user}', array('possible_user' => $possible_user));
        }
        // Retrieve a list of possible members.
        $request = $smcFunc['db_query']('', '
			SELECT id_member
			FROM {db_prefix}members
			WHERE {raw:match_possible_users}', array('match_possible_users' => 'real_name LIKE ' . implode(' OR real_name LIKE ', $realNameMatches)));
        // Simply do nothing if there're too many members matching the criteria.
        if ($smcFunc['db_num_rows']($request) > $maxMembersToSearch) {
            $userQuery = '';
        } elseif ($smcFunc['db_num_rows']($request) == 0) {
            $userQuery = $smcFunc['db_quote']('m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})', array('id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches)));
        } else {
            $memberlist = array();
            while ($row = $smcFunc['db_fetch_assoc']($request)) {
                $memberlist[] = $row['id_member'];
            }
            $userQuery = $smcFunc['db_quote']('(m.id_member IN ({array_int:matched_members}) OR (m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})))', array('matched_members' => $memberlist, 'id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches)));
        }
        $smcFunc['db_free_result']($request);
    }
    // If the boards were passed by URL (params=), temporarily put them back in $_REQUEST.
    if (!empty($search_params['brd']) && is_array($search_params['brd'])) {
        $_REQUEST['brd'] = $search_params['brd'];
    }
    // Ensure that brd is an array.
    if (!empty($_REQUEST['brd']) && !is_array($_REQUEST['brd'])) {
        $_REQUEST['brd'] = strpos($_REQUEST['brd'], ',') !== false ? explode(',', $_REQUEST['brd']) : array($_REQUEST['brd']);
    }
    // Make sure all boards are integers.
    if (!empty($_REQUEST['brd'])) {
        foreach ($_REQUEST['brd'] as $id => $brd) {
            $_REQUEST['brd'][$id] = (int) $brd;
        }
    }
    // Special case for boards: searching just one topic?
    if (!empty($search_params['topic'])) {
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			WHERE t.id_topic = {int:search_topic_id}
				AND {query_see_board}' . ($modSettings['postmod_active'] ? '
				AND t.approved = {int:is_approved_true}' : '') . '
			LIMIT 1', array('search_topic_id' => $search_params['topic'], 'is_approved_true' => 1));
        if ($smcFunc['db_num_rows']($request) == 0) {
            fatal_lang_error('topic_gone', false);
        }
        $search_params['brd'] = array();
        list($search_params['brd'][0]) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
    } elseif ($user_info['is_admin'] && (!empty($search_params['advanced']) || !empty($_REQUEST['brd']))) {
        $search_params['brd'] = empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'];
    } else {
        $see_board = empty($search_params['advanced']) ? 'query_wanna_see_board' : 'query_see_board';
        $request = $smcFunc['db_query']('', '
			SELECT b.id_board
			FROM {db_prefix}boards AS b
			WHERE {raw:boards_allowed_to_see}
				AND redirect = {string:empty_string}' . (empty($_REQUEST['brd']) ? !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
				AND b.id_board != {int:recycle_board_id}' : '' : '
				AND b.id_board IN ({array_int:selected_search_boards})'), array('boards_allowed_to_see' => $user_info[$see_board], 'empty_string' => '', 'selected_search_boards' => empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'], 'recycle_board_id' => $modSettings['recycle_board']));
        $search_params['brd'] = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $search_params['brd'][] = $row['id_board'];
        }
        $smcFunc['db_free_result']($request);
        // This error should pro'bly only happen for hackers.
        if (empty($search_params['brd'])) {
            $context['search_errors']['no_boards_selected'] = true;
        }
    }
    if (count($search_params['brd']) != 0) {
        foreach ($search_params['brd'] as $k => $v) {
            $search_params['brd'][$k] = (int) $v;
        }
        // If we've selected all boards, this parameter can be left empty.
        $request = $smcFunc['db_query']('', '
			SELECT COUNT(*)
			FROM {db_prefix}boards
			WHERE redirect = {string:empty_string}', array('empty_string' => ''));
        list($num_boards) = $smcFunc['db_fetch_row']($request);
        $smcFunc['db_free_result']($request);
        if (count($search_params['brd']) == $num_boards) {
            $boardQuery = '';
        } elseif (count($search_params['brd']) == $num_boards - 1 && !empty($modSettings['recycle_board']) && !in_array($modSettings['recycle_board'], $search_params['brd'])) {
            $boardQuery = '!= ' . $modSettings['recycle_board'];
        } else {
            $boardQuery = 'IN (' . implode(', ', $search_params['brd']) . ')';
        }
    } else {
        $boardQuery = '';
    }
    $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
    $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
    $context['compact'] = !$search_params['show_complete'];
    // Get the sorting parameters right. Default to sort by relevance descending.
    $sort_columns = array('relevance', 'num_replies', 'id_msg');
    if (empty($search_params['sort']) && !empty($_REQUEST['sort'])) {
        list($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, '');
    }
    $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'relevance';
    if (!empty($search_params['topic']) && $search_params['sort'] === 'num_replies') {
        $search_params['sort'] = 'id_msg';
    }
    // Sorting direction: descending unless stated otherwise.
    $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
    // Determine some values needed to calculate the relevance.
    $minMsg = (int) ((1 - $recentPercentage) * $modSettings['maxMsgID']);
    $recentMsg = $modSettings['maxMsgID'] - $minMsg;
    // *** Parse the search query
    // Unfortunately, searching for words like this is going to be slow, so we're blacklisting them.
    // !!! Setting to add more here?
    // !!! Maybe only blacklist if they are the only word, or "any" is used?
    $blacklisted_words = array('img', 'url', 'quote', 'www', 'http', 'the', 'is', 'it', 'are', 'if');
    // What are we searching for?
    if (empty($search_params['search'])) {
        if (isset($_GET['search'])) {
            $search_params['search'] = un_htmlspecialchars($_GET['search']);
        } elseif (isset($_POST['search'])) {
            $search_params['search'] = $_POST['search'];
        } else {
            $search_params['search'] = '';
        }
    }
    // Nothing??
    if (!isset($search_params['search']) || $search_params['search'] == '') {
        $context['search_errors']['invalid_search_string'] = true;
    } elseif ($smcFunc['strlen']($search_params['search']) > $context['search_string_limit']) {
        $context['search_errors']['string_too_long'] = true;
        $txt['error_string_too_long'] = sprintf($txt['error_string_too_long'], $context['search_string_limit']);
    }
    // Change non-word characters into spaces.
    $stripped_query = preg_replace('~(?:[\\x0B\\0' . ($context['utf8'] ? $context['server']['complex_preg_chars'] ? '\\x{A0}' : " " : '\\xA0') . '\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']);
    // Make the query lower case. It's gonna be case insensitive anyway.
    $stripped_query = un_htmlspecialchars($smcFunc['strtolower']($stripped_query));
    // This (hidden) setting will do fulltext searching in the most basic way.
    if (!empty($modSettings['search_simple_fulltext'])) {
        $stripped_query = strtr($stripped_query, array('"' => ''));
    }
    $no_regexp = preg_match('~&#(?:\\d{1,7}|x[0-9a-fA-F]{1,6});~', $stripped_query) === 1;
    // Extract phrase parts first (e.g. some words "this is a phrase" some more words.)
    preg_match_all('/(?:^|\\s)([-]?)"([^"]+)"(?:$|\\s)/', $stripped_query, $matches, PREG_PATTERN_ORDER);
    $phraseArray = $matches[2];
    // Remove the phrase parts and extract the words.
    $wordArray = explode(' ', preg_replace('~(?:^|\\s)(?:[-]?)"(?:[^"]+)"(?:$|\\s)~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']));
    // A minus sign in front of a word excludes the word.... so...
    $excludedWords = array();
    $excludedIndexWords = array();
    $excludedSubjectWords = array();
    $excludedPhrases = array();
    // .. first, we check for things like -"some words", but not "-some words".
    foreach ($matches[1] as $index => $word) {
        if ($word === '-') {
            if (($word = trim($phraseArray[$index], '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = $word;
            }
            unset($phraseArray[$index]);
        }
    }
    // Now we look for -test, etc.... normaller.
    foreach ($wordArray as $index => $word) {
        if (strpos(trim($word), '-') === 0) {
            if (($word = trim($word, '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = $word;
            }
            unset($wordArray[$index]);
        }
    }
    // The remaining words and phrases are all included.
    $searchArray = array_merge($phraseArray, $wordArray);
    // Trim everything and make sure there are no words that are the same.
    foreach ($searchArray as $index => $value) {
        // Skip anything practically empty.
        if (($searchArray[$index] = trim($value, '-_\' ')) === '') {
            unset($searchArray[$index]);
        } elseif (in_array($searchArray[$index], $blacklisted_words)) {
            $foundBlackListedWords = true;
            unset($searchArray[$index]);
        } elseif ($smcFunc['strlen']($value) < 2) {
            $context['search_errors']['search_string_small_words'] = true;
            unset($searchArray[$index]);
        } else {
            $searchArray[$index] = $searchArray[$index];
        }
    }
    $searchArray = array_slice(array_unique($searchArray), 0, 10);
    // Create an array of replacements for highlighting.
    $context['mark'] = array();
    foreach ($searchArray as $word) {
        $context['mark'][$word] = '<strong class="highlight">' . $word . '</strong>';
    }
    // Initialize two arrays storing the words that have to be searched for.
    $orParts = array();
    $searchWords = array();
    // Make sure at least one word is being searched for.
    if (empty($searchArray)) {
        $context['search_errors']['invalid_search_string' . (!empty($foundBlackListedWords) ? '_blacklist' : '')] = true;
    } elseif (empty($search_params['searchtype'])) {
        $orParts[0] = $searchArray;
    } else {
        foreach ($searchArray as $index => $value) {
            $orParts[$index] = array($value);
        }
    }
    // Don't allow duplicate error messages if one string is too short.
    if (isset($context['search_errors']['search_string_small_words'], $context['search_errors']['invalid_search_string'])) {
        unset($context['search_errors']['invalid_search_string']);
    }
    // Make sure the excluded words are in all or-branches.
    foreach ($orParts as $orIndex => $andParts) {
        foreach ($excludedWords as $word) {
            $orParts[$orIndex][] = $word;
        }
    }
    // Determine the or-branches and the fulltext search words.
    foreach ($orParts as $orIndex => $andParts) {
        $searchWords[$orIndex] = array('indexed_words' => array(), 'words' => array(), 'subject_words' => array(), 'all_words' => array());
        // Sort the indexed words (large words -> small words -> excluded words).
        if ($searchAPI->supportsMethod('searchSort')) {
            usort($orParts[$orIndex], 'searchSort');
        }
        foreach ($orParts[$orIndex] as $word) {
            $is_excluded = in_array($word, $excludedWords);
            $searchWords[$orIndex]['all_words'][] = $word;
            $subjectWords = text2words($word);
            if (!$is_excluded || count($subjectWords) === 1) {
                $searchWords[$orIndex]['subject_words'] = array_merge($searchWords[$orIndex]['subject_words'], $subjectWords);
                if ($is_excluded) {
                    $excludedSubjectWords = array_merge($excludedSubjectWords, $subjectWords);
                }
            } else {
                $excludedPhrases[] = $word;
            }
            // Have we got indexes to prepare?
            if ($searchAPI->supportsMethod('prepareIndexes')) {
                $searchAPI->prepareIndexes($word, $searchWords[$orIndex], $excludedIndexWords, $is_excluded);
            }
        }
        // Search_force_index requires all AND parts to have at least one fulltext word.
        if (!empty($modSettings['search_force_index']) && empty($searchWords[$orIndex]['indexed_words'])) {
            $context['search_errors']['query_not_specific_enough'] = true;
            break;
        } elseif ($search_params['subject_only'] && empty($searchWords[$orIndex]['subject_words']) && empty($excludedSubjectWords)) {
            $context['search_errors']['query_not_specific_enough'] = true;
            break;
        } else {
            $searchWords[$orIndex]['indexed_words'] = array_slice($searchWords[$orIndex]['indexed_words'], 0, 7);
            $searchWords[$orIndex]['subject_words'] = array_slice($searchWords[$orIndex]['subject_words'], 0, 7);
        }
    }
    // *** Spell checking
    $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new');
    if ($context['show_spellchecking']) {
        // Windows fix.
        ob_start();
        $old = error_reporting(0);
        pspell_new('en');
        $pspell_link = pspell_new($txt['lang_dictionary'], $txt['lang_spelling'], '', strtr($txt['lang_character_set'], array('iso-' => 'iso', 'ISO-' => 'iso')), PSPELL_FAST | PSPELL_RUN_TOGETHER);
        if (!$pspell_link) {
            $pspell_link = pspell_new('en', '', '', '', PSPELL_FAST | PSPELL_RUN_TOGETHER);
        }
        error_reporting($old);
        ob_end_clean();
        $did_you_mean = array('search' => array(), 'display' => array());
        $found_misspelling = false;
        foreach ($searchArray as $word) {
            if (empty($pspell_link)) {
                continue;
            }
            $word = $word;
            // Don't check phrases.
            if (preg_match('~^\\w+$~', $word) === 0) {
                $did_you_mean['search'][] = '"' . $word . '"';
                $did_you_mean['display'][] = '&quot;' . $smcFunc['htmlspecialchars']($word) . '&quot;';
                continue;
            } elseif (preg_match('~\\d~', $word) === 1) {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word);
                continue;
            } elseif (pspell_check($pspell_link, $word)) {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word);
                continue;
            }
            $suggestions = pspell_suggest($pspell_link, $word);
            foreach ($suggestions as $i => $s) {
                // Search is case insensitive.
                if ($smcFunc['strtolower']($s) == $smcFunc['strtolower']($word)) {
                    unset($suggestions[$i]);
                } elseif ($suggestions[$i] != censorText($s)) {
                    unset($suggestions[$i]);
                }
            }
            // Anything found?  If so, correct it!
            if (!empty($suggestions)) {
                $suggestions = array_values($suggestions);
                $did_you_mean['search'][] = $suggestions[0];
                $did_you_mean['display'][] = '<em><strong>' . $smcFunc['htmlspecialchars']($suggestions[0]) . '</strong></em>';
                $found_misspelling = true;
            } else {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $smcFunc['htmlspecialchars']($word);
            }
        }
        if ($found_misspelling) {
            // Don't spell check excluded words, but add them still...
            $temp_excluded = array('search' => array(), 'display' => array());
            foreach ($excludedWords as $word) {
                $word = $word;
                if (preg_match('~^\\w+$~', $word) == 0) {
                    $temp_excluded['search'][] = '-"' . $word . '"';
                    $temp_excluded['display'][] = '-&quot;' . $smcFunc['htmlspecialchars']($word) . '&quot;';
                } else {
                    $temp_excluded['search'][] = '-' . $word;
                    $temp_excluded['display'][] = '-' . $smcFunc['htmlspecialchars']($word);
                }
            }
            $did_you_mean['search'] = array_merge($did_you_mean['search'], $temp_excluded['search']);
            $did_you_mean['display'] = array_merge($did_you_mean['display'], $temp_excluded['display']);
            $temp_params = $search_params;
            $temp_params['search'] = implode(' ', $did_you_mean['search']);
            if (isset($temp_params['brd'])) {
                $temp_params['brd'] = implode(',', $temp_params['brd']);
            }
            $context['params'] = array();
            foreach ($temp_params as $k => $v) {
                $context['did_you_mean_params'][] = $k . '|\'|' . $v;
            }
            $context['did_you_mean_params'] = base64_encode(implode('|"|', $context['did_you_mean_params']));
            $context['did_you_mean'] = implode(' ', $did_you_mean['display']);
        }
    }
    // Let the user adjust the search query, should they wish?
    $context['search_params'] = $search_params;
    if (isset($context['search_params']['search'])) {
        $context['search_params']['search'] = $smcFunc['htmlspecialchars']($context['search_params']['search']);
    }
    if (isset($context['search_params']['userspec'])) {
        $context['search_params']['userspec'] = $smcFunc['htmlspecialchars']($context['search_params']['userspec']);
    }
    // Do we have captcha enabled?
    if ($user_info['is_guest'] && !empty($modSettings['search_enable_captcha']) && empty($_SESSION['ss_vv_passed']) && (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search'])) {
        // If we come from another search box tone down the error...
        if (!isset($_REQUEST['search_vv'])) {
            $context['search_errors']['need_verification_code'] = true;
        } else {
            require_once $sourcedir . '/Subs-Editor.php';
            $verificationOptions = array('id' => 'search');
            $context['require_verification'] = create_control_verification($verificationOptions, true);
            if (is_array($context['require_verification'])) {
                foreach ($context['require_verification'] as $error) {
                    $context['search_errors'][$error] = true;
                }
            } else {
                $_SESSION['ss_vv_passed'] = true;
            }
        }
    }
    // *** Encode all search params
    // All search params have been checked, let's compile them to a single string... made less simple by PHP 4.3.9 and below.
    $temp_params = $search_params;
    if (isset($temp_params['brd'])) {
        $temp_params['brd'] = implode(',', $temp_params['brd']);
    }
    $context['params'] = array();
    foreach ($temp_params as $k => $v) {
        $context['params'][] = $k . '|\'|' . $v;
    }
    if (!empty($context['params'])) {
        // Due to old IE's 2083 character limit, we have to compress long search strings
        $params = @gzcompress(implode('|"|', $context['params']));
        // Gzcompress failed, use try non-gz
        if (empty($params)) {
            $params = implode('|"|', $context['params']);
        }
        // Base64 encode, then replace +/= with uri safe ones that can be reverted
        $context['params'] = str_replace(array('+', '/', '='), array('-', '_', '.'), base64_encode($params));
    }
    // ... and add the links to the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?action=search;params=' . $context['params'], 'name' => $txt['search']);
    $context['linktree'][] = array('url' => $scripturl . '?action=search2;params=' . $context['params'], 'name' => $txt['search_results']);
    // *** A last error check
    // One or more search errors? Go back to the first search screen.
    if (!empty($context['search_errors'])) {
        $_REQUEST['params'] = $context['params'];
        return PlushSearch1();
    }
    // Spam me not, Spam-a-lot?
    if (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search']) {
        spamProtection('search');
    }
    // Store the last search string to allow pages of results to be browsed.
    $_SESSION['last_ss'] = $search_params['search'];
    // *** Reserve an ID for caching the search results.
    $query_params = array_merge($search_params, array('min_msg_id' => isset($minMsgID) ? (int) $minMsgID : 0, 'max_msg_id' => isset($maxMsgID) ? (int) $maxMsgID : 0, 'memberlist' => !empty($memberlist) ? $memberlist : array()));
    // Can this search rely on the API given the parameters?
    if ($searchAPI->supportsMethod('searchQuery', $query_params)) {
        $participants = array();
        $searchArray = array();
        $num_results = $searchAPI->searchQuery($query_params, $searchWords, $excludedIndexWords, $participants, $searchArray);
    } else {
        $update_cache = empty($_SESSION['search_cache']) || $_SESSION['search_cache']['params'] != $context['params'];
        if ($update_cache) {
            // Increase the pointer...
            $modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer'];
            // ...and store it right off.
            updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1));
            // As long as you don't change the parameters, the cache result is yours.
            $_SESSION['search_cache'] = array('id_search' => $modSettings['search_pointer'], 'num_results' => -1, 'params' => $context['params']);
            // Clear the previous cache of the final results cache.
            $smcFunc['db_search_query']('delete_log_search_results', '
				DELETE FROM {db_prefix}log_search_results
				WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search']));
            if ($search_params['subject_only']) {
                // We do this to try and avoid duplicate keys on databases not supporting INSERT IGNORE.
                $inserts = array();
                foreach ($searchWords as $orIndex => $words) {
                    $subject_query_params = array();
                    $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array());
                    if ($modSettings['postmod_active']) {
                        $subject_query['where'][] = 't.approved = {int:is_approved}';
                    }
                    $numTables = 0;
                    $prev_join = 0;
                    $numSubjectResults = 0;
                    foreach ($words['subject_words'] as $subjectWord) {
                        $numTables++;
                        if (in_array($subjectWord, $excludedSubjectWords)) {
                            $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)';
                            $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)';
                        } else {
                            $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)';
                            $subject_query['where'][] = 'subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}');
                            $prev_join = $numTables;
                        }
                        $subject_query_params['subject_words_' . $numTables] = $subjectWord;
                        $subject_query_params['subject_words_' . $numTables . '_wild'] = '%' . $subjectWord . '%';
                    }
                    if (!empty($userQuery)) {
                        if ($subject_query['from'] != '{db_prefix}messages AS m') {
                            $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_topic = t.id_topic)';
                        }
                        $subject_query['where'][] = $userQuery;
                    }
                    if (!empty($search_params['topic'])) {
                        $subject_query['where'][] = 't.id_topic = ' . $search_params['topic'];
                    }
                    if (!empty($minMsgID)) {
                        $subject_query['where'][] = 't.id_first_msg >= ' . $minMsgID;
                    }
                    if (!empty($maxMsgID)) {
                        $subject_query['where'][] = 't.id_last_msg <= ' . $maxMsgID;
                    }
                    if (!empty($boardQuery)) {
                        $subject_query['where'][] = 't.id_board ' . $boardQuery;
                    }
                    if (!empty($excludedPhrases)) {
                        if ($subject_query['from'] != '{db_prefix}messages AS m') {
                            $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                        }
                        $count = 0;
                        foreach ($excludedPhrases as $phrase) {
                            $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:excluded_phrases_' . $count . '}';
                            $subject_query_params['excluded_phrases_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]';
                        }
                    }
                    $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_subject', ($smcFunc['db_support_ignore'] ? '
						INSERT IGNORE INTO {db_prefix}log_search_results
							(id_search, id_topic, relevance, id_msg, num_matches)' : '') . '
						SELECT
							{int:id_search},
							t.id_topic,
							1000 * (
								{int:weight_frequency} / (t.num_replies + 1) +
								{int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END +
								{int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END +
								{int:weight_subject} +
								{int:weight_sticky} * t.is_sticky
							) / {int:weight_total} AS relevance,
							' . (empty($userQuery) ? 't.id_first_msg' : 'm.id_msg') . ',
							1
						FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : '
							INNER JOIN ' . implode('
							INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : '
							LEFT JOIN ' . implode('
							LEFT JOIN ', $subject_query['left_join'])) . '
						WHERE ' . implode('
							AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), array_merge($subject_query_params, array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['length'], 'weight_sticky' => $weight['sticky'], 'weight_subject' => $weight['subject'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1)));
                    // If the database doesn't support IGNORE to make this fast we need to do some tracking.
                    if (!$smcFunc['db_support_ignore']) {
                        while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                            // No duplicates!
                            if (isset($inserts[$row[1]])) {
                                continue;
                            }
                            foreach ($row as $key => $value) {
                                $inserts[$row[1]][] = (int) $row[$key];
                            }
                        }
                        $smcFunc['db_free_result']($ignoreRequest);
                        $numSubjectResults = count($inserts);
                    } else {
                        $numSubjectResults += $smcFunc['db_affected_rows']();
                    }
                    if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                        break;
                    }
                }
                // If there's data to be inserted for non-IGNORE databases do it here!
                if (!empty($inserts)) {
                    $smcFunc['db_insert']('', '{db_prefix}log_search_results', array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'int', 'id_msg' => 'int', 'num_matches' => 'int'), $inserts, array('id_search', 'id_topic'));
                }
                $_SESSION['search_cache']['num_results'] = $numSubjectResults;
            } else {
                $main_query = array('select' => array('id_search' => $_SESSION['search_cache']['id_search'], 'relevance' => '0'), 'weights' => array(), 'from' => '{db_prefix}topics AS t', 'inner_join' => array('{db_prefix}messages AS m ON (m.id_topic = t.id_topic)'), 'left_join' => array(), 'where' => array(), 'group_by' => array(), 'parameters' => array('min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1));
                if (empty($search_params['topic']) && empty($search_params['show_complete'])) {
                    $main_query['select']['id_topic'] = 't.id_topic';
                    $main_query['select']['id_msg'] = 'MAX(m.id_msg) AS id_msg';
                    $main_query['select']['num_matches'] = 'COUNT(*) AS num_matches';
                    $main_query['weights'] = array('frequency' => 'COUNT(*) / (MAX(t.num_replies) + 1)', 'age' => 'CASE WHEN MAX(m.id_msg) < {int:min_msg} THEN 0 ELSE (MAX(m.id_msg) - {int:min_msg}) / {int:recent_message} END', 'length' => 'CASE WHEN MAX(t.num_replies) < {int:huge_topic_posts} THEN MAX(t.num_replies) / {int:huge_topic_posts} ELSE 1 END', 'subject' => '0', 'first_message' => 'CASE WHEN MIN(m.id_msg) = MAX(t.id_first_msg) THEN 1 ELSE 0 END', 'sticky' => 'MAX(t.is_sticky)');
                    $main_query['group_by'][] = 't.id_topic';
                } else {
                    // This is outrageous!
                    $main_query['select']['id_topic'] = 'm.id_msg AS id_topic';
                    $main_query['select']['id_msg'] = 'm.id_msg';
                    $main_query['select']['num_matches'] = '1 AS num_matches';
                    $main_query['weights'] = array('age' => '((m.id_msg - t.id_first_msg) / CASE WHEN t.id_last_msg = t.id_first_msg THEN 1 ELSE t.id_last_msg - t.id_first_msg END)', 'first_message' => 'CASE WHEN m.id_msg = t.id_first_msg THEN 1 ELSE 0 END');
                    if (!empty($search_params['topic'])) {
                        $main_query['where'][] = 't.id_topic = {int:topic}';
                        $main_query['parameters']['topic'] = $search_params['topic'];
                    }
                    if (!empty($search_params['show_complete'])) {
                        $main_query['group_by'][] = 'm.id_msg, t.id_first_msg, t.id_last_msg';
                    }
                }
                // *** Get the subject results.
                $numSubjectResults = 0;
                if (empty($search_params['topic'])) {
                    $inserts = array();
                    // Create a temporary table to store some preliminary results in.
                    $smcFunc['db_search_query']('drop_tmp_log_search_topics', '
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_topics', array('db_error_skip' => true));
                    $createTemporary = $smcFunc['db_search_query']('create_tmp_log_search_topics', '
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_topics (
							id_topic mediumint(8) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_topic)
						) ENGINE=MEMORY', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clean up some previous cache.
                    if (!$createTemporary) {
                        $smcFunc['db_search_query']('delete_log_search_topics', '
							DELETE FROM {db_prefix}log_search_topics
							WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search']));
                    }
                    foreach ($searchWords as $orIndex => $words) {
                        $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array(), 'params' => array());
                        $numTables = 0;
                        $prev_join = 0;
                        $count = 0;
                        foreach ($words['subject_words'] as $subjectWord) {
                            $numTables++;
                            if (in_array($subjectWord, $excludedSubjectWords)) {
                                if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                    $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                                }
                                $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_not_' . $count . '}' : '= {string:subject_not_' . $count . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)';
                                $subject_query['params']['subject_not_' . $count] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord;
                                $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)';
                                $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:body_not_' . $count . '}';
                                $subject_query['params']['body_not_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($subjectWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $subjectWord), '\\\'') . '[[:>:]]';
                            } else {
                                $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)';
                                $subject_query['where'][] = 'subj' . $numTables . '.word LIKE {string:subject_like_' . $count . '}';
                                $subject_query['params']['subject_like_' . $count++] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord;
                                $prev_join = $numTables;
                            }
                        }
                        if (!empty($userQuery)) {
                            if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                            }
                            $subject_query['where'][] = '{raw:user_query}';
                            $subject_query['params']['user_query'] = $userQuery;
                        }
                        if (!empty($search_params['topic'])) {
                            $subject_query['where'][] = 't.id_topic = {int:topic}';
                            $subject_query['params']['topic'] = $search_params['topic'];
                        }
                        if (!empty($minMsgID)) {
                            $subject_query['where'][] = 't.id_first_msg >= {int:min_msg_id}';
                            $subject_query['params']['min_msg_id'] = $minMsgID;
                        }
                        if (!empty($maxMsgID)) {
                            $subject_query['where'][] = 't.id_last_msg <= {int:max_msg_id}';
                            $subject_query['params']['max_msg_id'] = $maxMsgID;
                        }
                        if (!empty($boardQuery)) {
                            $subject_query['where'][] = 't.id_board {raw:board_query}';
                            $subject_query['params']['board_query'] = $boardQuery;
                        }
                        if (!empty($excludedPhrases)) {
                            if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                            }
                            $count = 0;
                            foreach ($excludedPhrases as $phrase) {
                                $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}';
                                $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}';
                                $subject_query['params']['exclude_phrase_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]';
                            }
                        }
                        // Nothing to search for?
                        if (empty($subject_query['where'])) {
                            continue;
                        }
                        $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_topics', ($smcFunc['db_support_ignore'] ? '
							INSERT IGNORE INTO {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics
								(' . ($createTemporary ? '' : 'id_search, ') . 'id_topic)' : '') . '
							SELECT ' . ($createTemporary ? '' : $_SESSION['search_cache']['id_search'] . ', ') . 't.id_topic
							FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : '
								INNER JOIN ' . implode('
								INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : '
								LEFT JOIN ' . implode('
								LEFT JOIN ', $subject_query['left_join'])) . '
							WHERE ' . implode('
								AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : '
							LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), $subject_query['params']);
                        // Don't do INSERT IGNORE? Manually fix this up!
                        if (!$smcFunc['db_support_ignore']) {
                            while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                                $ind = $createTemporary ? 0 : 1;
                                // No duplicates!
                                if (isset($inserts[$row[$ind]])) {
                                    continue;
                                }
                                $inserts[$row[$ind]] = $row;
                            }
                            $smcFunc['db_free_result']($ignoreRequest);
                            $numSubjectResults = count($inserts);
                        } else {
                            $numSubjectResults += $smcFunc['db_affected_rows']();
                        }
                        if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                            break;
                        }
                    }
                    // Got some non-MySQL data to plonk in?
                    if (!empty($inserts)) {
                        $smcFunc['db_insert']('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics', $createTemporary ? array('id_topic' => 'int') : array('id_search' => 'int', 'id_topic' => 'int'), $inserts, $createTemporary ? array('id_topic') : array('id_search', 'id_topic'));
                    }
                    if ($numSubjectResults !== 0) {
                        $main_query['weights']['subject'] = 'CASE WHEN MAX(lst.id_topic) IS NULL THEN 0 ELSE 1 END';
                        $main_query['left_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (' . ($createTemporary ? '' : 'lst.id_search = {int:id_search} AND ') . 'lst.id_topic = t.id_topic)';
                        if (!$createTemporary) {
                            $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search'];
                        }
                    }
                }
                $indexedResults = 0;
                // We building an index?
                if ($searchAPI->supportsMethod('indexedWordQuery', $query_params)) {
                    $inserts = array();
                    $smcFunc['db_search_query']('drop_tmp_log_search_messages', '
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_messages', array('db_error_skip' => true));
                    $createTemporary = $smcFunc['db_search_query']('create_tmp_log_search_messages', '
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_messages (
							id_msg int(10) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_msg)
						) ENGINE=MEMORY', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clear, all clear!
                    if (!$createTemporary) {
                        $smcFunc['db_search_query']('delete_log_search_messages', '
							DELETE FROM {db_prefix}log_search_messages
							WHERE id_search = {int:id_search}', array('id_search' => $_SESSION['search_cache']['id_search']));
                    }
                    foreach ($searchWords as $orIndex => $words) {
                        // Search for this word, assuming we have some words!
                        if (!empty($words['indexed_words'])) {
                            // Variables required for the search.
                            $search_data = array('insert_into' => ($createTemporary ? 'tmp_' : '') . 'log_search_messages', 'no_regexp' => $no_regexp, 'max_results' => $maxMessageResults, 'indexed_results' => $indexedResults, 'params' => array('id_search' => !$createTemporary ? $_SESSION['search_cache']['id_search'] : 0, 'excluded_words' => $excludedWords, 'user_query' => !empty($userQuery) ? $userQuery : '', 'board_query' => !empty($boardQuery) ? $boardQuery : '', 'topic' => !empty($search_params['topic']) ? $search_params['topic'] : 0, 'min_msg_id' => !empty($minMsgID) ? $minMsgID : 0, 'max_msg_id' => !empty($maxMsgID) ? $maxMsgID : 0, 'excluded_phrases' => !empty($excludedPhrases) ? $excludedPhrases : array(), 'excluded_index_words' => !empty($excludedIndexWords) ? $excludedIndexWords : array(), 'excluded_subject_words' => !empty($excludedSubjectWords) ? $excludedSubjectWords : array()));
                            $ignoreRequest = $searchAPI->indexedWordQuery($words, $search_data);
                            if (!$smcFunc['db_support_ignore']) {
                                while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                                    // No duplicates!
                                    if (isset($inserts[$row[0]])) {
                                        continue;
                                    }
                                    $inserts[$row[0]] = $row;
                                }
                                $smcFunc['db_free_result']($ignoreRequest);
                                $indexedResults = count($inserts);
                            } else {
                                $indexedResults += $smcFunc['db_affected_rows']();
                            }
                            if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) {
                                break;
                            }
                        }
                    }
                    // More non-MySQL stuff needed?
                    if (!empty($inserts)) {
                        $smcFunc['db_insert']('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages', $createTemporary ? array('id_msg' => 'int') : array('id_msg' => 'int', 'id_search' => 'int'), $inserts, $createTemporary ? array('id_msg') : array('id_msg', 'id_search'));
                    }
                    if (empty($indexedResults) && empty($numSubjectResults) && !empty($modSettings['search_force_index'])) {
                        $context['search_errors']['query_not_specific_enough'] = true;
                        $_REQUEST['params'] = $context['params'];
                        return PlushSearch1();
                    } elseif (!empty($indexedResults)) {
                        $main_query['inner_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages AS lsm ON (lsm.id_msg = m.id_msg)';
                        if (!$createTemporary) {
                            $main_query['where'][] = 'lsm.id_search = {int:id_search}';
                            $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search'];
                        }
                    }
                } else {
                    $orWhere = array();
                    $count = 0;
                    foreach ($searchWords as $orIndex => $words) {
                        $where = array();
                        foreach ($words['all_words'] as $regularWord) {
                            $where[] = 'm.body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}';
                            if (in_array($regularWord, $excludedWords)) {
                                $where[] = 'm.subject NOT' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}';
                            }
                            $main_query['parameters']['all_word_body_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . '[[:>:]]';
                        }
                        if (!empty($where)) {
                            $orWhere[] = count($where) > 1 ? '(' . implode(' AND ', $where) . ')' : $where[0];
                        }
                    }
                    if (!empty($orWhere)) {
                        $main_query['where'][] = count($orWhere) > 1 ? '(' . implode(' OR ', $orWhere) . ')' : $orWhere[0];
                    }
                    if (!empty($userQuery)) {
                        $main_query['where'][] = '{raw:user_query}';
                        $main_query['parameters']['user_query'] = $userQuery;
                    }
                    if (!empty($search_params['topic'])) {
                        $main_query['where'][] = 'm.id_topic = {int:topic}';
                        $main_query['parameters']['topic'] = $search_params['topic'];
                    }
                    if (!empty($minMsgID)) {
                        $main_query['where'][] = 'm.id_msg >= {int:min_msg_id}';
                        $main_query['parameters']['min_msg_id'] = $minMsgID;
                    }
                    if (!empty($maxMsgID)) {
                        $main_query['where'][] = 'm.id_msg <= {int:max_msg_id}';
                        $main_query['parameters']['max_msg_id'] = $maxMsgID;
                    }
                    if (!empty($boardQuery)) {
                        $main_query['where'][] = 'm.id_board {raw:board_query}';
                        $main_query['parameters']['board_query'] = $boardQuery;
                    }
                }
                // Did we either get some indexed results, or otherwise did not do an indexed query?
                if (!empty($indexedResults) || !$searchAPI->supportsMethod('indexedWordQuery', $query_params)) {
                    $relevance = '1000 * (';
                    $new_weight_total = 0;
                    foreach ($main_query['weights'] as $type => $value) {
                        $relevance .= $weight[$type] . ' * ' . $value . ' + ';
                        $new_weight_total += $weight[$type];
                    }
                    $main_query['select']['relevance'] = substr($relevance, 0, -3) . ') / ' . $new_weight_total . ' AS relevance';
                    $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_no_index', ($smcFunc['db_support_ignore'] ? '
						INSERT IGNORE INTO ' . '{db_prefix}log_search_results
							(' . implode(', ', array_keys($main_query['select'])) . ')' : '') . '
						SELECT
							' . implode(',
							', $main_query['select']) . '
						FROM ' . $main_query['from'] . (empty($main_query['inner_join']) ? '' : '
							INNER JOIN ' . implode('
							INNER JOIN ', $main_query['inner_join'])) . (empty($main_query['left_join']) ? '' : '
							LEFT JOIN ' . implode('
							LEFT JOIN ', $main_query['left_join'])) . (!empty($main_query['where']) ? '
						WHERE ' : '') . implode('
							AND ', $main_query['where']) . (empty($main_query['group_by']) ? '' : '
						GROUP BY ' . implode(', ', $main_query['group_by'])) . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . $modSettings['search_max_results']), $main_query['parameters']);
                    // We love to handle non-good databases that don't support our ignore!
                    if (!$smcFunc['db_support_ignore']) {
                        $inserts = array();
                        while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                            // No duplicates!
                            if (isset($inserts[$row[2]])) {
                                continue;
                            }
                            foreach ($row as $key => $value) {
                                $inserts[$row[2]][] = (int) $row[$key];
                            }
                        }
                        $smcFunc['db_free_result']($ignoreRequest);
                        // Now put them in!
                        if (!empty($inserts)) {
                            $query_columns = array();
                            foreach ($main_query['select'] as $k => $v) {
                                $query_columns[$k] = 'int';
                            }
                            $smcFunc['db_insert']('', '{db_prefix}log_search_results', $query_columns, $inserts, array('id_search', 'id_topic'));
                        }
                        $_SESSION['search_cache']['num_results'] += count($inserts);
                    } else {
                        $_SESSION['search_cache']['num_results'] = $smcFunc['db_affected_rows']();
                    }
                }
                // Insert subject-only matches.
                if ($_SESSION['search_cache']['num_results'] < $modSettings['search_max_results'] && $numSubjectResults !== 0) {
                    $usedIDs = array_flip(empty($inserts) ? array() : array_keys($inserts));
                    $ignoreRequest = $smcFunc['db_search_query']('insert_log_search_results_sub_only', ($smcFunc['db_support_ignore'] ? '
						INSERT IGNORE INTO {db_prefix}log_search_results
							(id_search, id_topic, relevance, id_msg, num_matches)' : '') . '
						SELECT
							{int:id_search},
							t.id_topic,
							1000 * (
								{int:weight_frequency} / (t.num_replies + 1) +
								{int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END +
								{int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END +
								{int:weight_subject} +
								{int:weight_sticky} * t.is_sticky
							) / {int:weight_total} AS relevance,
							t.id_first_msg,
							1
						FROM {db_prefix}topics AS t
							INNER JOIN {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (lst.id_topic = t.id_topic)' . ($createTemporary ? '' : 'WHERE lst.id_search = {int:id_search}') . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . ($modSettings['search_max_results'] - $_SESSION['search_cache']['num_results'])), array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['frequency'], 'weight_sticky' => $weight['frequency'], 'weight_subject' => $weight['frequency'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts));
                    // Once again need to do the inserts if the database don't support ignore!
                    if (!$smcFunc['db_support_ignore']) {
                        $inserts = array();
                        while ($row = $smcFunc['db_fetch_row']($ignoreRequest)) {
                            // No duplicates!
                            if (isset($usedIDs[$row[1]])) {
                                continue;
                            }
                            $usedIDs[$row[1]] = true;
                            $inserts[] = $row;
                        }
                        $smcFunc['db_free_result']($ignoreRequest);
                        // Now put them in!
                        if (!empty($inserts)) {
                            $smcFunc['db_insert']('', '{db_prefix}log_search_results', array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'float', 'id_msg' => 'int', 'num_matches' => 'int'), $inserts, array('id_search', 'id_topic'));
                        }
                        $_SESSION['search_cache']['num_results'] += count($inserts);
                    } else {
                        $_SESSION['search_cache']['num_results'] += $smcFunc['db_affected_rows']();
                    }
                } else {
                    $_SESSION['search_cache']['num_results'] = 0;
                }
            }
        }
        // *** Retrieve the results to be shown on the page
        $participants = array();
        $request = $smcFunc['db_search_query']('', '
			SELECT ' . (empty($search_params['topic']) ? 'lsr.id_topic' : $search_params['topic'] . ' AS id_topic') . ', lsr.id_msg, lsr.relevance, lsr.num_matches
			FROM {db_prefix}log_search_results AS lsr' . ($search_params['sort'] == 'num_replies' ? '
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = lsr.id_topic)' : '') . '
			WHERE lsr.id_search = {int:id_search}
			ORDER BY ' . $search_params['sort'] . ' ' . $search_params['sort_dir'] . '
			LIMIT ' . (int) $_REQUEST['start'] . ', ' . $modSettings['search_results_per_page'], array('id_search' => $_SESSION['search_cache']['id_search']));
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $context['topics'][$row['id_msg']] = array('relevance' => round($row['relevance'] / 10, 1) . '%', 'num_matches' => $row['num_matches'], 'matches' => array());
            // By default they didn't participate in the topic!
            $participants[$row['id_topic']] = false;
        }
        $smcFunc['db_free_result']($request);
        $num_results = $_SESSION['search_cache']['num_results'];
    }
    if (!empty($context['topics'])) {
        // Create an array for the permissions.
        $boards_can = array('post_reply_own' => boardsAllowedTo('post_reply_own'), 'post_reply_any' => boardsAllowedTo('post_reply_any'), 'mark_any_notify' => boardsAllowedTo('mark_any_notify'));
        // How's about some quick moderation?
        if (!empty($options['display_quick_mod'])) {
            $boards_can['lock_any'] = boardsAllowedTo('lock_any');
            $boards_can['lock_own'] = boardsAllowedTo('lock_own');
            $boards_can['make_sticky'] = boardsAllowedTo('make_sticky');
            $boards_can['move_any'] = boardsAllowedTo('move_any');
            $boards_can['move_own'] = boardsAllowedTo('move_own');
            $boards_can['remove_any'] = boardsAllowedTo('remove_any');
            $boards_can['remove_own'] = boardsAllowedTo('remove_own');
            $boards_can['merge_any'] = boardsAllowedTo('merge_any');
            $context['can_lock'] = in_array(0, $boards_can['lock_any']);
            $context['can_sticky'] = in_array(0, $boards_can['make_sticky']) && !empty($modSettings['enableStickyTopics']);
            $context['can_move'] = in_array(0, $boards_can['move_any']);
            $context['can_remove'] = in_array(0, $boards_can['remove_any']);
            $context['can_merge'] = in_array(0, $boards_can['merge_any']);
        }
        // What messages are we using?
        $msg_list = array_keys($context['topics']);
        // Load the posters...
        $request = $smcFunc['db_query']('', '
			SELECT id_member
			FROM {db_prefix}messages
			WHERE id_member != {int:no_member}
				AND id_msg IN ({array_int:message_list})
			LIMIT ' . count($context['topics']), array('message_list' => $msg_list, 'no_member' => 0));
        $posters = array();
        while ($row = $smcFunc['db_fetch_assoc']($request)) {
            $posters[] = $row['id_member'];
        }
        $smcFunc['db_free_result']($request);
        if (!empty($posters)) {
            loadMemberData(array_unique($posters));
        }
        // Get the messages out for the callback - select enough that it can be made to look just like Display.
        $messages_request = $smcFunc['db_query']('', '
			SELECT
				m.id_msg, m.subject, m.poster_name, m.poster_email, m.poster_time, m.id_member,
				m.icon, m.poster_ip, m.body, m.smileys_enabled, m.modified_time, m.modified_name,
				first_m.id_msg AS first_msg, first_m.subject AS first_subject, first_m.icon AS first_icon, first_m.poster_time AS first_poster_time,
				first_mem.id_member AS first_member_id, IFNULL(first_mem.real_name, first_m.poster_name) AS first_member_name,
				last_m.id_msg AS last_msg, last_m.poster_time AS last_poster_time, last_mem.id_member AS last_member_id,
				IFNULL(last_mem.real_name, last_m.poster_name) AS last_member_name, last_m.icon AS last_icon, last_m.subject AS last_subject,
				t.id_topic, t.is_sticky, t.locked, t.id_poll, t.num_replies, t.num_views,
				b.id_board, b.name AS board_name, c.id_cat, c.name AS cat_name
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
				INNER JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
				INNER JOIN {db_prefix}messages AS first_m ON (first_m.id_msg = t.id_first_msg)
				INNER JOIN {db_prefix}messages AS last_m ON (last_m.id_msg = t.id_last_msg)
				LEFT JOIN {db_prefix}members AS first_mem ON (first_mem.id_member = first_m.id_member)
				LEFT JOIN {db_prefix}members AS last_mem ON (last_mem.id_member = first_m.id_member)
			WHERE m.id_msg IN ({array_int:message_list})' . ($modSettings['postmod_active'] ? '
				AND m.approved = {int:is_approved}' : '') . '
			ORDER BY FIND_IN_SET(m.id_msg, {string:message_list_in_set})
			LIMIT {int:limit}', array('message_list' => $msg_list, 'is_approved' => 1, 'message_list_in_set' => implode(',', $msg_list), 'limit' => count($context['topics'])));
        // If there are no results that means the things in the cache got deleted, so pretend we have no topics anymore.
        if ($smcFunc['db_num_rows']($messages_request) == 0) {
            $context['topics'] = array();
        }
        // If we want to know who participated in what then load this now.
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest']) {
            $result = $smcFunc['db_query']('', '
				SELECT id_topic
				FROM {db_prefix}messages
				WHERE id_topic IN ({array_int:topic_list})
					AND id_member = {int:current_member}
				GROUP BY id_topic
				LIMIT ' . count($participants), array('current_member' => $user_info['id'], 'topic_list' => array_keys($participants)));
            while ($row = $smcFunc['db_fetch_assoc']($result)) {
                $participants[$row['id_topic']] = true;
            }
            $smcFunc['db_free_result']($result);
        }
    }
    // Now that we know how many results to expect we can start calculating the page numbers.
    $context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $num_results, $modSettings['search_results_per_page'], false);
    // Consider the search complete!
    if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
        cache_put_data('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $user_info['id']), null, 90);
    }
    $context['key_words'] =& $searchArray;
    // Setup the default topic icons... for checking they exist and the like!
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless', 'clip');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    $context['sub_template'] = 'results';
    $context['page_title'] = $txt['search_results'];
    $context['get_topics'] = 'prepareSearchContext';
    $context['can_send_pm'] = allowedTo('pm_send');
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => addslashes(un_htmlspecialchars($txt['select_destination'])));
}
コード例 #12
0
ファイル: Messages.subs.php プロジェクト: Ralkage/Elkarte
/**
 * This function updates the log_search_subjects in the event of a topic being
 * moved, removed or split. It is being sent the topic id, and optionally
 * the new subject.
 * Used by updateStats('subject').
 *
 * @param int $id_topic
 * @param string|null $subject
 */
function updateSubjectStats($id_topic, $subject = null)
{
    $db = database();
    // Remove the previous subject (if any).
    $db->query('', '
		DELETE FROM {db_prefix}log_search_subjects
		WHERE id_topic = {int:id_topic}', array('id_topic' => (int) $id_topic));
    // Insert the new subject.
    if ($subject !== null) {
        $id_topic = (int) $id_topic;
        $subject_words = text2words($subject);
        $inserts = array();
        foreach ($subject_words as $word) {
            $inserts[] = array($word, $id_topic);
        }
        if (!empty($inserts)) {
            $db->insert('ignore', '{db_prefix}log_search_subjects', array('word' => 'string', 'id_topic' => 'int'), $inserts, array('word', 'id_topic'));
        }
    }
}
コード例 #13
0
ファイル: RemoveTopic.php プロジェクト: alencarmo/OCF
function removeMessage($message, $decreasePostCount = true)
{
    global $db_prefix, $board, $sourcedir, $modSettings, $ID_MEMBER, $user_info;
    if (empty($message) || !is_numeric($message)) {
        return false;
    }
    $request = db_query("\n\t\tSELECT\n\t\t\tm.ID_MEMBER, m.icon, m.posterTime, m.subject," . (empty($modSettings['search_custom_index_config']) ? '' : ' m.body,') . "\n\t\t\tt.ID_TOPIC, t.ID_FIRST_MSG, t.ID_LAST_MSG, t.numReplies, t.ID_BOARD,\n\t\t\tt.ID_MEMBER_STARTED AS ID_MEMBER_POSTER,\n\t\t\tb.countPosts\n\t\tFROM ({$db_prefix}messages AS m, {$db_prefix}topics AS t, {$db_prefix}boards AS b)\n\t\tWHERE m.ID_MSG = {$message}\n\t\t\tAND t.ID_TOPIC = m.ID_TOPIC\n\t\t\tAND b.ID_BOARD = t.ID_BOARD\n\t\tLIMIT 1", __FILE__, __LINE__);
    if (mysql_num_rows($request) == 0) {
        return false;
    }
    $row = mysql_fetch_assoc($request);
    mysql_free_result($request);
    if (empty($board) || $row['ID_BOARD'] != $board) {
        $delete_any = boardsAllowedTo('delete_any');
        if (!in_array(0, $delete_any) && !in_array($row['ID_BOARD'], $delete_any)) {
            $delete_own = boardsAllowedTo('delete_own');
            $delete_own = in_array(0, $delete_own) || in_array($row['ID_BOARD'], $delete_own);
            $delete_replies = boardsAllowedTo('delete_replies');
            $delete_replies = in_array(0, $delete_replies) || in_array($row['ID_BOARD'], $delete_replies);
            if ($row['ID_MEMBER'] == $ID_MEMBER) {
                if (!$delete_own) {
                    if ($row['ID_MEMBER_POSTER'] == $ID_MEMBER) {
                        if (!$delete_replies) {
                            fatal_lang_error('cannot_delete_replies');
                        }
                    } else {
                        fatal_lang_error('cannot_delete_own');
                    }
                } elseif (($row['ID_MEMBER_POSTER'] != $ID_MEMBER || !$delete_replies) && !empty($modSettings['edit_disable_time']) && $row['posterTime'] + $modSettings['edit_disable_time'] * 60 < time()) {
                    fatal_lang_error('modify_post_time_passed', false);
                }
            } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER) {
                if (!$delete_replies) {
                    fatal_lang_error('cannot_delete_replies');
                }
            } else {
                fatal_lang_error('cannot_delete_any');
            }
        }
    } else {
        // Check permissions to delete this message.
        if ($row['ID_MEMBER'] == $ID_MEMBER) {
            if (!allowedTo('delete_own')) {
                if ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('delete_any')) {
                    isAllowedTo('delete_replies');
                } elseif (!allowedTo('delete_any')) {
                    isAllowedTo('delete_own');
                }
            } elseif (!allowedTo('delete_any') && ($row['ID_MEMBER_POSTER'] != $ID_MEMBER || !allowedTo('delete_replies')) && !empty($modSettings['edit_disable_time']) && $row['posterTime'] + $modSettings['edit_disable_time'] * 60 < time()) {
                fatal_lang_error('modify_post_time_passed', false);
            }
        } elseif ($row['ID_MEMBER_POSTER'] == $ID_MEMBER && !allowedTo('delete_any')) {
            isAllowedTo('delete_replies');
        } else {
            isAllowedTo('delete_any');
        }
    }
    // Delete the *whole* topic, but only if the topic consists of one message.
    if ($row['ID_FIRST_MSG'] == $message) {
        if (empty($board) || $row['ID_BOARD'] != $board) {
            $remove_any = boardsAllowedTo('remove_any');
            $remove_any = in_array(0, $remove_any) || in_array($row['ID_BOARD'], $remove_any);
            if (!$remove_any) {
                $remove_own = boardsAllowedTo('remove_own');
                $remove_own = in_array(0, $remove_own) || in_array($row['ID_BOARD'], $remove_own);
            }
            if ($row['ID_MEMBER'] != $ID_MEMBER && !$remove_any) {
                fatal_lang_error('cannot_remove_any');
            } elseif (!$remove_any && !$remove_own) {
                fatal_lang_error('cannot_remove_own');
            }
        } else {
            // Check permissions to delete a whole topic.
            if ($row['ID_MEMBER'] != $ID_MEMBER) {
                isAllowedTo('remove_any');
            } elseif (!allowedTo('remove_any')) {
                isAllowedTo('remove_own');
            }
        }
        // ...if there is only one post.
        if (!empty($row['numReplies'])) {
            fatal_lang_error('delFirstPost', false);
        }
        removeTopics($row['ID_TOPIC']);
        return true;
    }
    // Default recycle to false.
    $recycle = false;
    // If recycle topics has been set, make a copy of this message in the recycle board.
    // Make sure we're not recycling messages that are already on the recycle board.
    if (!empty($modSettings['recycle_enable']) && $row['ID_BOARD'] != $modSettings['recycle_board'] && $row['icon'] != 'recycled') {
        // Check if the recycle board exists and if so get the read status.
        $request = db_query("\n\t\t\tSELECT (IFNULL(lb.ID_MSG, 0) >= b.ID_MSG_UPDATED) AS isSeen\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\t\tLEFT JOIN {$db_prefix}log_boards AS lb ON (lb.ID_BOARD = b.ID_BOARD AND lb.ID_MEMBER = {$ID_MEMBER})\n\t\t\tWHERE b.ID_BOARD = {$modSettings['recycle_board']}", __FILE__, __LINE__);
        if (mysql_num_rows($request) == 0) {
            fatal_lang_error('recycle_no_valid_board');
        }
        list($isRead) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Insert a new topic in the recycle board.
        db_query("\n\t\t\tINSERT INTO {$db_prefix}topics\n\t\t\t\t(ID_BOARD, ID_MEMBER_STARTED, ID_MEMBER_UPDATED, ID_FIRST_MSG, ID_LAST_MSG)\n\t\t\tVALUES ({$modSettings['recycle_board']}, {$row['ID_MEMBER']}, {$row['ID_MEMBER']}, {$message}, {$message})", __FILE__, __LINE__);
        // Capture the ID of the new topic...
        $topicID = db_insert_id();
        // If the topic creation went successful, move the message.
        if ($topicID > 0) {
            db_query("\n\t\t\t\tUPDATE {$db_prefix}messages\n\t\t\t\tSET \n\t\t\t\t\tID_TOPIC = {$topicID},\n\t\t\t\t\tID_BOARD = {$modSettings['recycle_board']},\n\t\t\t\t\ticon = 'recycled'\n\t\t\t\tWHERE ID_MSG = {$message}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
            // Mark recycled topic as read.
            if (!$user_info['is_guest']) {
                db_query("\n\t\t\t\t\tREPLACE INTO {$db_prefix}log_topics\n\t\t\t\t\t\t(ID_TOPIC, ID_MEMBER, ID_MSG)\n\t\t\t\t\tVALUES ({$topicID}, {$ID_MEMBER}, {$modSettings['maxMsgID']})", __FILE__, __LINE__);
            }
            // Mark recycle board as seen, if it was marked as seen before.
            if (!empty($isRead) && !$user_info['is_guest']) {
                db_query("\n\t\t\t\t\tREPLACE INTO {$db_prefix}log_boards\n\t\t\t\t\t\t(ID_BOARD, ID_MEMBER, ID_MSG)\n\t\t\t\t\tVALUES ({$modSettings['recycle_board']}, {$ID_MEMBER}, {$modSettings['maxMsgID']})", __FILE__, __LINE__);
            }
            // Add one topic and post to the recycle bin board.
            db_query("\n\t\t\t\tUPDATE {$db_prefix}boards\n\t\t\t\tSET\n\t\t\t\t\tnumTopics = numTopics + 1,\n\t\t\t\t\tnumPosts = numPosts + 1\n\t\t\t\tWHERE ID_BOARD = {$modSettings['recycle_board']}\n\t\t\t\tLIMIT 1", __FILE__, __LINE__);
            // Make sure this message isn't getting deleted later on.
            $recycle = true;
            // Make sure we update the search subject index.
            updateStats('subject', $topicID, $row['subject']);
        }
    }
    // Deleting a recycled message can not lower anyone's post count.
    if ($row['icon'] == 'recycled') {
        $decreasePostCount = false;
    }
    // This is the last post, update the last post on the board.
    if ($row['ID_LAST_MSG'] == $message) {
        // Find the last message, set it, and decrease the post count.
        $request = db_query("\n\t\t\tSELECT ID_MSG, ID_MEMBER\n\t\t\tFROM {$db_prefix}messages\n\t\t\tWHERE ID_TOPIC = {$row['ID_TOPIC']}\n\t\t\t\tAND ID_MSG != {$message}\n\t\t\tORDER BY ID_MSG DESC\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        $row2 = mysql_fetch_assoc($request);
        mysql_free_result($request);
        db_query("\n\t\t\tUPDATE {$db_prefix}topics\n\t\t\tSET\n\t\t\t\tID_LAST_MSG = {$row2['ID_MSG']},\n\t\t\t\tnumReplies = IF(numReplies = 0, 0, numReplies - 1),\n\t\t\t\tID_MEMBER_UPDATED = {$row2['ID_MEMBER']}\n\t\t\tWHERE ID_TOPIC = {$row['ID_TOPIC']}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
    } else {
        db_query("\n\t\t\tUPDATE {$db_prefix}topics\n\t\t\tSET numReplies = IF(numReplies = 0, 0, numReplies - 1)\n\t\t\tWHERE ID_TOPIC = {$row['ID_TOPIC']}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
    }
    db_query("\n\t\tUPDATE {$db_prefix}boards\n\t\tSET numPosts = IF(numPosts = 0, 0, numPosts - 1)\n\t\tWHERE ID_BOARD = {$row['ID_BOARD']}\n\t\tLIMIT 1", __FILE__, __LINE__);
    // If the poster was registered and the board this message was on incremented
    // the member's posts when it was posted, decrease his or her post count.
    if (!empty($row['ID_MEMBER']) && $decreasePostCount && empty($row['countPosts'])) {
        updateMemberData($row['ID_MEMBER'], array('posts' => '-'));
    }
    // Only remove posts if they're not recycled.
    if (!$recycle) {
        // Remove the message!
        db_query("\n\t\t\tDELETE FROM {$db_prefix}messages\n\t\t\tWHERE ID_MSG = {$message}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        if (!empty($modSettings['search_custom_index_config'])) {
            $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
            $words = text2words($row['body'], $customIndexSettings['bytes_per_word'], true);
            if (!empty($words)) {
                db_query("\n\t\t\t\t\tDELETE FROM {$db_prefix}log_search_words\n\t\t\t\t\tWHERE ID_WORD IN (" . implode(', ', $words) . ")\n\t\t\t\t\t\tAND ID_MSG = {$message}", __FILE__, __LINE__);
            }
        }
        // Delete attachment(s) if they exist.
        require_once $sourcedir . '/ManageAttachments.php';
        removeAttachments('a.attachmentType = 0 AND a.ID_MSG = ' . $message);
    }
    // Update the pesky statistics.
    updateStats('message');
    updateStats('topic');
    updateStats('calendar');
    // And now to update the last message of each board we messed with.
    require_once $sourcedir . '/Subs-Post.php';
    if ($recycle) {
        updateLastMessages(array($row['ID_BOARD'], $modSettings['recycle_board']));
    } else {
        updateLastMessages($row['ID_BOARD']);
    }
    return false;
}
コード例 #14
0
ファイル: ManageSearch.subs.php プロジェクト: KeiroD/Elkarte
/**
 * Creates a custom search index
 *
 * @package Search
 * @param int $start
 * @param int $messages_per_batch
 * @param string $column_size_definition
 * @param mixed[] $index_settings array containing specifics of what to create e.g. bytes per word
 */
function createSearchIndex($start, $messages_per_batch, $column_size_definition, $index_settings)
{
    global $modSettings;
    $db = database();
    $db_search = db_search();
    $step = 1;
    // Starting a new index we set up for the run
    if ($start === 0) {
        drop_log_search_words();
        $db_search->create_word_search($column_size_definition);
        // Temporarily switch back to not using a search index.
        if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom') {
            updateSettings(array('search_index' => ''));
        }
        // Don't let simultaneous processes be updating the search index.
        if (!empty($modSettings['search_custom_index_config'])) {
            updateSettings(array('search_custom_index_config' => ''));
        }
    }
    $num_messages = array('done' => 0, 'todo' => 0);
    $request = $db->query('', '
		SELECT id_msg >= {int:starting_id} AS todo, COUNT(*) AS num_messages
		FROM {db_prefix}messages
		GROUP BY todo', array('starting_id' => $start));
    while ($row = $db->fetch_assoc($request)) {
        $num_messages[empty($row['todo']) ? 'done' : 'todo'] = $row['num_messages'];
    }
    // Done with indexing the messages, on to the next step
    if (empty($num_messages['todo'])) {
        $step = 2;
        $percentage = 80;
        $start = 0;
    } else {
        // Number of seconds before the next step.
        $stop = time() + 3;
        while (time() < $stop) {
            $inserts = array();
            $request = $db->query('', '
				SELECT id_msg, body
				FROM {db_prefix}messages
				WHERE id_msg BETWEEN {int:starting_id} AND {int:ending_id}
				LIMIT {int:limit}', array('starting_id' => $start, 'ending_id' => $start + $messages_per_batch - 1, 'limit' => $messages_per_batch));
            $forced_break = false;
            $number_processed = 0;
            while ($row = $db->fetch_assoc($request)) {
                // In theory it's possible for one of these to take friggin ages so add more timeout protection.
                if ($stop < time()) {
                    $forced_break = true;
                    break;
                }
                $number_processed++;
                foreach (text2words($row['body'], $index_settings['bytes_per_word'], true) as $id_word) {
                    $inserts[] = array($id_word, $row['id_msg']);
                }
            }
            $num_messages['done'] += $number_processed;
            $num_messages['todo'] -= $number_processed;
            $db->free_result($request);
            $start += $forced_break ? $number_processed : $messages_per_batch;
            if (!empty($inserts)) {
                $db->insert('ignore', '{db_prefix}log_search_words', array('id_word' => 'int', 'id_msg' => 'int'), $inserts, array('id_word', 'id_msg'));
            }
            // Done then set up for the next step, set up for the next loop.
            if ($num_messages['todo'] === 0) {
                $step = 2;
                $start = 0;
                break;
            } else {
                updateSettings(array('search_custom_index_resume' => serialize(array_merge($index_settings, array('resume_at' => $start)))));
            }
        }
        // Since there are still steps to go, 80% is the maximum here.
        $percentage = round($num_messages['done'] / ($num_messages['done'] + $num_messages['todo']), 3) * 80;
    }
    return array($start, $step, $percentage);
}
コード例 #15
0
 public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
 {
     global $modSettings;
     $subwords = text2words($word, null, false);
     if (!$this->canDoBooleanSearch && count($subwords) > 1 && empty($modSettings['search_force_index'])) {
         $wordsSearch['words'][] = $word;
     }
     if ($this->canDoBooleanSearch) {
         $fulltextWord = count($subwords) === 1 ? $word : '"' . $word . '"';
         $wordsSearch['indexed_words'][] = $fulltextWord;
         if ($isExcluded) {
             $wordsExclude[] = $fulltextWord;
         }
     } elseif (count($subwords) > 1 && $isExcluded) {
         return;
     } else {
         $relyOnIndex = true;
         foreach ($subwords as $subword) {
             if ($smcFunc['strlen']($subword) >= $this->min_word_length && !in_array($subword, $this->bannedWords)) {
                 $wordsSearch['indexed_words'][] = $subword;
                 if ($isExcluded) {
                     $wordsExclude[] = $subword;
                 }
             } elseif (!in_array($subword, $this->bannedWords)) {
                 $relyOnIndex = false;
             }
         }
         if ($this->canDoBooleanSearch && !$relyOnIndex && empty($modSettings['search_force_index'])) {
             $wordsSearch['words'][] = $word;
         }
     }
 }
コード例 #16
0
ファイル: SearchAPI-Fulltext.php プロジェクト: Glyph13/SMF2.1
 /**
  * fulltext_search::prepareIndexes()
  *
  * Do we have to do some work with the words we are searching for to prepare them?
  *
  * @param mixed $word
  * @param mixed $wordsSearch
  * @param mixed $wordsExclude
  * @param mixed $isExcluded
  * @return
  */
 public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
 {
     global $modSettings, $smcFunc;
     $subwords = text2words($word, null, false);
     if (empty($modSettings['search_force_index'])) {
         // A boolean capable search engine and not forced to only use an index, we may use a non indexed search
         // this is harder on the server so we are restrictive here
         if (count($subwords) > 1 && preg_match('~[.:@$]~', $word)) {
             // using special characters that a full index would ignore and the remaining words are short which would also be ignored
             if ($smcFunc['strlen'](current($subwords)) < $this->min_word_length && $smcFunc['strlen'](next($subwords)) < $this->min_word_length) {
                 $wordsSearch['words'][] = trim($word, "/*- ");
                 $wordsSearch['complex_words'][] = count($subwords) === 1 ? $word : '"' . $word . '"';
             }
         } elseif ($smcFunc['strlen'](trim($word, "/*- ")) < $this->min_word_length) {
             // short words have feelings too
             $wordsSearch['words'][] = trim($word, "/*- ");
             $wordsSearch['complex_words'][] = count($subwords) === 1 ? $word : '"' . $word . '"';
         }
     }
     $fulltextWord = count($subwords) === 1 ? $word : '"' . $word . '"';
     $wordsSearch['indexed_words'][] = $fulltextWord;
     if ($isExcluded) {
         $wordsExclude[] = $fulltextWord;
     }
 }
コード例 #17
0
ファイル: Topic.subs.php プロジェクト: Ralkage/Elkarte
/**
 * Removes the passed id_topic's.
 * Permissions are NOT checked here because the function is used in a scheduled task
 *
 * @param int[]|int $topics The topics to remove (can be an id or an array of ids).
 * @param bool $decreasePostCount if true users' post count will be reduced
 * @param bool $ignoreRecycling if true topics are not moved to the recycle board (if it exists).
 */
function removeTopics($topics, $decreasePostCount = true, $ignoreRecycling = false)
{
    global $modSettings;
    $db = database();
    // Nothing to do?
    if (empty($topics)) {
        return;
    }
    // Only a single topic.
    if (is_numeric($topics)) {
        $topics = array($topics);
    }
    // Decrease the post counts for members.
    if ($decreasePostCount) {
        $requestMembers = $db->query('', '
			SELECT m.id_member, COUNT(*) AS posts
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
			WHERE m.id_topic IN ({array_int:topics})
				AND m.icon != {string:recycled}
				AND b.count_posts = {int:do_count_posts}
				AND m.approved = {int:is_approved}
			GROUP BY m.id_member', array('do_count_posts' => 0, 'recycled' => 'recycled', 'topics' => $topics, 'is_approved' => 1));
        if ($db->num_rows($requestMembers) > 0) {
            while ($rowMembers = $db->fetch_assoc($requestMembers)) {
                updateMemberData($rowMembers['id_member'], array('posts' => 'posts - ' . $rowMembers['posts']));
            }
        }
        $db->free_result($requestMembers);
    }
    // Recycle topics that aren't in the recycle board...
    if (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 && !$ignoreRecycling) {
        $request = $db->query('', '
			SELECT id_topic, id_board, unapproved_posts, approved
			FROM {db_prefix}topics
			WHERE id_topic IN ({array_int:topics})
				AND id_board != {int:recycle_board}
			LIMIT ' . count($topics), array('recycle_board' => $modSettings['recycle_board'], 'topics' => $topics));
        if ($db->num_rows($request) > 0) {
            // Get topics that will be recycled.
            $recycleTopics = array();
            while ($row = $db->fetch_assoc($request)) {
                if (function_exists('apache_reset_timeout')) {
                    @apache_reset_timeout();
                }
                $recycleTopics[] = $row['id_topic'];
                // Set the id_previous_board for this topic - and make it not sticky.
                $db->query('', '
					UPDATE {db_prefix}topics
					SET id_previous_board = {int:id_previous_board}, is_sticky = {int:not_sticky}
					WHERE id_topic = {int:id_topic}', array('id_previous_board' => $row['id_board'], 'id_topic' => $row['id_topic'], 'not_sticky' => 0));
            }
            $db->free_result($request);
            // Mark recycled topics as recycled.
            $db->query('', '
				UPDATE {db_prefix}messages
				SET icon = {string:recycled}
				WHERE id_topic IN ({array_int:recycle_topics})', array('recycle_topics' => $recycleTopics, 'recycled' => 'recycled'));
            // Move the topics to the recycle board.
            require_once SUBSDIR . '/Topic.subs.php';
            moveTopics($recycleTopics, $modSettings['recycle_board']);
            // Close reports that are being recycled.
            require_once SUBSDIR . '/Moderation.subs.php';
            $db->query('', '
				UPDATE {db_prefix}log_reported
				SET closed = {int:is_closed}
				WHERE id_topic IN ({array_int:recycle_topics})', array('recycle_topics' => $recycleTopics, 'is_closed' => 1));
            updateSettings(array('last_mod_report_action' => time()));
            recountOpenReports();
            // Topics that were recycled don't need to be deleted, so subtract them.
            $topics = array_diff($topics, $recycleTopics);
        } else {
            $db->free_result($request);
        }
    }
    // Still topics left to delete?
    if (empty($topics)) {
        return;
    }
    $adjustBoards = array();
    // Find out how many posts we are deleting.
    $request = $db->query('', '
		SELECT id_board, approved, COUNT(*) AS num_topics, SUM(unapproved_posts) AS unapproved_posts,
			SUM(num_replies) AS num_replies
		FROM {db_prefix}topics
		WHERE id_topic IN ({array_int:topics})
		GROUP BY id_board, approved', array('topics' => $topics));
    while ($row = $db->fetch_assoc($request)) {
        if (!isset($adjustBoards[$row['id_board']]['num_posts'])) {
            cache_put_data('board-' . $row['id_board'], null, 120);
            $adjustBoards[$row['id_board']] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0, 'id_board' => $row['id_board']);
        }
        // Posts = (num_replies + 1) for each approved topic.
        $adjustBoards[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? $row['num_topics'] : 0);
        $adjustBoards[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts'];
        // Add the topics to the right type.
        if ($row['approved']) {
            $adjustBoards[$row['id_board']]['num_topics'] += $row['num_topics'];
        } else {
            $adjustBoards[$row['id_board']]['unapproved_topics'] += $row['num_topics'];
        }
    }
    $db->free_result($request);
    // Decrease number of posts and topics for each board.
    foreach ($adjustBoards as $stats) {
        if (function_exists('apache_reset_timeout')) {
            @apache_reset_timeout();
        }
        $db->query('', '
			UPDATE {db_prefix}boards
			SET
				num_posts = CASE WHEN {int:num_posts} > num_posts THEN 0 ELSE num_posts - {int:num_posts} END,
				num_topics = CASE WHEN {int:num_topics} > num_topics THEN 0 ELSE num_topics - {int:num_topics} END,
				unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END,
				unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END
			WHERE id_board = {int:id_board}', array('id_board' => $stats['id_board'], 'num_posts' => $stats['num_posts'], 'num_topics' => $stats['num_topics'], 'unapproved_posts' => $stats['unapproved_posts'], 'unapproved_topics' => $stats['unapproved_topics']));
    }
    // Remove polls for these topics.
    $request = $db->query('', '
		SELECT id_poll
		FROM {db_prefix}topics
		WHERE id_topic IN ({array_int:topics})
			AND id_poll > {int:no_poll}
		LIMIT ' . count($topics), array('no_poll' => 0, 'topics' => $topics));
    $polls = array();
    while ($row = $db->fetch_assoc($request)) {
        $polls[] = $row['id_poll'];
    }
    $db->free_result($request);
    if (!empty($polls)) {
        $db->query('', '
			DELETE FROM {db_prefix}polls
			WHERE id_poll IN ({array_int:polls})', array('polls' => $polls));
        $db->query('', '
			DELETE FROM {db_prefix}poll_choices
			WHERE id_poll IN ({array_int:polls})', array('polls' => $polls));
        $db->query('', '
			DELETE FROM {db_prefix}log_polls
			WHERE id_poll IN ({array_int:polls})', array('polls' => $polls));
    }
    // Get rid of the attachment(s).
    require_once SUBSDIR . '/ManageAttachments.subs.php';
    $attachmentQuery = array('attachment_type' => 0, 'id_topic' => $topics);
    removeAttachments($attachmentQuery, 'messages');
    // Delete search index entries.
    if (!empty($modSettings['search_custom_index_config'])) {
        $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
        $request = $db->query('', '
			SELECT id_msg, body
			FROM {db_prefix}messages
			WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
        $words = array();
        $messages = array();
        while ($row = $db->fetch_assoc($request)) {
            if (function_exists('apache_reset_timeout')) {
                @apache_reset_timeout();
            }
            $words = array_merge($words, text2words($row['body'], $customIndexSettings['bytes_per_word'], true));
            $messages[] = $row['id_msg'];
        }
        $db->free_result($request);
        $words = array_unique($words);
        if (!empty($words) && !empty($messages)) {
            $db->query('', '
				DELETE FROM {db_prefix}log_search_words
				WHERE id_word IN ({array_int:word_list})
					AND id_msg IN ({array_int:message_list})', array('word_list' => $words, 'message_list' => $messages));
        }
    }
    // Reuse the message array if available
    if (empty($messages)) {
        $messages = messagesInTopics($topics);
    }
    // If there are messages left in this topic
    if (!empty($messages)) {
        // Remove all likes now that the topic is gone
        $db->query('', '
			DELETE FROM {db_prefix}message_likes
			WHERE id_msg IN ({array_int:messages})', array('messages' => $messages));
        // Remove all mentions now that the topic is gone
        $db->query('', '
			DELETE FROM {db_prefix}log_mentions
			WHERE id_msg IN ({array_int:messages})', array('messages' => $messages));
    }
    // Delete messages in each topic.
    $db->query('', '
		DELETE FROM {db_prefix}messages
		WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
    // Remove linked calendar events.
    // @todo if unlinked events are enabled, wouldn't this be expected to keep them?
    $db->query('', '
		DELETE FROM {db_prefix}calendar
		WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
    // Delete log_topics data
    $db->query('', '
		DELETE FROM {db_prefix}log_topics
		WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
    // Delete notifications
    $db->query('', '
		DELETE FROM {db_prefix}log_notify
		WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
    // Delete the topics themselves
    $db->query('', '
		DELETE FROM {db_prefix}topics
		WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
    // Remove data from the subjects for search cache
    $db->query('', '
		DELETE FROM {db_prefix}log_search_subjects
		WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
    require_once SUBSDIR . '/FollowUps.subs.php';
    removeFollowUpsByTopic($topics);
    foreach ($topics as $topic_id) {
        cache_put_data('topic_board-' . $topic_id, null, 120);
    }
    // Maybe there's an addon that wants to delete topic related data of its own
    call_integration_hook('integrate_remove_topics', array($topics));
    // Update the totals...
    updateStats('message');
    updateTopicStats();
    updateSettings(array('calendar_updated' => time()));
    require_once SUBSDIR . '/Post.subs.php';
    $updates = array();
    foreach ($adjustBoards as $stats) {
        $updates[] = $stats['id_board'];
    }
    updateLastMessages($updates);
}
コード例 #18
0
ファイル: SearchAPI-Custom.php プロジェクト: Glyph13/SMF2.1
    /**
     * After a post is modified, we update the search index database.
     */
    public function postModified($msgOptions, $topicOptions, $posterOptions)
    {
        global $modSettings, $smcFunc;
        if (isset($msgOptions['body'])) {
            $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
            $stopwords = empty($modSettings['search_stopwords']) ? array() : explode(',', $modSettings['search_stopwords']);
            $old_body = isset($msgOptions['old_body']) ? $msgOptions['old_body'] : '';
            // create thew new and old index
            $old_index = text2words($old_body, $customIndexSettings['bytes_per_word'], true);
            $new_index = text2words($msgOptions['body'], $customIndexSettings['bytes_per_word'], true);
            // Calculate the words to be added and removed from the index.
            $removed_words = array_diff(array_diff($old_index, $new_index), $stopwords);
            $inserted_words = array_diff(array_diff($new_index, $old_index), $stopwords);
            // Delete the removed words AND the added ones to avoid key constraints.
            if (!empty($removed_words)) {
                $removed_words = array_merge($removed_words, $inserted_words);
                $smcFunc['db_query']('', '
					DELETE FROM {db_prefix}log_search_words
					WHERE id_msg = {int:id_msg}
						AND id_word IN ({array_int:removed_words})', array('removed_words' => $removed_words, 'id_msg' => $msgOptions['id']));
            }
            // Add the new words to be indexed.
            if (!empty($inserted_words)) {
                $inserts = array();
                foreach ($inserted_words as $word) {
                    $inserts[] = array($word, $msgOptions['id']);
                }
                $smcFunc['db_insert']('insert', '{db_prefix}log_search_words', array('id_word' => 'string', 'id_msg' => 'int'), $inserts, array('id_word', 'id_msg'));
            }
        }
    }
コード例 #19
0
ファイル: Search.php プロジェクト: VBGAMER45/SMFMods
function PlushSearch2()
{
    global $scripturl, $modSettings, $sourcedir, $txt, $db_prefix, $db_connection;
    global $user_info, $ID_MEMBER, $context, $options, $messages_request, $boards_can;
    global $excludedWords, $participants, $func;
    // !!! Add spam protection.
    if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) {
        fatal_lang_error('loadavg_search_disabled', false);
    }
    // No, no, no... this is a bit hard on the server, so don't you go prefetching it!
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Forbidden');
        die;
    }
    $weight_factors = array('frequency', 'age', 'length', 'subject', 'first_message', 'sticky');
    $weight = array();
    $weight_total = 0;
    foreach ($weight_factors as $weight_factor) {
        $weight[$weight_factor] = empty($modSettings['search_weight_' . $weight_factor]) ? 0 : (int) $modSettings['search_weight_' . $weight_factor];
        $weight_total += $weight[$weight_factor];
    }
    // Zero weight.  Weightless :P.
    if (empty($weight_total)) {
        fatal_lang_error('search_invalid_weights');
    }
    // These vars don't require an interface, the're just here for tweaking.
    $recentPercentage = 0.3;
    $humungousTopicPosts = 200;
    $maxMembersToSearch = 500;
    $maxMessageResults = empty($modSettings['search_max_results']) ? 0 : $modSettings['search_max_results'] * 5;
    // Start with no errors.
    $context['search_errors'] = array();
    // Number of pages hard maximum - normally not set at all.
    $modSettings['search_max_results'] = empty($modSettings['search_max_results']) ? 200 * $modSettings['search_results_per_page'] : (int) $modSettings['search_max_results'];
    loadLanguage('Search');
    loadTemplate('Search');
    // Are you allowed?
    isAllowedTo('search_posts');
    require_once $sourcedir . '/Display.php';
    if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'fulltext') {
        // Try to determine the minimum number of letters for a fulltext search.
        $request = db_query("\n\t\t\tSHOW VARIABLES\n\t\t\tLIKE 'ft_min_word_len'", false, false);
        if ($request !== false && mysql_num_rows($request) == 1) {
            list(, $min_word_length) = mysql_fetch_row($request);
            mysql_free_result($request);
        } else {
            $min_word_length = '4';
        }
        // Some MySQL versions are superior to others :P.
        $canDoBooleanSearch = version_compare(mysql_get_server_info($db_connection), '4.0.1', '>=') == 1;
        // Get a list of banned fulltext words.
        $banned_words = empty($modSettings['search_banned_words']) ? array() : explode(',', addslashes($modSettings['search_banned_words']));
    } elseif (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom' && !empty($modSettings['search_custom_index_config'])) {
        $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
        $min_word_length = $customIndexSettings['bytes_per_word'];
        $banned_words = empty($modSettings['search_stopwords']) ? array() : explode(',', addslashes($modSettings['search_stopwords']));
    } else {
        $modSettings['search_index'] = '';
    }
    // $search_params will carry all settings that differ from the default search parameters.
    // That way, the URLs involved in a search page will be kept as short as possible.
    $search_params = array();
    if (isset($_REQUEST['params'])) {
        $temp_params = explode('|"|', base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))));
        foreach ($temp_params as $i => $data) {
            @(list($k, $v) = explode('|\'|', $data));
            $search_params[$k] = stripslashes($v);
        }
        if (isset($search_params['brd'])) {
            $search_params['brd'] = empty($search_params['brd']) ? array() : explode(',', $search_params['brd']);
        }
    }
    // Store whether simple search was used (needed if the user wants to do another query).
    if (!isset($search_params['advanced'])) {
        $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1;
    }
    // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'.
    if (!empty($search_params['searchtype']) || !empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2) {
        $search_params['searchtype'] = 2;
    }
    // Minimum age of messages. Default to zero (don't set param in that case).
    if (!empty($search_params['minage']) || !empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0) {
        $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage'];
    }
    // Maximum age of messages. Default to infinite (9999 days: param not set).
    if (!empty($search_params['maxage']) || !empty($_REQUEST['maxage']) && $_REQUEST['maxage'] != 9999) {
        $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage'];
    }
    // Searching a specific topic?
    if (!empty($_REQUEST['topic'])) {
        $search_params['topic'] = (int) $_REQUEST['topic'];
        $search_params['show_complete'] = true;
    } elseif (!empty($search_params['topic'])) {
        $search_params['topic'] = (int) $search_params['topic'];
    }
    if (!empty($search_params['minage']) || !empty($search_params['maxage'])) {
        $request = db_query("\n\t\t\tSELECT " . (empty($search_params['maxage']) ? '0, ' : 'IFNULL(MIN(ID_MSG), -1), ') . (empty($search_params['minage']) ? '0' : 'IFNULL(MAX(ID_MSG), -1)') . "\n\t\t\tFROM {$db_prefix}messages\n\t\t\tWHERE " . (empty($search_params['minage']) ? '1' : 'posterTime <= ' . (time() - 86400 * $search_params['minage'])) . (empty($search_params['maxage']) ? '' : "\n\t\t\t\tAND posterTime >= " . (time() - 86400 * $search_params['maxage'])), __FILE__, __LINE__);
        list($minMsgID, $maxMsgID) = mysql_fetch_row($request);
        if ($minMsgID < 0 || $maxMsgID < 0) {
            $context['search_errors']['no_messages_in_time_frame'] = true;
        }
        mysql_free_result($request);
    }
    // Default the user name to a wildcard matching every user (*).
    if (!empty($search_params['userspec']) || !empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*') {
        $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec'];
    }
    // If there's no specific user, then don't mention it in the main query.
    if (empty($search_params['userspec'])) {
        $userQuery = '';
    } else {
        $userString = strtr(addslashes($func['htmlspecialchars'](stripslashes($search_params['userspec']), ENT_QUOTES)), array('&quot;' => '"'));
        $userString = strtr($userString, array('%' => '\\%', '_' => '\\_', '*' => '%', '?' => '_'));
        preg_match_all('~"([^"]+)"~', $userString, $matches);
        $possible_users = array_merge($matches[1], explode(',', preg_replace('~"([^"]+)"~', '', $userString)));
        for ($k = 0, $n = count($possible_users); $k < $n; $k++) {
            $possible_users[$k] = trim($possible_users[$k]);
            if (strlen($possible_users[$k]) == 0) {
                unset($possible_users[$k]);
            }
        }
        // Retrieve a list of possible members.
        $request = db_query("\n\t\t\tSELECT ID_MEMBER\n\t\t\tFROM {$db_prefix}members\n\t\t\tWHERE realName LIKE '" . implode("' OR realName LIKE '", $possible_users) . "'", __FILE__, __LINE__);
        // Simply do nothing if there're too many members matching the criteria.
        if (mysql_num_rows($request) > $maxMembersToSearch) {
            $userQuery = '';
        } elseif (mysql_num_rows($request) == 0) {
            $userQuery = "m.ID_MEMBER = 0 AND (m.posterName LIKE '" . implode("' OR m.posterName LIKE '", $possible_users) . "')";
        } else {
            $memberlist = array();
            while ($row = mysql_fetch_assoc($request)) {
                $memberlist[] = $row['ID_MEMBER'];
            }
            $userQuery = "(m.ID_MEMBER IN (" . implode(', ', $memberlist) . ") OR (m.ID_MEMBER = 0 AND (m.posterName LIKE '" . implode("' OR m.posterName LIKE '", $possible_users) . "')))";
        }
        mysql_free_result($request);
    }
    // If the boards were passed by URL (params=), temporarily put them back in $_REQUEST.
    if (!empty($search_params['brd']) && is_array($search_params['brd'])) {
        $_REQUEST['brd'] = $search_params['brd'];
    }
    // Ensure that brd is an array.
    if (!empty($_REQUEST['brd']) && !is_array($_REQUEST['brd'])) {
        $_REQUEST['brd'] = strpos($_REQUEST['brd'], ',') !== false ? explode(',', $_REQUEST['brd']) : array($_REQUEST['brd']);
    }
    // Make sure all boards are integers.
    if (!empty($_REQUEST['brd'])) {
        foreach ($_REQUEST['brd'] as $id => $brd) {
            $_REQUEST['brd'][$id] = (int) $brd;
        }
    }
    // Special case for boards: searching just one topic?
    if (!empty($search_params['topic'])) {
        $request = db_query("\n\t\t\tSELECT b.ID_BOARD\n\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}boards AS b)\n\t\t\tWHERE b.ID_BOARD = t.ID_BOARD\n\t\t\t\tAND t.ID_TOPIC = " . $search_params['topic'] . "\n\t\t\t\tAND {$user_info['query_see_board']}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        if (mysql_num_rows($request) == 0) {
            fatal_lang_error('topic_gone', false);
        }
        $search_params['brd'] = array();
        list($search_params['brd'][0]) = mysql_fetch_row($request);
        mysql_free_result($request);
    } elseif ($user_info['is_admin'] && (!empty($search_params['advanced']) || !empty($_REQUEST['brd']))) {
        $search_params['brd'] = empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'];
    } else {
        $request = db_query("\n\t\t\tSELECT b.ID_BOARD\n\t\t\tFROM {$db_prefix}boards AS b\n\t\t\tWHERE {$user_info['query_see_board']}" . (empty($_REQUEST['brd']) ? !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? "\n\t\t\t\tAND b.ID_BOARD != {$modSettings['recycle_board']}" : '' : "\n\t\t\t\tAND b.ID_BOARD IN (" . implode(', ', $_REQUEST['brd']) . ")"), __FILE__, __LINE__);
        $search_params['brd'] = array();
        while ($row = mysql_fetch_assoc($request)) {
            $search_params['brd'][] = $row['ID_BOARD'];
        }
        mysql_free_result($request);
        // This error should pro'bly only happen for hackers.
        if (empty($search_params['brd'])) {
            $context['search_errors']['no_boards_selected'] = true;
        }
    }
    if (count($search_params['brd']) != 0) {
        // If we've selected all boards, this parameter can be left empty.
        $request = db_query("\n\t\t\tSELECT COUNT(*)\n\t\t\tFROM {$db_prefix}boards", __FILE__, __LINE__);
        list($num_boards) = mysql_fetch_row($request);
        mysql_free_result($request);
        if (count($search_params['brd']) == $num_boards) {
            $boardQuery = '';
        } elseif (count($search_params['brd']) == $num_boards - 1 && !empty($modSettings['recycle_board']) && !in_array($modSettings['recycle_board'], $search_params['brd'])) {
            $boardQuery = '!= ' . $modSettings['recycle_board'];
        } else {
            $boardQuery = 'IN (' . implode(', ', $search_params['brd']) . ')';
        }
    } else {
        $boardQuery = '';
    }
    $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
    $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
    $context['compact'] = !$search_params['show_complete'];
    // Get the sorting parameters right. Default to sort by relevance descending.
    $sort_columns = array('relevance', 'numReplies', 'ID_MSG');
    if (empty($search_params['sort']) && !empty($_REQUEST['sort'])) {
        list($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, '');
    }
    $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'relevance';
    if (!empty($search_params['topic']) && $search_params['sort'] === 'numReplies') {
        $search_params['sort'] = 'ID_MSG';
    }
    // Sorting direction: descending unless stated otherwise.
    $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
    // Determine some values needed to calculate the relevance.
    $minMsg = (int) ((1 - $recentPercentage) * $modSettings['maxMsgID']);
    $recentMsg = $modSettings['maxMsgID'] - $minMsg;
    // *** Parse the search query
    // Unfortunately, searching for words like this is going to be slow, so we're blacklisting them.
    // !!! Setting to add more here?
    // !!! Maybe only blacklist if they are the only word, or "any" is used?
    $blacklisted_words = array('img', 'url', 'quote', 'www', 'http', 'the', 'is', 'it', 'are', 'if');
    // What are we searching for?
    if (empty($search_params['search'])) {
        if (isset($_GET['search'])) {
            $search_params['search'] = un_htmlspecialchars($_GET['search']);
        } elseif (isset($_POST['search'])) {
            $search_params['search'] = stripslashes($_POST['search']);
        } else {
            $search_params['search'] = '';
        }
    }
    // Nothing??
    if (!isset($search_params['search']) || $search_params['search'] == '') {
        $context['search_errors']['invalid_search_string'] = true;
    }
    // Change non-word characters into spaces.
    $stripped_query = preg_replace('~([\\x0B\\0' . ($context['utf8'] ? $context['server']['complex_preg_chars'] ? '\\x{A0}' : pack('C*', 0xc2, 0xa0) : '\\xA0') . '\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]|&(amp|lt|gt|quot);)+~' . ($context['utf8'] ? 'u' : ''), ' ', $search_params['search']);
    // Make the query lower case. It's gonna be case insensitive anyway.
    $stripped_query = un_htmlspecialchars($func['strtolower']($stripped_query));
    // This (hidden) setting will do fulltext searching in the most basic way.
    if (!empty($modSettings['search_simple_fulltext'])) {
        $stripped_query = strtr($stripped_query, array('"' => ''));
    }
    $no_regexp = preg_match('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', $stripped_query) === 1;
    // Extract phrase parts first (e.g. some words "this is a phrase" some more words.)
    preg_match_all('/(?:^|\\s)([-]?)"([^"]+)"(?:$|\\s)/', $stripped_query, $matches, PREG_PATTERN_ORDER);
    $phraseArray = $matches[2];
    // Remove the phrase parts and extract the words.
    $wordArray = explode(' ', preg_replace('~(?:^|\\s)([-]?)"([^"]+)"(?:$|\\s)~' . ($context['utf8'] ? 'u' : ''), ' ', $stripped_query));
    // A minus sign in front of a word excludes the word.... so...
    $excludedWords = array();
    $excludedIndexWords = array();
    $excludedSubjectWords = array();
    $excludedPhrases = array();
    // .. first, we check for things like -"some words", but not "-some words".
    foreach ($matches[1] as $index => $word) {
        if ($word === '-') {
            if (($word = trim($phraseArray[$index], '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = addslashes($word);
            }
            unset($phraseArray[$index]);
        }
    }
    // Now we look for -test, etc.... normaller.
    foreach ($wordArray as $index => $word) {
        if (strpos(trim($word), '-') === 0) {
            if (($word = trim($word, '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = addslashes($word);
            }
            unset($wordArray[$index]);
        }
    }
    // The remaining words and phrases are all included.
    $searchArray = array_merge($phraseArray, $wordArray);
    // Trim everything and make sure there are no words that are the same.
    foreach ($searchArray as $index => $value) {
        if (($searchArray[$index] = trim($value, '-_\' ')) === '' || in_array($searchArray[$index], $blacklisted_words)) {
            unset($searchArray[$index]);
        } else {
            $searchArray[$index] = addslashes($searchArray[$index]);
        }
    }
    $searchArray = array_slice(array_unique($searchArray), 0, 10);
    // Create an array of replacements for highlighting.
    $context['mark'] = array();
    foreach ($searchArray as $word) {
        $context['mark'][$word] = '<b class="highlight">' . $word . '</b>';
    }
    // Initialize two arrays storing the words that have to be searched for.
    $orParts = array();
    $searchWords = array();
    // Make sure at least one word is being searched for.
    if (empty($searchArray)) {
        $context['search_errors']['invalid_search_string'] = true;
    } elseif (empty($search_params['searchtype'])) {
        $orParts[0] = $searchArray;
    } else {
        foreach ($searchArray as $index => $value) {
            $orParts[$index] = array($value);
        }
    }
    // Make sure the excluded words are in all or-branches.
    foreach ($orParts as $orIndex => $andParts) {
        foreach ($excludedWords as $word) {
            $orParts[$orIndex][] = $word;
        }
    }
    // Determine the or-branches and the fulltext search words.
    foreach ($orParts as $orIndex => $andParts) {
        $searchWords[$orIndex] = array('indexed_words' => array(), 'words' => array(), 'subject_words' => array(), 'all_words' => array());
        // Sort the indexed words (large words -> small words -> excluded words).
        if (!empty($modSettings['search_index'])) {
            usort($orParts[$orIndex], 'searchSort');
        }
        foreach ($orParts[$orIndex] as $word) {
            $is_excluded = in_array($word, $excludedWords);
            $searchWords[$orIndex]['all_words'][] = $word;
            $subjectWords = text2words(stripslashes($word));
            if (!$is_excluded || count($subjectWords) === 1) {
                $searchWords[$orIndex]['subject_words'] = array_merge($searchWords[$orIndex]['subject_words'], $subjectWords);
                if ($is_excluded) {
                    $excludedSubjectWords = array_merge($excludedSubjectWords, $subjectWords);
                }
            } else {
                $excludedPhrases[] = $word;
            }
            if (!empty($modSettings['search_index'])) {
                $subwords = text2words(stripslashes($word), $modSettings['search_index'] === 'fulltext' ? null : $min_word_length, $modSettings['search_index'] === 'custom');
                if (($modSettings['search_index'] === 'custom' || $modSettings['search_index'] === 'fulltext' && !$canDoBooleanSearch && count($subwords) > 1) && empty($modSettings['search_force_index'])) {
                    $searchWords[$orIndex]['words'][] = $word;
                }
                if ($modSettings['search_index'] === 'fulltext' && $canDoBooleanSearch) {
                    $fulltextWord = count($subwords) === 1 ? $word : '"' . $word . '"';
                    $searchWords[$orIndex]['indexed_words'][] = $fulltextWord;
                    if ($is_excluded) {
                        $excludedIndexWords[] = $fulltextWord;
                    }
                } elseif (count($subwords) > 1 && $is_excluded) {
                    continue;
                } else {
                    $relyOnIndex = true;
                    foreach ($subwords as $subword) {
                        if (($modSettings['search_index'] === 'custom' || strlen(stripslashes($subword)) >= $min_word_length) && !in_array($subword, $banned_words)) {
                            $searchWords[$orIndex]['indexed_words'][] = $subword;
                            if ($is_excluded) {
                                $excludedIndexWords[] = $subword;
                            }
                        } elseif (!in_array($subword, $banned_words)) {
                            $relyOnIndex = false;
                        }
                    }
                    if ($modSettings['search_index'] === 'fulltext' && $canDoBooleanSearch && !$relyOnIndex && empty($modSettings['search_force_index'])) {
                        $searchWords[$orIndex]['words'][] = $word;
                    }
                }
            }
        }
        // Search_force_index requires all AND parts to have at least one fulltext word.
        if (!empty($modSettings['search_force_index']) && empty($searchWords[$orIndex]['indexed_words'])) {
            $context['search_errors']['query_not_specific_enough'] = true;
            break;
        } else {
            $searchWords[$orIndex]['indexed_words'] = array_slice($searchWords[$orIndex]['indexed_words'], 0, 7);
            $searchWords[$orIndex]['subject_words'] = array_slice($searchWords[$orIndex]['subject_words'], 0, 7);
        }
    }
    // *** Spell checking
    $context['show_spellchecking'] = !empty($modSettings['enableSpellChecking']) && function_exists('pspell_new');
    if ($context['show_spellchecking']) {
        // Windows fix.
        ob_start();
        $old = error_reporting(0);
        pspell_new('en');
        $pspell_link = pspell_new($txt['lang_dictionary'], $txt['lang_spelling'], '', strtr($txt['lang_character_set'], array('iso-' => 'iso', 'ISO-' => 'iso')), PSPELL_FAST | PSPELL_RUN_TOGETHER);
        error_reporting($old);
        if (!$pspell_link) {
            $pspell_link = pspell_new('en', '', '', '', PSPELL_FAST | PSPELL_RUN_TOGETHER);
        }
        ob_end_clean();
        $did_you_mean = array('search' => array(), 'display' => array());
        $found_misspelling = false;
        foreach ($searchArray as $word) {
            if (empty($pspell_link)) {
                continue;
            }
            $word = stripslashes($word);
            // Don't check phrases.
            if (preg_match('~^\\w+$~', $word) === 0) {
                $did_you_mean['search'][] = '"' . $word . '"';
                $did_you_mean['display'][] = '&quot;' . $func['htmlspecialchars']($word) . '&quot;';
                continue;
            } elseif (preg_match('~\\d~', $word) === 1) {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $func['htmlspecialchars']($word);
                continue;
            } elseif (pspell_check($pspell_link, $word)) {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $func['htmlspecialchars']($word);
                continue;
            }
            $suggestions = pspell_suggest($pspell_link, $word);
            foreach ($suggestions as $i => $s) {
                // Search is case insensitive.
                if ($func['strtolower']($s) == $func['strtolower']($word)) {
                    unset($suggestions[$i]);
                }
            }
            // Anything found?  If so, correct it!
            if (!empty($suggestions)) {
                $suggestions = array_values($suggestions);
                $did_you_mean['search'][] = $suggestions[0];
                $did_you_mean['display'][] = '<em><b>' . $func['htmlspecialchars']($suggestions[0]) . '</b></em>';
                $found_misspelling = true;
            } else {
                $did_you_mean['search'][] = $word;
                $did_you_mean['display'][] = $func['htmlspecialchars']($word);
            }
        }
        if ($found_misspelling) {
            // Don't spell check excluded words, but add them still...
            $temp_excluded = array('search' => array(), 'display' => array());
            foreach ($excludedWords as $word) {
                $word = stripslashes($word);
                if (preg_match('~^\\w+$~', $word) == 0) {
                    $temp_excluded['search'][] = '-"' . $word . '"';
                    $temp_excluded['display'][] = '-&quot;' . $func['htmlspecialchars']($word) . '&quot;';
                } else {
                    $temp_excluded['search'][] = '-' . $word;
                    $temp_excluded['display'][] = '-' . $func['htmlspecialchars']($word);
                }
            }
            $did_you_mean['search'] = array_merge($did_you_mean['search'], $temp_excluded['search']);
            $did_you_mean['display'] = array_merge($did_you_mean['display'], $temp_excluded['display']);
            $temp_params = $search_params;
            $temp_params['search'] = implode(' ', $did_you_mean['search']);
            if (isset($temp_params['brd'])) {
                $temp_params['brd'] = implode(',', $temp_params['brd']);
            }
            $context['params'] = array();
            foreach ($temp_params as $k => $v) {
                $context['did_you_mean_params'][] = $k . '|\'|' . addslashes($v);
            }
            $context['did_you_mean_params'] = base64_encode(implode('|"|', $context['did_you_mean_params']));
            $context['did_you_mean'] = implode(' ', $did_you_mean['display']);
        }
    }
    // Let the user adjust the search query, should they wish?
    $context['search_params'] = $search_params;
    if (isset($context['search_params']['search'])) {
        $context['search_params']['search'] = $func['htmlspecialchars']($context['search_params']['search']);
    }
    if (isset($context['search_params']['userspec'])) {
        $context['search_params']['userspec'] = $func['htmlspecialchars']($context['search_params']['userspec']);
    }
    // *** Encode all search params
    // All search params have been checked, let's compile them to a single string... made less simple by PHP 4.3.9 and below.
    $temp_params = $search_params;
    if (isset($temp_params['brd'])) {
        $temp_params['brd'] = implode(',', $temp_params['brd']);
    }
    $context['params'] = array();
    foreach ($temp_params as $k => $v) {
        $context['params'][] = $k . '|\'|' . addslashes($v);
    }
    $context['params'] = base64_encode(implode('|"|', $context['params']));
    // ... and add the links to the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?action=search;params=' . $context['params'], 'name' => $txt[182]);
    $context['linktree'][] = array('url' => $scripturl . '?action=search2;params=' . $context['params'], 'name' => $txt['search_results']);
    // *** A last error check
    // One or more search errors? Go back to the first search screen.
    if (!empty($context['search_errors'])) {
        $_REQUEST['params'] = $context['params'];
        return PlushSearch1();
    }
    /*	// !!! This doesn't seem too urgent anymore. Can we remove it?
    	if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2)
    	{
    		// !!! Change error message...
    		if (cache_get_data('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $ID_MEMBER), 90) == 1)
    			fatal_lang_error('loadavg_search_disabled', false);
    		cache_put_data('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $ID_MEMBER), 1, 90);
    	}*/
    // *** Reserve an ID for caching the search results.
    // Update the cache if the current search term is not yet cached.
    if (empty($_SESSION['search_cache']) || $_SESSION['search_cache']['params'] != $context['params']) {
        // Increase the pointer...
        $modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer'];
        // ...and store it right off.
        updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1));
        // As long as you don't change the parameters, the cache result is yours.
        $_SESSION['search_cache'] = array('ID_SEARCH' => $modSettings['search_pointer'], 'num_results' => -1, 'params' => $context['params']);
        // Clear the previous cache of the final results cache.
        db_query("\n\t\t\tDELETE FROM {$db_prefix}log_search_results\n\t\t\tWHERE ID_SEARCH = " . $_SESSION['search_cache']['ID_SEARCH'], __FILE__, __LINE__);
        if ($search_params['subject_only']) {
            foreach ($searchWords as $orIndex => $words) {
                $subject_query = array('from' => array("{$db_prefix}topics AS t"), 'left_join' => array(), 'where' => array());
                $numTables = 0;
                $prev_join = 0;
                $numSubjectResults = 0;
                foreach ($words['subject_words'] as $subjectWord) {
                    $numTables++;
                    if (in_array($subjectWord, $excludedSubjectWords)) {
                        $subject_query['left_join'][] = "{$db_prefix}log_search_subjects AS subj{$numTables} ON (subj{$numTables}.word " . (empty($modSettings['search_match_words']) ? "LIKE '%{$subjectWord}%'" : "= '{$subjectWord}'") . " AND subj{$numTables}.ID_TOPIC = t.ID_TOPIC)";
                        $subject_query['where'][] = "(subj{$numTables}.word IS NULL)";
                    } else {
                        $subject_query['from'][] = "{$db_prefix}log_search_subjects AS subj{$numTables}";
                        $subject_query['where'][] = "subj{$numTables}.word " . (empty($modSettings['search_match_words']) ? "LIKE '%{$subjectWord}%'" : "= '{$subjectWord}'");
                        $subject_query['where'][] = "subj{$numTables}.ID_TOPIC = " . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.ID_TOPIC';
                        $prev_join = $numTables;
                    }
                }
                if (!empty($userQuery)) {
                    if (!in_array("{$db_prefix}messages AS m", $subject_query['from'])) {
                        $subject_query['from'][] = "{$db_prefix}messages AS m";
                        $subject_query['where'][] = 'm.ID_TOPIC = t.ID_TOPIC';
                    }
                    $subject_query['where'][] = $userQuery;
                }
                if (!empty($search_params['topic'])) {
                    $subject_query['where'][] = 't.ID_TOPIC = ' . $search_params['topic'];
                }
                if (!empty($minMsgID)) {
                    $subject_query['where'][] = 't.ID_FIRST_MSG >= ' . $minMsgID;
                }
                if (!empty($maxMsgID)) {
                    $subject_query['where'][] = 't.ID_LAST_MSG <= ' . $maxMsgID;
                }
                if (!empty($boardQuery)) {
                    $subject_query['where'][] = 't.ID_BOARD ' . $boardQuery;
                }
                if (!empty($excludedPhrases)) {
                    if (!in_array("{$db_prefix}messages AS m", $subject_query['from'])) {
                        $subject_query['from'][] = "{$db_prefix}messages AS m";
                        $subject_query['where'][] = 'm.ID_MSG = t.ID_FIRST_MSG';
                    }
                    foreach ($excludedPhrases as $phrase) {
                        $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . "[[:>:]]'");
                    }
                }
                db_query("\n\t\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_search_results\n\t\t\t\t\t\t(ID_SEARCH, ID_TOPIC, relevance, ID_MSG, num_matches)\n\t\t\t\t\tSELECT \n\t\t\t\t\t\t" . $_SESSION['search_cache']['ID_SEARCH'] . ",\n\t\t\t\t\t\tt.ID_TOPIC,\n\t\t\t\t\t\t1000 * (\n\t\t\t\t\t\t\t{$weight['frequency']} / (t.numReplies + 1) +\n\t\t\t\t\t\t\t{$weight['age']} * IF(t.ID_FIRST_MSG < {$minMsg}, 0, (t.ID_FIRST_MSG - {$minMsg}) / {$recentMsg}) +\n\t\t\t\t\t\t\t{$weight['length']} * IF(t.numReplies < {$humungousTopicPosts}, t.numReplies / {$humungousTopicPosts}, 1) +\n\t\t\t\t\t\t\t{$weight['subject']} +\n\t\t\t\t\t\t\t{$weight['sticky']} * t.isSticky\n\t\t\t\t\t\t) / {$weight_total} AS relevance,\n\t\t\t\t\t\t" . (empty($userQuery) ? 't.ID_FIRST_MSG' : 'm.ID_MSG') . ",\n\t\t\t\t\t\t1\n\t\t\t\t\tFROM (" . implode(', ', $subject_query['from']) . ')' . (empty($subject_query['left_join']) ? '' : "\n\t\t\t\t\t\tLEFT JOIN " . implode("\n\t\t\t\t\t\tLEFT JOIN ", $subject_query['left_join'])) . "\n\t\t\t\t\tWHERE " . implode("\n\t\t\t\t\t\tAND ", $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : "\n\t\t\t\t\tLIMIT " . ($modSettings['search_max_results'] - $numSubjectResults)), __FILE__, __LINE__);
                $numSubjectResults += db_affected_rows();
                if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                    break;
                }
            }
            $_SESSION['search_cache']['num_results'] = $numSubjectResults;
        } else {
            $main_query = array('select' => array('ID_SEARCH' => $_SESSION['search_cache']['ID_SEARCH'], 'relevance' => '0'), 'weights' => array(), 'from' => array("{$db_prefix}topics AS t", "{$db_prefix}messages AS m"), 'left_join' => array(), 'where' => array('t.ID_TOPIC = m.ID_TOPIC'), 'group_by' => array());
            if (empty($search_params['topic'])) {
                $main_query['select']['ID_TOPIC'] = 't.ID_TOPIC';
                $main_query['select']['ID_MSG'] = 'MAX(m.ID_MSG) AS ID_MSG';
                $main_query['select']['num_matches'] = 'COUNT(*) AS num_matches';
                $main_query['weights'] = array('frequency' => 'COUNT(*) / (t.numReplies + 1)', 'age' => "IF(MAX(m.ID_MSG) < {$minMsg}, 0, (MAX(m.ID_MSG) - {$minMsg}) / {$recentMsg})", 'length' => "IF(t.numReplies < {$humungousTopicPosts}, t.numReplies / {$humungousTopicPosts}, 1)", 'subject' => '0', 'first_message' => "IF(MIN(m.ID_MSG) = t.ID_FIRST_MSG, 1, 0)", 'sticky' => 't.isSticky');
                $main_query['group_by'][] = 't.ID_TOPIC';
            } else {
                // This is outrageous!
                $main_query['select']['ID_TOPIC'] = 'm.ID_MSG AS ID_TOPIC';
                $main_query['select']['ID_MSG'] = 'm.ID_MSG';
                $main_query['select']['num_matches'] = '1 AS num_matches';
                $main_query['weights'] = array('age' => "((m.ID_MSG - t.ID_FIRST_MSG) / IF(t.ID_LAST_MSG = t.ID_FIRST_MSG, 1, t.ID_LAST_MSG - t.ID_FIRST_MSG))", 'first_message' => "IF(m.ID_MSG = t.ID_FIRST_MSG, 1, 0)");
                $main_query['where'][] = 't.ID_TOPIC = ' . $search_params['topic'];
            }
            // *** Get the subject results.
            $numSubjectResults = 0;
            if (empty($search_params['topic'])) {
                // Create a temporary table to store some preliminary results in.
                db_query("\n\t\t\t\t\tDROP TABLE IF EXISTS {$db_prefix}tmp_log_search_topics", __FILE__, __LINE__);
                $createTemporary = db_query("\n\t\t\t\t\tCREATE TEMPORARY TABLE {$db_prefix}tmp_log_search_topics (\n\t\t\t\t\t\tID_TOPIC mediumint(8) unsigned NOT NULL default '0',\n\t\t\t\t\t\tPRIMARY KEY (ID_TOPIC)\n\t\t\t\t\t) TYPE=HEAP", false, false) !== false;
                // Clean up some previous cache.
                if (!$createTemporary) {
                    db_query("\n\t\t\t\t\t\tDELETE FROM {$db_prefix}log_search_topics\n\t\t\t\t\t\tWHERE ID_SEARCH = " . $_SESSION['search_cache']['ID_SEARCH'], __FILE__, __LINE__);
                }
                foreach ($searchWords as $orIndex => $words) {
                    $subject_query = array('from' => array("{$db_prefix}topics AS t"), 'left_join' => array(), 'where' => array());
                    $numTables = 0;
                    $prev_join = 0;
                    foreach ($words['subject_words'] as $subjectWord) {
                        $numTables++;
                        if (in_array($subjectWord, $excludedSubjectWords)) {
                            if (!in_array("{$db_prefix}messages AS m", $subject_query['from'])) {
                                $subject_query['from'][] = "{$db_prefix}messages AS m";
                                $subject_query['where'][] = 'm.ID_MSG = t.ID_FIRST_MSG';
                            }
                            $subject_query['left_join'][] = "{$db_prefix}log_search_subjects AS subj{$numTables} ON (subj{$numTables}.word " . (empty($modSettings['search_match_words']) ? "LIKE '%{$subjectWord}%'" : "= '{$subjectWord}'") . " AND subj{$numTables}.ID_TOPIC = t.ID_TOPIC)";
                            $subject_query['where'][] = "(subj{$numTables}.word IS NULL)";
                            $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($subjectWord, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $subjectWord), '\\\'') . "[[:>:]]'");
                        } else {
                            $subject_query['from'][] = "{$db_prefix}log_search_subjects AS subj{$numTables}";
                            $subject_query['where'][] = "subj{$numTables}.word " . (empty($modSettings['search_match_words']) ? "LIKE '%{$subjectWord}%'" : "= '{$subjectWord}'");
                            $subject_query['where'][] = "subj{$numTables}.ID_TOPIC = " . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.ID_TOPIC';
                            $prev_join = $numTables;
                        }
                    }
                    if (!empty($userQuery)) {
                        if (!in_array("{$db_prefix}messages AS m", $subject_query['from'])) {
                            $subject_query['from'][] = "{$db_prefix}messages AS m";
                            $subject_query['where'][] = 'm.ID_MSG = t.ID_FIRST_MSG';
                        }
                        $subject_query['where'][] = $userQuery;
                    }
                    if (!empty($search_params['topic'])) {
                        $subject_query['where'][] = 't.ID_TOPIC = ' . $search_params['topic'];
                    }
                    if (!empty($minMsgID)) {
                        $subject_query['where'][] = 't.ID_FIRST_MSG >= ' . $minMsgID;
                    }
                    if (!empty($maxMsgID)) {
                        $subject_query['where'][] = 't.ID_LAST_MSG <= ' . $maxMsgID;
                    }
                    if (!empty($boardQuery)) {
                        $subject_query['where'][] = 't.ID_BOARD ' . $boardQuery;
                    }
                    if (!empty($excludedPhrases)) {
                        if (!in_array("{$db_prefix}messages AS m", $subject_query['from'])) {
                            $subject_query['from'][] = "{$db_prefix}messages AS m";
                            $subject_query['where'][] = 'm.ID_MSG = t.ID_FIRST_MSG';
                        }
                        foreach ($excludedPhrases as $phrase) {
                            $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . "[[:>:]]'");
                            $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . "[[:>:]]'");
                        }
                    }
                    db_query("\n\t\t\t\t\t\tINSERT IGNORE INTO {$db_prefix}" . ($createTemporary ? 'tmp_' : '') . "log_search_topics\n\t\t\t\t\t\t\t(" . ($createTemporary ? '' : 'ID_SEARCH, ') . "ID_TOPIC)\n\t\t\t\t\t\tSELECT " . ($createTemporary ? '' : $_SESSION['search_cache']['ID_SEARCH'] . ', ') . "t.ID_TOPIC\n\t\t\t\t\t\tFROM (" . implode(', ', $subject_query['from']) . ')' . (empty($subject_query['left_join']) ? '' : "\n\t\t\t\t\t\t\tLEFT JOIN " . implode("\n\t\t\t\t\t\t\tLEFT JOIN ", $subject_query['left_join'])) . "\n\t\t\t\t\t\tWHERE " . implode("\n\t\t\t\t\t\t\tAND ", $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : "\n\t\t\t\t\t\tLIMIT " . ($modSettings['search_max_results'] - $numSubjectResults)), __FILE__, __LINE__);
                    $numSubjectResults += db_affected_rows();
                    if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                        break;
                    }
                }
                if ($numSubjectResults !== 0) {
                    $main_query['weights']['subject'] = 'IF(lst.ID_TOPIC IS NULL, 0, 1)';
                    $main_query['left_join'][] = "{$db_prefix}" . ($createTemporary ? 'tmp_' : '') . "log_search_topics AS lst ON (" . ($createTemporary ? '' : 'lst.ID_SEARCH = ' . $_SESSION['search_cache']['ID_SEARCH'] . ' AND ') . "lst.ID_TOPIC = t.ID_TOPIC)";
                }
            }
            $indexedResults = 0;
            if (!empty($modSettings['search_index'])) {
                db_query("\n\t\t\t\t\tDROP TABLE IF EXISTS {$db_prefix}tmp_log_search_messages", __FILE__, __LINE__);
                $createTemporary = db_query("\n\t\t\t\t\tCREATE TEMPORARY TABLE {$db_prefix}tmp_log_search_messages (\n\t\t\t\t\t\tID_MSG int(10) unsigned NOT NULL default '0',\n\t\t\t\t\t\tPRIMARY KEY (ID_MSG)\n\t\t\t\t\t) TYPE=HEAP", false, false) !== false;
                if (!$createTemporary) {
                    db_query("\n\t\t\t\t\t\tDELETE FROM {$db_prefix}log_search_messages\n\t\t\t\t\t\tWHERE ID_SEARCH = " . $_SESSION['search_cache']['ID_SEARCH'], __FILE__, __LINE__);
                }
                foreach ($searchWords as $orIndex => $words) {
                    // *** Do the fulltext search.
                    if (!empty($words['indexed_words']) && $modSettings['search_index'] == 'fulltext') {
                        $fulltext_query = array('insert_into' => $db_prefix . ($createTemporary ? 'tmp_' : '') . 'log_search_messages', 'select' => array('ID_MSG' => 'ID_MSG'), 'where' => array());
                        if (!$createTemporary) {
                            $fulltext_query['select']['ID_SEARCH'] = $_SESSION['search_cache']['ID_SEARCH'];
                        }
                        if (empty($modSettings['search_simple_fulltext'])) {
                            foreach ($words['words'] as $regularWord) {
                                $fulltext_query['where'][] = 'body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . "[[:>:]]'");
                            }
                        }
                        if (!empty($userQuery)) {
                            $fulltext_query['where'][] = strtr($userQuery, array('m.' => ''));
                        }
                        if (!empty($search_params['topic'])) {
                            $fulltext_query['where'][] = 'ID_TOPIC = ' . $search_params['topic'];
                        }
                        if (!empty($minMsgID)) {
                            $fulltext_query['where'][] = 'ID_MSG >= ' . $minMsgID;
                        }
                        if (!empty($maxMsgID)) {
                            $fulltext_query['where'][] = 'ID_MSG <= ' . $maxMsgID;
                        }
                        if (!empty($boardQuery)) {
                            $fulltext_query['where'][] = 'ID_BOARD ' . $boardQuery;
                        }
                        if (!empty($excludedPhrases) && empty($modSettings['search_force_index'])) {
                            foreach ($excludedPhrases as $phrase) {
                                $fulltext_query['where'][] = 'subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . "[[:>:]]'");
                            }
                        }
                        if (!empty($excludedSubjectWords) && empty($modSettings['search_force_index'])) {
                            foreach ($excludedSubjectWords as $excludedWord) {
                                $fulltext_query['where'][] = 'subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($excludedWord, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $excludedWord), '\\\'') . "[[:>:]]'");
                            }
                        }
                        if (!empty($modSettings['search_simple_fulltext'])) {
                            $fulltext_query['where'][] = "MATCH (body) AGAINST ('" . implode(' ', array_diff($words['indexed_words'], $excludedIndexWords)) . "')";
                        } elseif ($canDoBooleanSearch) {
                            $where = "MATCH (body) AGAINST ('";
                            foreach ($words['indexed_words'] as $fulltextWord) {
                                $where .= (in_array($fulltextWord, $excludedIndexWords) ? '-' : '+') . $fulltextWord . ' ';
                            }
                            $fulltext_query['where'][] = substr($where, 0, -1) . "' IN BOOLEAN MODE)";
                        } else {
                            foreach ($words['indexed_words'] as $fulltextWord) {
                                $fulltext_query['where'][] = (in_array($fulltextWord, $excludedIndexWords) ? 'NOT ' : '') . "MATCH (body) AGAINST ('{$fulltextWord}')";
                            }
                        }
                        db_query("\n\t\t\t\t\t\t\tINSERT IGNORE INTO {$fulltext_query['insert_into']}\n\t\t\t\t\t\t\t\t(" . implode(', ', array_keys($fulltext_query['select'])) . ")\n\t\t\t\t\t\t\tSELECT " . implode(', ', $fulltext_query['select']) . "\n\t\t\t\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\t\t\t\tWHERE " . implode("\n\t\t\t\t\t\t\t\tAND ", $fulltext_query['where']) . (empty($maxMessageResults) ? '' : "\n\t\t\t\t\t\t\tLIMIT " . ($maxMessageResults - $indexedResults)), __FILE__, __LINE__);
                        $indexedResults += db_affected_rows();
                        if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) {
                            break;
                        }
                    } elseif (!empty($words['indexed_words']) && $modSettings['search_index'] == 'custom') {
                        $custom_query = array('insert_into' => $db_prefix . ($createTemporary ? 'tmp_' : '') . 'log_search_messages', 'select' => array('ID_MSG' => 'm.ID_MSG'), 'from' => array("{$db_prefix}messages AS m"), 'left_join' => array(), 'where' => array());
                        if (!$createTemporary) {
                            $custom_query['select']['ID_SEARCH'] = $_SESSION['search_cache']['ID_SEARCH'];
                        }
                        foreach ($words['words'] as $regularWord) {
                            $custom_query['where'][] = 'm.body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . "[[:>:]]'");
                        }
                        if (!empty($userQuery)) {
                            $custom_query['where'][] = $userQuery;
                        }
                        if (!empty($search_params['topic'])) {
                            $custom_query['where'][] = 'm.ID_TOPIC = ' . $search_params['topic'];
                        }
                        if (!empty($minMsgID)) {
                            $custom_query['where'][] = 'm.ID_MSG >= ' . $minMsgID;
                        }
                        if (!empty($maxMsgID)) {
                            $custom_query['where'][] = 'm.ID_MSG <= ' . $maxMsgID;
                        }
                        if (!empty($boardQuery)) {
                            $custom_query['where'][] = 'm.ID_BOARD ' . $boardQuery;
                        }
                        if (!empty($excludedPhrases) && empty($modSettings['search_force_index'])) {
                            foreach ($excludedPhrases as $phrase) {
                                $fulltext_query['where'][] = 'subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . "[[:>:]]'");
                            }
                        }
                        if (!empty($excludedSubjectWords) && empty($modSettings['search_force_index'])) {
                            foreach ($excludedSubjectWords as $excludedWord) {
                                $fulltext_query['where'][] = 'subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($excludedWord, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $excludedWord), '\\\'') . "[[:>:]]'");
                            }
                        }
                        $numTables = 0;
                        $prev_join = 0;
                        foreach ($words['indexed_words'] as $indexedWord) {
                            $numTables++;
                            if (in_array($indexedWord, $excludedIndexWords)) {
                                $custom_query['left_join'][] = "{$db_prefix}log_search_words AS lsw{$numTables} ON (lsw{$numTables}.ID_WORD = {$indexedWord} AND lsw{$numTables}.ID_MSG = m.ID_MSG)";
                                $custom_query['where'][] = "(lsw{$numTables}.ID_WORD IS NULL)";
                            } else {
                                $custom_query['from'][] = "{$db_prefix}log_search_words AS lsw{$numTables}";
                                $custom_query['where'][] = "lsw{$numTables}.ID_WORD = {$indexedWord}";
                                $custom_query['where'][] = "lsw{$numTables}.ID_MSG = " . ($prev_join === 0 ? 'm' : 'lsw' . $prev_join) . '.ID_MSG';
                                $prev_join = $numTables;
                            }
                        }
                        db_query("\n\t\t\t\t\t\t\tINSERT IGNORE INTO {$custom_query['insert_into']}\n\t\t\t\t\t\t\t\t(" . implode(', ', array_keys($custom_query['select'])) . ")\n\t\t\t\t\t\t\tSELECT " . implode(', ', $custom_query['select']) . "\n\t\t\t\t\t\t\tFROM (" . implode(', ', $custom_query['from']) . ')' . (empty($custom_query['left_join']) ? '' : "\n\t\t\t\t\t\t\t\tLEFT JOIN " . implode("\n\t\t\t\t\t\t\t\tLEFT JOIN ", $custom_query['left_join'])) . "\n\t\t\t\t\t\t\tWHERE " . implode("\n\t\t\t\t\t\t\t\tAND ", $custom_query['where']) . (empty($maxMessageResults) ? '' : "\n\t\t\t\t\t\t\tLIMIT " . ($maxMessageResults - $indexedResults)), __FILE__, __LINE__);
                        $indexedResults += db_affected_rows();
                        if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) {
                            break;
                        }
                    }
                }
                if (empty($indexedResults) && empty($numSubjectResults) && !empty($modSettings['search_force_index'])) {
                    $context['search_errors']['query_not_specific_enough'] = true;
                    $_REQUEST['params'] = $context['params'];
                    return PlushSearch1();
                } elseif (!empty($indexedResults)) {
                    $main_query['from'][] = $db_prefix . ($createTemporary ? 'tmp_' : '') . 'log_search_messages AS lsm';
                    $main_query['where'][] = 'lsm.ID_MSG = m.ID_MSG';
                    if (!$createTemporary) {
                        $main_query['where'][] = 'lsm.ID_SEARCH = ' . $_SESSION['search_cache']['ID_SEARCH'];
                    }
                }
            } else {
                $orWhere = array();
                foreach ($searchWords as $orIndex => $words) {
                    $where = array();
                    foreach ($words['all_words'] as $regularWord) {
                        $where[] = 'm.body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . "[[:>:]]'");
                        if (in_array($regularWord, $excludedWords)) {
                            $where[] = 'm.subject NOT' . (empty($modSettings['search_match_words']) || $no_regexp ? " LIKE '%" . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . "%'" : " RLIKE '[[:<:]]" . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . "[[:>:]]'");
                        }
                    }
                    if (!empty($where)) {
                        $orWhere[] = count($where) > 1 ? '(' . implode(' AND ', $where) . ')' : $where[0];
                    }
                }
                if (!empty($orWhere)) {
                    $main_query['where'][] = count($orWhere) > 1 ? '(' . implode(' OR ', $orWhere) . ')' : $orWhere[0];
                }
                if (!empty($userQuery)) {
                    $main_query['where'][] = $userQuery;
                }
                if (!empty($search_params['topic'])) {
                    $main_query['where'][] = 'm.ID_TOPIC = ' . $search_params['topic'];
                }
                if (!empty($minMsgID)) {
                    $main_query['where'][] = 'm.ID_MSG >= ' . $minMsgID;
                }
                if (!empty($maxMsgID)) {
                    $main_query['where'][] = 'm.ID_MSG <= ' . $maxMsgID;
                }
                if (!empty($boardQuery)) {
                    $main_query['where'][] = 'm.ID_BOARD ' . $boardQuery;
                }
            }
            if (!empty($indexedResults) || empty($modSettings['search_index'])) {
                $relevance = '1000 * (';
                $new_weight_total = 0;
                foreach ($main_query['weights'] as $type => $value) {
                    $relevance .= $weight[$type] . ' * ' . $value . ' + ';
                    $new_weight_total += $weight[$type];
                }
                $main_query['select']['relevance'] = substr($relevance, 0, -3) . ") / {$new_weight_total} AS relevance";
                db_query("\n\t\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_search_results\n\t\t\t\t\t\t(" . implode(', ', array_keys($main_query['select'])) . ")\n\t\t\t\t\tSELECT\n\t\t\t\t\t\t" . implode(',
						', $main_query['select']) . "\n\t\t\t\t\tFROM (" . implode(', ', $main_query['from']) . ')' . (empty($main_query['left_join']) ? '' : "\n\t\t\t\t\t\tLEFT JOIN " . implode("\n\t\t\t\t\t\tLEFT JOIN ", $main_query['left_join'])) . "\n\t\t\t\t\tWHERE " . implode("\n\t\t\t\t\t\tAND ", $main_query['where']) . (empty($main_query['group_by']) ? '' : "\n\t\t\t\t\tGROUP BY " . implode(', ', $main_query['group_by'])) . (empty($modSettings['search_max_results']) ? '' : "\n\t\t\t\t\tLIMIT {$modSettings['search_max_results']}"), __FILE__, __LINE__);
                $_SESSION['search_cache']['num_results'] = db_affected_rows();
            }
            // Insert subject-only matches.
            if ($_SESSION['search_cache']['num_results'] < $modSettings['search_max_results'] && $numSubjectResults !== 0) {
                db_query("\n\t\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_search_results\n\t\t\t\t\t\t(ID_SEARCH, ID_TOPIC, relevance, ID_MSG, num_matches)\n\t\t\t\t\tSELECT\n\t\t\t\t\t\t" . $_SESSION['search_cache']['ID_SEARCH'] . ",\n\t\t\t\t\t\tt.ID_TOPIC,\n\t\t\t\t\t\t1000 * (\n\t\t\t\t\t\t\t{$weight['frequency']} / (t.numReplies + 1) +\n\t\t\t\t\t\t\t{$weight['age']} * IF(t.ID_FIRST_MSG < {$minMsg}, 0, (t.ID_FIRST_MSG - {$minMsg}) / {$recentMsg}) +\n\t\t\t\t\t\t\t{$weight['length']} * IF(t.numReplies < {$humungousTopicPosts}, t.numReplies / {$humungousTopicPosts}, 1) +\n\t\t\t\t\t\t\t{$weight['subject']} +\n\t\t\t\t\t\t\t{$weight['sticky']} * t.isSticky\n\t\t\t\t\t\t) / {$weight_total} AS relevance,\n\t\t\t\t\t\tt.ID_FIRST_MSG,\n\t\t\t\t\t\t1\n\t\t\t\t\tFROM ({$db_prefix}topics AS t, {$db_prefix}" . ($createTemporary ? 'tmp_' : '') . "log_search_topics AS lst)\n\t\t\t\t\tWHERE lst.ID_TOPIC = t.ID_TOPIC" . (empty($modSettings['search_max_results']) ? '' : "\n\t\t\t\t\tLIMIT " . ($modSettings['search_max_results'] - $_SESSION['search_cache']['num_results'])), __FILE__, __LINE__);
                $_SESSION['search_cache']['num_results'] += db_affected_rows();
            } elseif ($_SESSION['search_cache']['num_results'] == -1) {
                $_SESSION['search_cache']['num_results'] = 0;
            }
        }
    }
    // *** Retrieve the results to be shown on the page
    $participants = array();
    $request = db_query("\n\t\tSELECT " . (empty($search_params['topic']) ? 'lsr.ID_TOPIC' : $search_params['topic'] . ' AS ID_TOPIC') . ", lsr.ID_MSG, lsr.relevance, lsr.num_matches\n\t\tFROM ({$db_prefix}log_search_results AS lsr" . ($search_params['sort'] == 'numReplies' ? ", {$db_prefix}topics AS t" : '') . ")\n\t\tWHERE ID_SEARCH = " . $_SESSION['search_cache']['ID_SEARCH'] . ($search_params['sort'] == 'numReplies' ? "\n\t\t\tAND t.ID_TOPIC = lsr.ID_TOPIC" : '') . "\n\t\tORDER BY {$search_params['sort']} {$search_params['sort_dir']}\n\t\tLIMIT " . (int) $_REQUEST['start'] . ", {$modSettings['search_results_per_page']}", __FILE__, __LINE__);
    while ($row = mysql_fetch_assoc($request)) {
        $context['topics'][$row['ID_MSG']] = array('id' => $row['ID_TOPIC'], 'relevance' => round($row['relevance'] / 10, 1) . '%', 'num_matches' => $row['num_matches'], 'matches' => array());
        // By default they didn't participate in the topic!
        $participants[$row['ID_TOPIC']] = false;
    }
    mysql_free_result($request);
    // Now that we know how many results to expect we can start calculating the page numbers.
    $context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $_SESSION['search_cache']['num_results'], $modSettings['search_results_per_page'], false);
    if (!empty($context['topics'])) {
        // Create an array for the permissions.
        $boards_can = array('post_reply_own' => boardsAllowedTo('post_reply_own'), 'post_reply_any' => boardsAllowedTo('post_reply_any'), 'mark_any_notify' => boardsAllowedTo('mark_any_notify'));
        // How's about some quick moderation?
        if (!empty($options['display_quick_mod']) && !empty($context['topics'])) {
            $boards_can['lock_any'] = boardsAllowedTo('lock_any');
            $boards_can['lock_own'] = boardsAllowedTo('lock_own');
            $boards_can['make_sticky'] = boardsAllowedTo('make_sticky');
            $boards_can['move_any'] = boardsAllowedTo('move_any');
            $boards_can['move_own'] = boardsAllowedTo('move_own');
            $boards_can['remove_any'] = boardsAllowedTo('remove_any');
            $boards_can['remove_own'] = boardsAllowedTo('remove_own');
            $boards_can['merge_any'] = boardsAllowedTo('merge_any');
            $context['can_lock'] = in_array(0, $boards_can['lock_any']);
            $context['can_sticky'] = in_array(0, $boards_can['make_sticky']) && !empty($modSettings['enableStickyTopics']);
            $context['can_move'] = in_array(0, $boards_can['move_any']);
            $context['can_remove'] = in_array(0, $boards_can['remove_any']);
            $context['can_merge'] = in_array(0, $boards_can['merge_any']);
        }
        // Load the posters...
        $request = db_query("\n\t\t\tSELECT ID_MEMBER\n\t\t\tFROM {$db_prefix}messages\n\t\t\tWHERE ID_MEMBER != 0\n\t\t\t\tAND ID_MSG IN (" . implode(', ', array_keys($context['topics'])) . ")\n\t\t\tLIMIT " . count($context['topics']), __FILE__, __LINE__);
        $posters = array();
        while ($row = mysql_fetch_assoc($request)) {
            $posters[] = $row['ID_MEMBER'];
        }
        mysql_free_result($request);
        if (!empty($posters)) {
            loadMemberData(array_unique($posters));
        }
        // Get the messages out for the callback - select enough that it can be made to look just like Display.
        $messages_request = db_query("\n\t\t\tSELECT\n\t\t\t\tm.ID_MSG, m.subject, m.posterName, m.posterEmail, m.posterTime, m.ID_MEMBER,\n\t\t\t\tm.icon, m.posterIP, m.body, m.smileysEnabled, m.modifiedTime, m.modifiedName,\n\t\t\t\tfirst_m.ID_MSG AS first_msg, first_m.subject AS first_subject, first_m.icon AS firstIcon, first_m.posterTime AS first_posterTime,\n\t\t\t\tfirst_mem.ID_MEMBER AS first_member_id, IFNULL(first_mem.realName, first_m.posterName) AS first_member_name,\n\t\t\t\tlast_m.ID_MSG AS last_msg, last_m.posterTime AS last_posterTime, last_mem.ID_MEMBER AS last_member_id,\n\t\t\t\tIFNULL(last_mem.realName, last_m.posterName) AS last_member_name, last_m.icon AS lastIcon, last_m.subject AS last_subject,\n\t\t\t\tt.ID_TOPIC, t.isSticky, t.locked, t.ID_POLL, t.numReplies, t.numViews,\n\t\t\t\tb.ID_BOARD, b.name AS bName, c.ID_CAT, c.name AS cName\n\t\t\tFROM ({$db_prefix}messages AS m, {$db_prefix}topics AS t, {$db_prefix}boards AS b, {$db_prefix}categories AS c, {$db_prefix}messages AS first_m, {$db_prefix}messages AS last_m)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS first_mem ON (first_mem.ID_MEMBER = first_m.ID_MEMBER)\n\t\t\t\tLEFT JOIN {$db_prefix}members AS last_mem ON (last_mem.ID_MEMBER = first_m.ID_MEMBER)\n\t\t\tWHERE m.ID_MSG IN (" . implode(', ', array_keys($context['topics'])) . ")\n\t\t\t\tAND t.ID_TOPIC = m.ID_TOPIC\n\t\t\t\tAND b.ID_BOARD = t.ID_BOARD\n\t\t\t\tAND c.ID_CAT = b.ID_CAT\n\t\t\t\tAND first_m.ID_MSG = t.ID_FIRST_MSG\n\t\t\t\tAND last_m.ID_MSG = t.ID_LAST_MSG\n\t\t\tORDER BY FIND_IN_SET(m.ID_MSG, '" . implode(',', array_keys($context['topics'])) . "')\n\t\t\tLIMIT " . count($context['topics']), __FILE__, __LINE__);
        // Note that the reg-exp slows things alot, but makes things make a lot more sense.
        // If we want to know who participated in what then load this now.
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest']) {
            $result = db_query("\n\t\t\t\tSELECT ID_TOPIC\n\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\tWHERE ID_TOPIC IN (" . implode(', ', array_keys($participants)) . ")\n\t\t\t\t\tAND ID_MEMBER = {$ID_MEMBER}\n\t\t\t\tGROUP BY ID_TOPIC\n\t\t\t\tLIMIT " . count($participants), __FILE__, __LINE__);
            while ($row = mysql_fetch_assoc($result)) {
                $participants[$row['ID_TOPIC']] = true;
            }
            mysql_free_result($result);
        }
    }
    // Consider the search complete!
    if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
        cache_put_data('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $ID_MEMBER), null, 90);
    }
    $context['key_words'] =& $searchArray;
    // Set the basic stuff for the template.
    $context['allow_hide_email'] = !empty($modSettings['allow_hideEmail']);
    // Setup the default topic icons... for checking they exist and the like!
    $stable_icons = array('xx', 'thumbup', 'thumbdown', 'exclamation', 'question', 'lamp', 'smiley', 'angry', 'cheesy', 'grin', 'sad', 'wink', 'moved', 'recycled', 'wireless');
    $context['icon_sources'] = array();
    foreach ($stable_icons as $icon) {
        $context['icon_sources'][$icon] = 'images_url';
    }
    $context['sub_template'] = 'results';
    $context['page_title'] = $txt[166];
    $context['get_topics'] = 'prepareSearchContext';
    $context['can_send_pm'] = allowedTo('pm_send');
    loadJumpTo();
    if (!empty($options['display_quick_mod']) && !empty($_SESSION['move_to_topic'])) {
        foreach ($context['jump_to'] as $id => $cat) {
            if (isset($context['jump_to'][$id]['boards'][$_SESSION['move_to_topic']])) {
                $context['jump_to'][$id]['boards'][$_SESSION['move_to_topic']]['selected'] = true;
            }
        }
    }
}
コード例 #20
0
ファイル: Subs-Post.php プロジェクト: VBGAMER45/SMFMods
function modifyPost(&$msgOptions, &$topicOptions, &$posterOptions)
{
    global $db_prefix, $user_info, $ID_MEMBER, $modSettings;
    $topicOptions['poll'] = isset($topicOptions['poll']) ? (int) $topicOptions['poll'] : null;
    $topicOptions['lock_mode'] = isset($topicOptions['lock_mode']) ? $topicOptions['lock_mode'] : null;
    $topicOptions['sticky_mode'] = isset($topicOptions['sticky_mode']) ? $topicOptions['sticky_mode'] : null;
    // This is longer than it has to be, but makes it so we only set/change what we have to.
    $messages_columns = array();
    if (isset($posterOptions['name'])) {
        $messages_columns[] = "posterName = '{$posterOptions['name']}'";
    }
    if (isset($posterOptions['email'])) {
        $messages_columns[] = "posterEmail = '{$posterOptions['email']}'";
    }
    if (isset($msgOptions['icon'])) {
        $messages_columns[] = "icon = '{$msgOptions['icon']}'";
    }
    if (isset($msgOptions['subject'])) {
        $messages_columns[] = "subject = '{$msgOptions['subject']}'";
    }
    if (isset($msgOptions['body'])) {
        $messages_columns[] = "body = '{$msgOptions['body']}'";
        if (!empty($modSettings['search_custom_index_config'])) {
            $request = db_query("\n\t\t\t\tSELECT body\n\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\tWHERE ID_MSG = {$msgOptions['id']}", __FILE__, __LINE__);
            list($old_body) = mysql_fetch_row($request);
            mysql_free_result($request);
        }
    }
    if (!empty($msgOptions['modify_time'])) {
        $messages_columns[] = "modifiedTime = {$msgOptions['modify_time']}";
        $messages_columns[] = "modifiedName = '{$msgOptions['modify_name']}'";
        $messages_columns[] = "ID_MSG_MODIFIED = {$modSettings['maxMsgID']}";
    }
    if (isset($msgOptions['smileys_enabled'])) {
        $messages_columns[] = "smileysEnabled = " . (empty($msgOptions['smileys_enabled']) ? '0' : '1');
    }
    // Change the post.
    db_query("\n\t\tUPDATE {$db_prefix}messages\n\t\tSET " . implode(', ', $messages_columns) . "\n\t\tWHERE ID_MSG = {$msgOptions['id']}\n\t\tLIMIT 1", __FILE__, __LINE__);
    // Lock and or sticky the post.
    if ($topicOptions['sticky_mode'] !== null || $topicOptions['lock_mode'] !== null || $topicOptions['poll'] !== null) {
        db_query("\n\t\t\tUPDATE {$db_prefix}topics\n\t\t\tSET\n\t\t\t\tisSticky = " . ($topicOptions['sticky_mode'] === null ? 'isSticky' : $topicOptions['sticky_mode']) . ",\n\t\t\t\tlocked = " . ($topicOptions['lock_mode'] === null ? 'locked' : $topicOptions['lock_mode']) . ",\n\t\t\t\tID_POLL = " . ($topicOptions['poll'] === null ? 'ID_POLL' : $topicOptions['poll']) . "\n\t\t\tWHERE ID_TOPIC = {$topicOptions['id']}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
    }
    // Mark inserted topic as read.
    if (!empty($topicOptions['mark_as_read']) && !$user_info['is_guest']) {
        db_query("\n\t\t\tREPLACE INTO {$db_prefix}log_topics\n\t\t\t\t(ID_TOPIC, ID_MEMBER, ID_MSG)\n\t\t\tVALUES ({$topicOptions['id']}, {$ID_MEMBER}, {$modSettings['maxMsgID']})", __FILE__, __LINE__);
    }
    // If there's a custom search index, it needs to be modified...
    if (isset($msgOptions['body']) && !empty($modSettings['search_custom_index_config'])) {
        $stopwords = empty($modSettings['search_stopwords']) ? array() : explode(',', addslashes($modSettings['search_stopwords']));
        $old_index = text2words($old_body, 4, true);
        $new_index = text2words(stripslashes($msgOptions['body']), 4, true);
        // Calculate the words to remove from the index.
        $removed_words = array_diff(array_diff($old_index, $new_index), $stopwords);
        if (!empty($removed_words)) {
            db_query("\n\t\t\t\tDELETE FROM {$db_prefix}log_search_words\n\t\t\t\tWHERE ID_MSG = {$msgOptions['id']}\n\t\t\t\t\tAND ID_WORD IN (" . implode(", ", $removed_words) . ")\n\t\t\t\tLIMIT " . count($removed_words), __FILE__, __LINE__);
        }
        // Calculate the new words to be indexed.
        $inserted_words = array_diff(array_diff($new_index, $old_index), $stopwords);
        if (!empty($inserted_words)) {
            db_query("\n\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_search_words\n\t\t\t\t\t(ID_WORD, ID_MSG)\n\t\t\t\tVALUES\n\t\t\t\t\t('" . implode("', {$msgOptions['id']}),\n\t\t\t\t\t('", $inserted_words) . "', {$msgOptions['id']})", __FILE__, __LINE__);
        }
    }
    if (isset($msgOptions['subject'])) {
        // Only update the subject if this was the first message in the topic.
        $request = db_query("\n\t\t\tSELECT ID_TOPIC\n\t\t\tFROM {$db_prefix}topics\n\t\t\tWHERE ID_FIRST_MSG = {$msgOptions['id']}\n\t\t\tLIMIT 1", __FILE__, __LINE__);
        if (mysql_num_rows($request) == 1) {
            updateStats('subject', $topicOptions['id'], $msgOptions['subject']);
        }
        mysql_free_result($request);
    }
    return true;
}
コード例 #21
0
ファイル: ManageSearch.php プロジェクト: VBGAMER45/SMFMods
function CreateMessageIndex()
{
    global $modSettings, $context, $db_prefix;
    $context['admin_tabs']['tabs']['method']['is_selected'] = true;
    $messages_per_batch = 100;
    $index_properties = array(2 => array('column_definition' => 'smallint(5)'), 4 => array('column_definition' => 'mediumint(8)', 'step_size' => 1000000, 'max_size' => 16777215), 5 => array('column_definition' => 'int(10)', 'step_size' => 100000000, 'max_size' => 4294967295));
    if (isset($_REQUEST['resume']) && !empty($modSettings['search_custom_index_resume'])) {
        $context['index_settings'] = unserialize($modSettings['search_custom_index_resume']);
        $context['start'] = (int) $context['index_settings']['resume_at'];
        unset($context['index_settings']['resume_at']);
        $context['step'] = 1;
    } else {
        $context['index_settings'] = array('bytes_per_word' => isset($_REQUEST['bytes_per_word']) && isset($index_properties[$_REQUEST['bytes_per_word']]) ? (int) $_REQUEST['bytes_per_word'] : 2);
        $context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
        $context['step'] = isset($_REQUEST['step']) ? (int) $_REQUEST['step'] : 0;
    }
    if ($context['step'] !== 0) {
        checkSession('request');
    }
    // Step 0: let the user determine how they like their index.
    if ($context['step'] === 0) {
        $context['sub_template'] = 'create_index';
    }
    // Step 1: insert all the words.
    if ($context['step'] === 1) {
        $context['sub_template'] = 'create_index_progress';
        if ($context['start'] === 0) {
            db_query("\n\t\t\t\tDROP TABLE IF EXISTS {$db_prefix}log_search_words", __FILE__, __LINE__);
            // MySQL users below 4.0 can not use Engine
            if (version_compare('4', preg_replace('~\\-.+?$~', '', min(mysql_get_server_info(), mysql_get_client_info()))) > 0) {
                $schema_type = 'TYPE=';
            } else {
                $schema_type = 'ENGINE=';
            }
            db_query("\n\t\t\t\tCREATE TABLE {$db_prefix}log_search_words (\n\t\t\t\t\tID_WORD " . $index_properties[$context['index_settings']['bytes_per_word']]['column_definition'] . " unsigned NOT NULL default '0',\n\t\t\t\t\tID_MSG int(10) unsigned NOT NULL default '0',\n\t\t\t\t\tPRIMARY KEY (ID_WORD, ID_MSG)\n\t\t\t\t) " . $schema_type . "MyISAM", __FILE__, __LINE__);
            // Temporarily switch back to not using a search index.
            if (!empty($modSettings['search_index']) && $modSettings['search_index'] == 'custom') {
                updateSettings(array('search_index' => ''));
            }
            // Don't let simultanious processes be updating the search index.
            if (!empty($modSettings['search_custom_index_config'])) {
                updateSettings(array('search_custom_index_config' => ''));
            }
        }
        $num_messages = array('done' => 0, 'todo' => 0);
        $request = db_query("\n\t\t\tSELECT ID_MSG >= {$context['start']} AS todo, COUNT(*) AS numMesages\n\t\t\tFROM {$db_prefix}messages\n\t\t\tGROUP BY todo", __FILE__, __LINE__);
        while ($row = mysql_fetch_assoc($request)) {
            $num_messages[empty($row['todo']) ? 'done' : 'todo'] = $row['numMesages'];
        }
        if (empty($num_messages['todo'])) {
            $context['step'] = 2;
            $context['percentage'] = 80;
            $context['start'] = 0;
        } else {
            // Number of seconds before the next step.
            $stop = time() + 3;
            while (time() < $stop) {
                $inserts = '';
                $request = db_query("\n\t\t\t\t\tSELECT ID_MSG, body\n\t\t\t\t\tFROM {$db_prefix}messages\n\t\t\t\t\tWHERE ID_MSG BETWEEN {$context['start']} AND " . ($context['start'] + $messages_per_batch - 1) . "\n\t\t\t\t\tLIMIT {$messages_per_batch}", __FILE__, __LINE__);
                while ($row = mysql_fetch_assoc($request)) {
                    foreach (text2words($row['body'], $context['index_settings']['bytes_per_word'], true) as $ID_WORD) {
                        $inserts .= "({$ID_WORD}, {$row['ID_MSG']}),\n";
                    }
                }
                $num_messages['done'] += mysql_num_rows($request);
                $num_messages['todo'] -= mysql_num_rows($request);
                mysql_free_result($request);
                $context['start'] += $messages_per_batch;
                if (!empty($inserts)) {
                    db_query("\n\t\t\t\t\t\tINSERT IGNORE INTO {$db_prefix}log_search_words\n\t\t\t\t\t\t\t(ID_WORD, ID_MSG)\n\t\t\t\t\t\tVALUES\n\t\t\t\t\t\t\t" . substr($inserts, 0, -2), __FILE__, __LINE__);
                }
                if ($num_messages['todo'] === 0) {
                    $context['step'] = 2;
                    $context['start'] = 0;
                    break;
                } else {
                    updateSettings(array('search_custom_index_resume' => serialize(array_merge($context['index_settings'], array('resume_at' => $context['start'])))));
                }
            }
            // Since there are still two steps to go, 90% is the maximum here.
            $context['percentage'] = round($num_messages['done'] / ($num_messages['done'] + $num_messages['todo']), 3) * 80;
        }
    } elseif ($context['step'] === 2) {
        if ($context['index_settings']['bytes_per_word'] < 4) {
            $context['step'] = 3;
        } else {
            $stop_words = $context['start'] === 0 || empty($modSettings['search_stopwords']) ? array() : explode(',', $modSettings['search_stopwords']);
            $stop = time() + 3;
            $context['sub_template'] = 'create_index_progress';
            $maxMessages = ceil(60 * $modSettings['totalMessages'] / 100);
            while (time() < $stop) {
                $request = db_query("\n\t\t\t\t\tSELECT ID_WORD, count(ID_WORD) AS numWords\n\t\t\t\t\tFROM {$db_prefix}log_search_words\n\t\t\t\t\tWHERE ID_WORD BETWEEN {$context['start']} AND " . ($context['start'] + $index_properties[$context['index_settings']['bytes_per_word']]['step_size'] - 1) . "\n\t\t\t\t\tGROUP BY ID_WORD\n\t\t\t\t\tHAVING numWords > {$maxMessages}", __FILE__, __LINE__);
                while ($row = mysql_fetch_assoc($request)) {
                    $stop_words[] = $row['ID_WORD'];
                }
                mysql_free_result($request);
                updateSettings(array('search_stopwords' => implode(',', $stop_words)));
                if (!empty($stop_words)) {
                    db_query("\n\t\t\t\t\t\tDELETE FROM {$db_prefix}log_search_words\n\t\t\t\t\t\tWHERE ID_WORD in (" . implode(', ', $stop_words) . ')', __FILE__, __LINE__);
                }
                $context['start'] += $index_properties[$context['index_settings']['bytes_per_word']]['step_size'];
                if ($context['start'] > $index_properties[$context['index_settings']['bytes_per_word']]['max_size']) {
                    $context['step'] = 3;
                    break;
                }
            }
            $context['percentage'] = 80 + round($context['start'] / $index_properties[$context['index_settings']['bytes_per_word']]['max_size'], 3) * 20;
        }
    }
    // Step 3: remove words not distinctive enough.
    if ($context['step'] === 3) {
        $context['sub_template'] = 'create_index_done';
        updateSettings(array('search_index' => 'custom', 'search_custom_index_config' => serialize($context['index_settings'])));
        db_query("\n\t\t\tDELETE FROM {$db_prefix}settings\n\t\t\tWHERE variable = 'search_custom_index_resume'", __FILE__, __LINE__);
    }
}