Example #1
0
/**
 * Save a new draft, or update an existing draft.
 */
function saveDraft()
{
    global $smcFunc, $topic, $board, $user_info, $options;
    if (!isset($_REQUEST['draft']) || $user_info['is_guest'] || empty($options['use_drafts'])) {
        return false;
    }
    $msgid = isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0;
    // Clean up what we may or may not have
    $subject = isset($_POST['subject']) ? $_POST['subject'] : '';
    $message = isset($_POST['message']) ? $_POST['message'] : '';
    $icon = isset($_POST['icon']) ? preg_replace('~[\\./\\\\*:"\'<>]~', '', $_POST['icon']) : 'xx';
    // Sanitise what we do have
    $subject = commonAPI::htmltrim(commonAPI::htmlspecialchars($subject));
    $message = commonAPI::htmlspecialchars($message, ENT_QUOTES);
    preparsecode($message);
    if (commonAPI::htmltrim(commonAPI::htmlspecialchars($subject)) === '' && commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['message']), ENT_QUOTES) === '') {
        fatal_lang_error('empty_draft', false);
    }
    // Hrm, so is this a new draft or not?
    if (isset($_REQUEST['draft_id']) && (int) $_REQUEST['draft_id'] > 0 || $msgid) {
        $_REQUEST['draft_id'] = (int) $_REQUEST['draft_id'];
        $id_cond = $msgid ? ' 1=1 ' : ' id_draft = {int:draft} ';
        $id_sel = $msgid ? ' AND id_msg = {int:message} ' : ' AND id_board = {int:board} AND id_topic = {int:topic} ';
        // Does this draft exist?
        smf_db_query('
			UPDATE {db_prefix}drafts
			SET subject = {string:subject},
				body = {string:body},
				updated = {int:post_time},
				icon = {string:post_icon},
				smileys = {int:smileys_enabled},
				is_locked = {int:locked},
				is_sticky = {int:sticky}
			WHERE ' . $id_cond . '
				AND id_member = {int:member}
				' . $id_sel . '
			LIMIT 1', array('draft' => $_REQUEST['draft_id'], 'board' => $board, 'topic' => $topic, 'message' => $msgid, 'member' => $user_info['id'], 'subject' => $subject, 'body' => $message, 'post_time' => time(), 'post_icon' => $icon, 'smileys_enabled' => !isset($_POST['ns']) ? 1 : 0, 'locked' => !empty($_POST['lock_draft']) ? 1 : 0, 'sticky' => isset($_POST['sticky']) ? 1 : 0));
        if (smf_db_affected_rows() != 0) {
            return $_REQUEST['draft_id'];
        }
    }
    smf_db_insert('insert', '{db_prefix}drafts', array('id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'id_member' => 'int', 'subject' => 'string', 'body' => 'string', 'updated' => 'int', 'icon' => 'string', 'smileys' => 'int', 'is_locked' => 'int', 'is_sticky' => 'int'), array($board, $topic, $msgid, $user_info['id'], $subject, $message, time(), $icon, !isset($_POST['ns']) ? 1 : 0, !empty($_POST['lock_draft']) ? 1 : 0, isset($_POST['sticky']) ? 1 : 0), array('id_draft'));
    return smf_db_insert_id('{db_prefix}drafts');
}
Example #2
0
function logSpider()
{
    global $modSettings, $context;
    if (empty($modSettings['spider_mode']) || empty($_SESSION['id_robot'])) {
        return;
    }
    // Attempt to update today's entry.
    if ($modSettings['spider_mode'] == 1) {
        $date = strftime('%Y-%m-%d', forum_time(false));
        smf_db_query('
			UPDATE {db_prefix}log_spider_stats
			SET last_seen = {int:current_time}, page_hits = page_hits + 1
			WHERE id_spider = {int:current_spider}
				AND stat_date = {date:current_date}', array('current_date' => $date, 'current_time' => time(), 'current_spider' => $_SESSION['id_robot']));
        // Nothing updated?
        if (smf_db_affected_rows() == 0) {
            smf_db_insert('ignore', '{db_prefix}log_spider_stats', array('id_spider' => 'int', 'last_seen' => 'int', 'stat_date' => 'date', 'page_hits' => 'int'), array($_SESSION['id_robot'], time(), $date, 1), array('id_spider', 'stat_date'));
        }
    } else {
        if ($modSettings['spider_mode'] > 2) {
            $url = $_GET + array('USER_AGENT' => $_SERVER['HTTP_USER_AGENT']);
            unset($url['sesc'], $url[$context['session_var']]);
            $url = serialize($url);
        } else {
            $url = '';
        }
        smf_db_insert('insert', '{db_prefix}log_spider_hits', array('id_spider' => 'int', 'log_time' => 'int', 'url' => 'string'), array($_SESSION['id_robot'], time(), $url), array());
    }
}
Example #3
0
function ReduceMailQueue($number = false, $override_limit = false, $force_send = false)
{
    global $modSettings, $smcFunc, $sourcedir;
    // Are we intending another script to be sending out the queue?
    if (!empty($modSettings['mail_queue_use_cron']) && empty($force_send)) {
        return false;
    }
    // By default send 5 at once.
    if (!$number) {
        $number = empty($modSettings['mail_quantity']) ? 5 : $modSettings['mail_quantity'];
    }
    // If we came with a timestamp, and that doesn't match the next event, then someone else has beaten us.
    if (isset($_GET['ts']) && $_GET['ts'] != $modSettings['mail_next_send'] && empty($force_send)) {
        return false;
    }
    // By default move the next sending on by 10 seconds, and require an affected row.
    if (!$override_limit) {
        $delay = !empty($modSettings['mail_queue_delay']) ? $modSettings['mail_queue_delay'] : (!empty($modSettings['mail_limit']) && $modSettings['mail_limit'] < 5 ? 10 : 5);
        smf_db_query('
			UPDATE {db_prefix}settings
			SET value = {string:next_mail_send}
			WHERE variable = {string:mail_next_send}
				AND value = {string:last_send}', array('next_mail_send' => time() + $delay, 'mail_next_send' => 'mail_next_send', 'last_send' => $modSettings['mail_next_send']));
        if (smf_db_affected_rows() == 0) {
            return false;
        }
        $modSettings['mail_next_send'] = time() + $delay;
    }
    // If we're not overriding how many are we allow to send?
    if (!$override_limit && !empty($modSettings['mail_limit'])) {
        list($mt, $mn) = @explode('|', $modSettings['mail_recent']);
        // Nothing worth noting...
        if (empty($mn) || $mt < time() - 60) {
            $mt = time();
            $mn = $number;
        } elseif ($mn < $modSettings['mail_limit']) {
            $mn += $number;
        } else {
            return false;
        }
        // Reflect that we're about to send some, do it now to be safe.
        updateSettings(array('mail_recent' => $mt . '|' . $mn));
    }
    // Now we know how many we're sending, let's send them.
    $request = smf_db_query('
		SELECT /*!40001 SQL_NO_CACHE */ id_mail, recipient, body, subject, headers, send_html
		FROM {db_prefix}mail_queue
		ORDER BY priority ASC, id_mail ASC
		LIMIT ' . $number, array());
    $ids = array();
    $emails = array();
    while ($row = mysql_fetch_assoc($request)) {
        // We want to delete these from the database ASAP, so just get the data and go.
        $ids[] = $row['id_mail'];
        $emails[] = array('to' => $row['recipient'], 'body' => $row['body'], 'subject' => $row['subject'], 'headers' => $row['headers'], 'send_html' => $row['send_html']);
    }
    mysql_free_result($request);
    // Delete, delete, delete!!!
    if (!empty($ids)) {
        smf_db_query('
			DELETE FROM {db_prefix}mail_queue
			WHERE id_mail IN ({array_int:mail_list})', array('mail_list' => $ids));
    }
    // Don't believe we have any left?
    if (count($ids) < $number) {
        // Only update the setting if no-one else has beaten us to it.
        smf_db_query('
			UPDATE {db_prefix}settings
			SET value = {string:no_send}
			WHERE variable = {string:mail_next_send}
				AND value = {string:last_mail_send}', array('no_send' => '0', 'mail_next_send' => 'mail_next_send', 'last_mail_send' => $modSettings['mail_next_send']));
    }
    if (empty($ids)) {
        return false;
    }
    if (!empty($modSettings['mail_type']) && $modSettings['smtp_host'] != '') {
        require_once $sourcedir . '/lib/Subs-Post.php';
    }
    // Send each email, yea!
    $failed_emails = array();
    foreach ($emails as $key => $email) {
        if (empty($modSettings['mail_type']) || $modSettings['smtp_host'] == '') {
            $email['subject'] = strtr($email['subject'], array("\r" => '', "\n" => ''));
            if (!empty($modSettings['mail_strip_carriage'])) {
                $email['body'] = strtr($email['body'], array("\r" => ''));
                $email['headers'] = strtr($email['headers'], array("\r" => ''));
            }
            // No point logging a specific error here, as we have no language. PHP error is helpful anyway...
            $result = mail(strtr($email['to'], array("\r" => '', "\n" => '')), $email['subject'], $email['body'], $email['headers']);
            // Try to stop a timeout, this would be bad...
            @set_time_limit(300);
            if (function_exists('apache_reset_timeout')) {
                @apache_reset_timeout();
            }
        } else {
            $result = smtp_mail(array($email['to']), $email['subject'], $email['body'], $email['send_html'] ? $email['headers'] : 'Mime-Version: 1.0' . "\r\n" . $email['headers']);
        }
        // Hopefully it sent?
        if (!$result) {
            $failed_emails[] = array($email['to'], $email['body'], $email['subject'], $email['headers'], $email['send_html']);
        }
    }
    // Any emails that didn't send?
    if (!empty($failed_emails)) {
        // Update the failed attempts check.
        smf_db_insert('replace', '{db_prefix}settings', array('variable' => 'string', 'value' => 'string'), array('mail_failed_attempts', empty($modSettings['mail_failed_attempts']) ? 1 : ++$modSettings['mail_failed_attempts']), array('variable'));
        // If we have failed to many times, tell mail to wait a bit and try again.
        if ($modSettings['mail_failed_attempts'] > 5) {
            smf_db_query('
				UPDATE {db_prefix}settings
				SET value = {string:mail_next_send}
				WHERE variable = {string:next_mail_send}
					AND value = {string:last_send}', array('next_mail_send' => time() + 60, 'mail_next_send' => 'mail_next_send', 'last_send' => $modSettings['mail_next_send']));
        }
        // Add our email back to the queue, manually.
        smf_db_insert('insert', '{db_prefix}mail_queue', array('recipient' => 'string', 'body' => 'string', 'subject' => 'string', 'headers' => 'string', 'send_html' => 'string'), $failed_emails, array('id_mail'));
        return false;
    } elseif (!empty($modSettings['mail_failed_attempts'])) {
        smf_db_query('
			UPDATE {db_prefix}settings
			SET value = {string:zero}
			WHERE variable = {string:mail_failed_attempts}', array('zero' => '0', 'mail_failed_attempts' => 'mail_failed_attempts'));
    }
    // Had something to send...
    return true;
}
Example #4
0
function reattributePosts($memID, $email = false, $membername = false, $post_count = false)
{
    global $smcFunc;
    // Firstly, if email and username aren't passed find out the members email address and name.
    if ($email === false && $membername === false) {
        $request = smf_db_query('
			SELECT email_address, member_name
			FROM {db_prefix}members
			WHERE id_member = {int:memID}
			LIMIT 1', array('memID' => $memID));
        list($email, $membername) = mysql_fetch_row($request);
        mysql_free_result($request);
    }
    // If they want the post count restored then we need to do some research.
    if ($post_count) {
        $request = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board AND b.count_posts = {int:count_posts})
			WHERE m.id_member = {int:guest_id}
				AND m.approved = {int:is_approved}
				AND m.icon != {string:recycled_icon}' . (empty($email) ? '' : '
				AND m.poster_email = {string:email_address}') . (empty($membername) ? '' : '
				AND m.poster_name = {string:member_name}'), array('count_posts' => 0, 'guest_id' => 0, 'email_address' => $email, 'member_name' => $membername, 'is_approved' => 1, 'recycled_icon' => 'recycled'));
        list($messageCount) = mysql_fetch_row($request);
        mysql_free_result($request);
        updateMemberData($memID, array('posts' => 'posts + ' . $messageCount));
    }
    $query_parts = array();
    if (!empty($email)) {
        $query_parts[] = 'poster_email = {string:email_address}';
    }
    if (!empty($membername)) {
        $query_parts[] = 'poster_name = {string:member_name}';
    }
    $query = implode(' AND ', $query_parts);
    // Finally, update the posts themselves!
    smf_db_query('
		UPDATE {db_prefix}messages
		SET id_member = {int:memID}
		WHERE ' . $query, array('memID' => $memID, 'email_address' => $email, 'member_name' => $membername));
    return smf_db_affected_rows();
}
Example #5
0
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;
}
Example #6
0
function Post2()
{
    global $board, $topic, $txt, $modSettings, $sourcedir, $context;
    global $user_info, $board_info, $options, $backend_subdir;
    /*  todo: drafts -> plugin
    	if(in_array('dr', $context['admin_features'])) {
    		require_once($sourcedir . '/lib/Subs-Drafts.php');
    		enqueueThemeScript('drafts', 'scripts/drafts.js', true);
    		$context['have_drafts'] = true;
    	}
    	else*/
    $context['have_drafts'] = false;
    $context['auto_preview'] = isset($_REQUEST['autopreview']) && $_REQUEST['autopreview'] ? 1 : 0;
    $context['need_synhlt'] = true;
    $context['no_astream'] = isset($_REQUEST['noactivity']) && (int) $_REQUEST['noactivity'] == 1;
    $context['can_tag_users'] = allowedTo('tag_users');
    // Sneaking off, are we?
    if (empty($_POST) && empty($topic)) {
        redirectexit('action=post;board=' . $board . '.0');
    } elseif (empty($_POST) && !empty($topic)) {
        redirectexit('action=post;topic=' . $topic . '.0');
    }
    // No need!
    $context['robot_no_index'] = true;
    // If we came from WYSIWYG then turn it back into BBC regardless.
    if (!empty($_REQUEST['message_mode']) && isset($_REQUEST['message'])) {
        require_once $sourcedir . '/lib/Subs-Editor.php';
        $_REQUEST['message'] = html_to_bbc($_REQUEST['message']);
        // We need to unhtml it now as it gets done shortly.
        $_REQUEST['message'] = un_htmlspecialchars($_REQUEST['message']);
        // We need this for everything else.
        $_POST['message'] = $_REQUEST['message'];
    }
    // Previewing? Go back to start.
    if (isset($_REQUEST['preview'])) {
        return Post();
    }
    // Prevent double submission of this form.
    checkSubmitOnce('check');
    // No errors as yet.
    $post_errors = array();
    // If the session has timed out, let the user re-submit their form.
    if (checkSession('post', '', false) != '') {
        $post_errors[] = 'session_timeout';
    }
    // Wrong verification code?
    if (!$user_info['is_admin'] && !$user_info['is_mod'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1)) {
        require_once $sourcedir . '/lib/Subs-Editor.php';
        $verificationOptions = array('id' => 'post', 'skip_template' => true);
        $context['require_verification'] = create_control_verification($verificationOptions, true);
        if (is_array($context['require_verification'])) {
            $post_errors = array_merge($post_errors, $context['require_verification']);
        }
    }
    require_once $sourcedir . '/lib/Subs-Post.php';
    loadLanguage('Post');
    // If this isn't a new topic load the topic info that we need.
    if (!empty($topic)) {
        $request = smf_db_query('
			SELECT t.locked, t.is_sticky, t.id_poll, t.approved, t.id_first_msg, t.id_last_msg, t.id_member_started, t.id_member_updated,
				t.id_board, t.id_prefix, t.id_layout, t.num_replies, b.automerge, ba.id_topic AS banned_from_topic
			FROM {db_prefix}topics AS t
			LEFT JOIN {db_prefix}boards AS b on b.id_board = t.id_board 
			LEFT JOIN {db_prefix}topicbans AS ba ON (ba.id_topic = {int:current_topic} AND ba.id_member = {int:current_member})
			WHERE t.id_topic = {int:current_topic}
			LIMIT 1', array('current_topic' => $topic, 'current_member' => $user_info['id']));
        $topic_info = mysql_fetch_assoc($request);
        mysql_free_result($request);
        // Though the topic should be there, it might have vanished.
        if (!is_array($topic_info)) {
            fatal_lang_error('topic_doesnt_exist');
        }
        // Did this topic suddenly move? Just checking...
        if ($topic_info['id_board'] != $board) {
            fatal_lang_error('not_a_topic');
        }
        if ($topic_info['banned_from_topic'] != 0 && !$user_info['is_admin'] && !allowedTo('moderate_board') && !allowedTo('moderate_forum')) {
            fatal_lang_error('banned_from_topic');
        }
    }
    // Replying to a topic?
    if (!empty($topic) && !isset($_REQUEST['msg'])) {
        // Don't allow a post if it's locked.
        if ($topic_info['locked'] != 0 && !allowedTo('moderate_board')) {
            fatal_lang_error('topic_locked', false);
        }
        // Sorry, multiple polls aren't allowed... yet.  You should stop giving me ideas :P.
        if (isset($_REQUEST['poll']) && $topic_info['id_poll'] > 0) {
            unset($_REQUEST['poll']);
        }
        // Do the permissions and approval stuff...
        $becomesApproved = true;
        if ($topic_info['id_member_started'] != $user_info['id']) {
            if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_any') && !allowedTo('post_reply_any')) {
                $becomesApproved = false;
            } else {
                isAllowedTo('post_reply_any');
            }
        } elseif (!allowedTo('post_reply_any')) {
            if ($modSettings['postmod_active'] && allowedTo('post_unapproved_replies_own') && !allowedTo('post_reply_own')) {
                $becomesApproved = false;
            } else {
                isAllowedTo('post_reply_own');
            }
        }
        if (isset($_POST['lock'])) {
            // Nothing is changed to the lock.
            if (empty($topic_info['locked']) && empty($_POST['lock']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                // You cannot override a moderator lock.
                if ($topic_info['locked'] == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        // So you wanna (un)sticky this...let's see.
        if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky'))) {
            unset($_POST['sticky']);
        }
        // If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
        if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg']) {
            $_REQUEST['preview'] = true;
            return Post();
        }
        // drafts
        if (isset($_POST['lock'])) {
            $_POST['lock_draft'] = !empty($_POST['lock']) ? 1 : 0;
        } else {
            $_POST['lock_draft'] = !empty($topic_info['locked']) ? 1 : 0;
        }
        // it's not, grab from topic's current info
        if ($context['have_drafts']) {
            $draft = saveDraft();
            if (!empty($draft) && !in_array('session_timeout', $post_errors)) {
                if (isset($_REQUEST['xml'])) {
                    draftXmlReturn($draft);
                }
                EoS_Smarty::loadTemplate('post/draft_saved');
                $context['page_title'] = $txt['draft_saved_short'];
                return;
            }
        }
        $posterIsGuest = $user_info['is_guest'];
    } elseif (empty($topic)) {
        // Now don't be silly, new topics will get their own id_msg soon enough.
        unset($_REQUEST['msg'], $_POST['msg'], $_GET['msg']);
        // Do like, the permissions, for safety and stuff...
        $becomesApproved = true;
        if ($modSettings['postmod_active'] && !allowedTo('post_new') && allowedTo('post_unapproved_topics')) {
            $becomesApproved = false;
        } else {
            isAllowedTo('post_new');
        }
        if (isset($_POST['lock'])) {
            // New topics are by default not locked.
            if (empty($_POST['lock'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own'))) {
                unset($_POST['lock']);
            } else {
                $_POST['lock'] = allowedTo('lock_any') ? 1 : 2;
            }
        }
        if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky'))) {
            unset($_POST['sticky']);
        }
        $posterIsGuest = $user_info['is_guest'];
        // Are we saving a draft? If so, hand over control to the draft code -- except, in the case of a session failure
        $_POST['lock_draft'] = !empty($_POST['lock']) ? 1 : 0;
        if ($context['have_drafts']) {
            $draft = saveDraft();
            if (!empty($draft) && !in_array('session_timeout', $post_errors)) {
                if (isset($_REQUEST['xml'])) {
                    draftXmlReturn($draft);
                }
                EoS_Smarty::loadTemplate('post/draft_saved');
                $context['page_title'] = $txt['draft_saved_short'];
                return;
            }
        }
    } elseif (isset($_REQUEST['msg']) && !empty($topic)) {
        $_REQUEST['msg'] = (int) $_REQUEST['msg'];
        $request = smf_db_query('
			SELECT id_member, poster_name, poster_email, poster_time, approved, locked
			FROM {db_prefix}messages
			WHERE id_msg = {int:id_msg}
			LIMIT 1', array('id_msg' => $_REQUEST['msg']));
        if (mysql_num_rows($request) == 0) {
            fatal_lang_error('cant_find_messages', false);
        }
        $row = mysql_fetch_assoc($request);
        $msg_owner = $row['id_member'];
        mysql_free_result($request);
        if (!empty($topic_info['locked']) && !allowedTo('moderate_board')) {
            fatal_lang_error('topic_locked', false);
        }
        if (isset($_POST['lock'])) {
            // Nothing changes to the lock status.
            if (empty($_POST['lock']) && empty($topic_info['locked']) || !empty($_POST['lock']) && !empty($topic_info['locked'])) {
                unset($_POST['lock']);
            } elseif (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $topic_info['id_member_started']) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                // You're not allowed to break a moderator's lock.
                if ($topic_info['locked'] == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        // Change the sticky status of this topic?
        if (isset($_POST['sticky']) && (!allowedTo('make_sticky') || $_POST['sticky'] == $topic_info['is_sticky'])) {
            unset($_POST['sticky']);
        }
        if ($row['locked'] && !(allowedTo('moderate_board') || allowedTo('moderate_forum'))) {
            fatal_lang_error('modify_message_locked', false);
        }
        if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) {
            if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
                fatal_lang_error('modify_post_time_passed', false);
            } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) {
                isAllowedTo('modify_replies');
            } else {
                isAllowedTo('modify_own');
            }
        } elseif ($topic_info['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) {
            isAllowedTo('modify_replies');
            // If you're modifying a reply, I say it better be logged...
            $moderationAction = true;
        } else {
            isAllowedTo('modify_any');
            // Log it, assuming you're not modifying your own post.
            if ($row['id_member'] != $user_info['id']) {
                $moderationAction = true;
            }
        }
        $posterIsGuest = empty($row['id_member']);
        // Can they approve it?
        $can_approve = allowedTo('approve_posts');
        $becomesApproved = $modSettings['postmod_active'] ? $can_approve && !$row['approved'] ? !empty($_REQUEST['approve']) ? 1 : 0 : $row['approved'] : 1;
        $approve_has_changed = $row['approved'] != $becomesApproved;
        if (!allowedTo('moderate_forum') || !$posterIsGuest) {
            $_POST['guestname'] = $row['poster_name'];
            $_POST['email'] = $row['poster_email'];
        }
        if ($context['have_drafts']) {
            $draft = saveDraft();
            if (!empty($draft) && !in_array('session_timeout', $post_errors)) {
                if (isset($_REQUEST['xml'])) {
                    draftXmlReturn($draft);
                }
                EoS_Smarty::loadTemplate('post/draft_saved');
                $context['page_title'] = $txt['draft_saved_short'];
                return;
            }
        }
    }
    // If the poster is a guest evaluate the legality of name and email.
    if ($posterIsGuest) {
        $_POST['guestname'] = !isset($_POST['guestname']) ? '' : trim($_POST['guestname']);
        $_POST['email'] = !isset($_POST['email']) ? '' : trim($_POST['email']);
        if ($_POST['guestname'] == '' || $_POST['guestname'] == '_') {
            $post_errors[] = 'no_name';
        }
        if (commonAPI::strlen($_POST['guestname']) > 25) {
            $post_errors[] = 'long_name';
        }
        if (empty($modSettings['guest_post_no_email'])) {
            // Only check if they changed it!
            if (!isset($row) || $row['poster_email'] != $_POST['email']) {
                if (!allowedTo('moderate_forum') && (!isset($_POST['email']) || $_POST['email'] == '')) {
                    $post_errors[] = 'no_email';
                }
                if (!allowedTo('moderate_forum') && preg_match('~^[0-9A-Za-z=_+\\-/][0-9A-Za-z=_\'+\\-/\\.]*@[\\w\\-]+(\\.[\\w\\-]+)*(\\.[\\w]{2,6})$~', $_POST['email']) == 0) {
                    $post_errors[] = 'bad_email';
                }
            }
            // Now make sure this email address is not banned from posting.
            isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
        }
        // In case they are making multiple posts this visit, help them along by storing their name.
        if (empty($post_errors)) {
            $_SESSION['guest_name'] = $_POST['guestname'];
            $_SESSION['guest_email'] = $_POST['email'];
        }
    }
    // Check the subject and message.
    if (!isset($_POST['subject']) || commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['subject'])) === '') {
        $post_errors[] = 'no_subject';
    }
    if (!isset($_POST['message']) || commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['message']), ENT_QUOTES) === '') {
        $post_errors[] = 'no_message';
    } elseif (!empty($modSettings['max_messageLength']) && commonAPI::strlen($_POST['message']) > $modSettings['max_messageLength']) {
        $post_errors[] = 'long_message';
    } else {
        // Prepare the message a bit for some additional testing.
        $_POST['message'] = commonAPI::htmlspecialchars($_POST['message'], ENT_QUOTES);
        // Preparse code. (Zef)
        if ($user_info['is_guest']) {
            $user_info['name'] = $_POST['guestname'];
        }
        preparsecode($_POST['message']);
        // Let's see if there's still some content left without the tags.
        if (commonAPI::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($_POST['message'], '[html]') === false)) {
            $post_errors[] = 'no_message';
        }
    }
    if (isset($_POST['calendar']) && !isset($_REQUEST['deleteevent']) && commonAPI::htmltrim($_POST['evtitle']) === '') {
        $post_errors[] = 'no_event';
    }
    // You are not!
    if (isset($_POST['message']) && strtolower($_POST['message']) == 'i am the administrator.' && !$user_info['is_admin']) {
        fatal_error('Knave! Masquerader! Charlatan!', false);
    }
    // Validate the poll...
    if (isset($_REQUEST['poll']) && $modSettings['pollMode'] == '1') {
        if (!empty($topic) && !isset($_REQUEST['msg'])) {
            fatal_lang_error('no_access', false);
        }
        // This is a new topic... so it's a new poll.
        if (empty($topic)) {
            isAllowedTo('poll_post');
        } elseif ($user_info['id'] == $topic_info['id_member_started'] && !allowedTo('poll_add_any')) {
            isAllowedTo('poll_add_own');
        } else {
            isAllowedTo('poll_add_any');
        }
        if (!isset($_POST['question']) || trim($_POST['question']) == '') {
            $post_errors[] = 'no_question';
        }
        $_POST['options'] = empty($_POST['options']) ? array() : htmltrim__recursive($_POST['options']);
        // Get rid of empty ones.
        foreach ($_POST['options'] as $k => $option) {
            if ($option == '') {
                unset($_POST['options'][$k], $_POST['options'][$k]);
            }
        }
        // What are you going to vote between with one choice?!?
        if (count($_POST['options']) < 2) {
            $post_errors[] = 'poll_few';
        }
    }
    if ($posterIsGuest) {
        // If user is a guest, make sure the chosen name isn't taken.
        require_once $sourcedir . '/lib/Subs-Members.php';
        if (isReservedName($_POST['guestname'], 0, true, false) && (!isset($row['poster_name']) || $_POST['guestname'] != $row['poster_name'])) {
            $post_errors[] = 'bad_name';
        }
    } elseif (!isset($_REQUEST['msg'])) {
        $_POST['guestname'] = $user_info['username'];
        $_POST['email'] = $user_info['email'];
    }
    // Any mistakes?
    if (!empty($post_errors)) {
        loadLanguage('Errors');
        // Previewing.
        $_REQUEST['preview'] = true;
        $context['post_error'] = array('messages' => array());
        foreach ($post_errors as $post_error) {
            $context['post_error'][$post_error] = true;
            if ($post_error == 'long_message') {
                $txt['error_' . $post_error] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
            }
            $context['post_error']['messages'][] = $txt['error_' . $post_error];
        }
        return Post();
    }
    // Make sure the user isn't spamming the board.
    if (!isset($_REQUEST['msg'])) {
        spamProtection('post');
    }
    // At about this point, we're posting and that's that.
    ignore_user_abort(true);
    @set_time_limit(300);
    // Add special html entities to the subject, name, and email.
    $_POST['subject'] = strtr(commonAPI::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
    $_POST['guestname'] = htmlspecialchars($_POST['guestname']);
    $_POST['email'] = htmlspecialchars($_POST['email']);
    // At this point, we want to make sure the subject isn't too long.
    if (commonAPI::strlen($_POST['subject']) > 100) {
        $_POST['subject'] = commonAPI::substr($_POST['subject'], 0, 100);
    }
    // Make the poll...
    if (isset($_REQUEST['poll'])) {
        // Make sure that the user has not entered a ridiculous number of options..
        if (empty($_POST['poll_max_votes']) || $_POST['poll_max_votes'] <= 0) {
            $_POST['poll_max_votes'] = 1;
        } elseif ($_POST['poll_max_votes'] > count($_POST['options'])) {
            $_POST['poll_max_votes'] = count($_POST['options']);
        } else {
            $_POST['poll_max_votes'] = (int) $_POST['poll_max_votes'];
        }
        $_POST['poll_expire'] = (int) $_POST['poll_expire'];
        $_POST['poll_expire'] = $_POST['poll_expire'] > 9999 ? 9999 : ($_POST['poll_expire'] < 0 ? 0 : $_POST['poll_expire']);
        // Just set it to zero if it's not there..
        if (!isset($_POST['poll_hide'])) {
            $_POST['poll_hide'] = 0;
        } else {
            $_POST['poll_hide'] = (int) $_POST['poll_hide'];
        }
        $_POST['poll_change_vote'] = isset($_POST['poll_change_vote']) ? 1 : 0;
        $_POST['poll_guest_vote'] = isset($_POST['poll_guest_vote']) ? 1 : 0;
        // Make sure guests are actually allowed to vote generally.
        if ($_POST['poll_guest_vote']) {
            require_once $sourcedir . '/lib/Subs-Members.php';
            $allowedVoteGroups = groupsAllowedTo('poll_vote', $board);
            if (!in_array(-1, $allowedVoteGroups['allowed'])) {
                $_POST['poll_guest_vote'] = 0;
            }
        }
        // If the user tries to set the poll too far in advance, don't let them.
        if (!empty($_POST['poll_expire']) && $_POST['poll_expire'] < 1) {
            fatal_lang_error('poll_range_error', false);
        } elseif (empty($_POST['poll_expire']) && $_POST['poll_hide'] == 2) {
            $_POST['poll_hide'] = 1;
        }
        // Clean up the question and answers.
        $_POST['question'] = htmlspecialchars($_POST['question']);
        $_POST['question'] = commonAPI::truncate($_POST['question'], 255);
        $_POST['question'] = preg_replace('~&amp;#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', $_POST['question']);
        $_POST['options'] = htmlspecialchars__recursive($_POST['options']);
    }
    // Check if they are trying to delete any current attachments....
    if (isset($_REQUEST['msg'], $_POST['attach_del']) && (allowedTo('post_attachment') || $modSettings['postmod_active'] && allowedTo('post_unapproved_attachments'))) {
        $del_temp = array();
        foreach ($_POST['attach_del'] as $i => $dummy) {
            $del_temp[$i] = (int) $dummy;
        }
        require_once $sourcedir . '/lib/Subs-ManageAttachments.php';
        $attachmentQuery = array('attachment_type' => 0, 'id_msg' => (int) $_REQUEST['msg'], 'not_id_attach' => $del_temp);
        removeAttachments($attachmentQuery);
    }
    // ...or attach a new file...
    if (isset($_FILES['attachment']['name']) || !empty($_SESSION['temp_attachments']) && empty($_POST['from_qr'])) {
        // Verify they can post them!
        if (!$modSettings['postmod_active'] || !allowedTo('post_unapproved_attachments')) {
            isAllowedTo('post_attachment');
        }
        // Make sure we're uploading to the right place.
        if (!empty($modSettings['currentAttachmentUploadDir'])) {
            if (!is_array($modSettings['attachmentUploadDir'])) {
                $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']);
            }
            // The current directory, of course!
            $current_attach_dir = $modSettings['attachmentUploadDir'][$modSettings['currentAttachmentUploadDir']];
        } else {
            $current_attach_dir = $modSettings['attachmentUploadDir'];
        }
        // If this isn't a new post, check the current attachments.
        if (isset($_REQUEST['msg'])) {
            $request = smf_db_query('
				SELECT COUNT(*), SUM(size)
				FROM {db_prefix}attachments
				WHERE id_msg = {int:id_msg}
					AND attachment_type = {int:attachment_type}', array('id_msg' => (int) $_REQUEST['msg'], 'attachment_type' => 0));
            list($quantity, $total_size) = mysql_fetch_row($request);
            mysql_free_result($request);
        } else {
            $quantity = 0;
            $total_size = 0;
        }
        if (!empty($_SESSION['temp_attachments'])) {
            foreach ($_SESSION['temp_attachments'] as $attachID => $name) {
                if (preg_match('~^post_tmp_' . $user_info['id'] . '_\\d+$~', $attachID) == 0) {
                    continue;
                }
                if (!empty($_POST['attach_del']) && !in_array($attachID, $_POST['attach_del'])) {
                    unset($_SESSION['temp_attachments'][$attachID]);
                    @unlink($current_attach_dir . '/' . $attachID);
                    continue;
                }
                $_FILES['attachment']['tmp_name'][] = $attachID;
                $_FILES['attachment']['name'][] = $name;
                $_FILES['attachment']['size'][] = filesize($current_attach_dir . '/' . $attachID);
                list($_FILES['attachment']['width'][], $_FILES['attachment']['height'][]) = @getimagesize($current_attach_dir . '/' . $attachID);
                unset($_SESSION['temp_attachments'][$attachID]);
            }
        }
        if (!isset($_FILES['attachment']['name'])) {
            $_FILES['attachment']['tmp_name'] = array();
        }
        $attachIDs = array();
        foreach ($_FILES['attachment']['tmp_name'] as $n => $dummy) {
            if ($_FILES['attachment']['name'][$n] == '') {
                continue;
            }
            // Have we reached the maximum number of files we are allowed?
            $quantity++;
            if (!empty($modSettings['attachmentNumPerPostLimit']) && $quantity > $modSettings['attachmentNumPerPostLimit']) {
                checkSubmitOnce('free');
                fatal_lang_error('attachments_limit_per_post', false, array($modSettings['attachmentNumPerPostLimit']));
            }
            // Check the total upload size for this post...
            $total_size += $_FILES['attachment']['size'][$n];
            if (!empty($modSettings['attachmentPostLimit']) && $total_size > $modSettings['attachmentPostLimit'] * 1024) {
                checkSubmitOnce('free');
                fatal_lang_error('file_too_big', false, array($modSettings['attachmentPostLimit']));
            }
            $attachmentOptions = array('post' => isset($_REQUEST['msg']) ? $_REQUEST['msg'] : 0, 'poster' => $user_info['id'], 'name' => $_FILES['attachment']['name'][$n], 'tmp_name' => $_FILES['attachment']['tmp_name'][$n], 'size' => $_FILES['attachment']['size'][$n], 'approved' => !$modSettings['postmod_active'] || allowedTo('post_attachment'));
            if (createAttachment($attachmentOptions)) {
                $attachIDs[] = $attachmentOptions['id'];
                if (!empty($attachmentOptions['thumb'])) {
                    $attachIDs[] = $attachmentOptions['thumb'];
                }
            } else {
                if (in_array('could_not_upload', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('attach_timeout', 'critical');
                }
                if (in_array('too_large', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('file_too_big', false, array($modSettings['attachmentSizeLimit']));
                }
                if (in_array('bad_extension', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_error($attachmentOptions['name'] . '.<br />' . $txt['cant_upload_type'] . ' ' . $modSettings['attachmentExtensions'] . '.', false);
                }
                if (in_array('directory_full', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('ran_out_of_space', 'critical');
                }
                if (in_array('bad_filename', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_error(basename($attachmentOptions['name']) . '.<br />' . $txt['restricted_filename'] . '.', 'critical');
                }
                if (in_array('taken_filename', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('filename_exists');
                }
                if (in_array('bad_attachment', $attachmentOptions['errors'])) {
                    checkSubmitOnce('free');
                    fatal_lang_error('bad_attachment');
                }
            }
        }
    }
    // Make the poll...
    if (isset($_REQUEST['poll'])) {
        // Create the poll.
        smf_db_insert('', '{db_prefix}polls', array('question' => 'string-255', 'hide_results' => 'int', 'max_votes' => 'int', 'expire_time' => 'int', 'id_member' => 'int', 'poster_name' => 'string-255', 'change_vote' => 'int', 'guest_vote' => 'int'), array($_POST['question'], $_POST['poll_hide'], $_POST['poll_max_votes'], empty($_POST['poll_expire']) ? 0 : time() + $_POST['poll_expire'] * 3600 * 24, $user_info['id'], $_POST['guestname'], $_POST['poll_change_vote'], $_POST['poll_guest_vote']), array('id_poll'));
        $id_poll = smf_db_insert_id('{db_prefix}polls', 'id_poll');
        // Create each answer choice.
        $i = 0;
        $pollOptions = array();
        foreach ($_POST['options'] as $option) {
            $pollOptions[] = array($id_poll, $i, $option);
            $i++;
        }
        smf_db_insert('insert', '{db_prefix}poll_choices', array('id_poll' => 'int', 'id_choice' => 'int', 'label' => 'string-255'), $pollOptions, array('id_poll', 'id_choice'));
    } else {
        $id_poll = 0;
    }
    // Creating a new topic?
    $newTopic = empty($_REQUEST['msg']) && empty($topic);
    $_POST['icon'] = !empty($attachIDs) && $_POST['icon'] == 'xx' ? 'clip' : $_POST['icon'];
    if (empty($attachIDs) && $_POST['icon'] == 'clip') {
        $_POST['icon'] = 'xx';
    }
    // Collect all parameters for the creation or modification of a post.
    $msgOptions = array('id' => empty($_REQUEST['msg']) ? 0 : (int) $_REQUEST['msg'], 'subject' => $_POST['subject'], 'body' => $_POST['message'], 'icon' => preg_replace('~[\\./\\\\*:"\'<>]~', '', $_POST['icon']), 'smileys_enabled' => !isset($_POST['ns']), 'attachments' => empty($attachIDs) ? array() : $attachIDs, 'approved' => $becomesApproved, 'id_owner' => isset($msg_owner) ? $msg_owner : 0, 'locked' => !empty($_POST['lock_message']) && (allowedTo('moderate_board') || allowedTo('moderate_forum')));
    $topicOptions = array('id' => empty($topic) ? 0 : $topic, 'board' => $board, 'poll' => isset($_REQUEST['poll']) ? $id_poll : null, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => true, 'topic_prefix' => isset($_REQUEST['topic_prefix']) ? intval($_REQUEST['topic_prefix']) : null, 'topic_layout' => (isset($_REQUEST['stickfirst']) && $_REQUEST['stickfirst'] ? 0x80 : 0) | (isset($_REQUEST['firstlayout']) && $_REQUEST['firstlayout'] ? $_REQUEST['firstlayout'] : 0), 'automerge' => !empty($topic) ? $topic_info['automerge'] : 0, 'id_first_msg' => !empty($topic) ? $topic_info['id_first_msg'] : 0, 'id_last_msg' => !empty($topic) ? $topic_info['id_last_msg'] : 0, 'id_member_started' => !empty($topic) ? $topic_info['id_member_started'] : 0, 'id_member_updated' => !empty($topic) ? $topic_info['id_member_updated'] : 0, 'is_approved' => !$modSettings['postmod_active'] || empty($topic) || !empty($board_info['cur_topic_approved']), 'num_replies' => !empty($topic) ? $topic_info['num_replies'] : 0);
    $posterOptions = array('id' => $user_info['id'], 'name' => $_POST['guestname'], 'email' => $_POST['email'], 'update_post_count' => !$user_info['is_guest'] && !isset($_REQUEST['msg']) && $board_info['posts_count']);
    // This is an already existing message. Edit it.
    if (!empty($_REQUEST['msg'])) {
        // Have admins allowed people to hide their screwups?
        if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member']) {
            $msgOptions['modify_time'] = time();
            $msgOptions['modify_name'] = $user_info['name'];
        }
        // This will save some time...
        if (empty($approve_has_changed)) {
            unset($msgOptions['approved']);
        }
        modifyPost($msgOptions, $topicOptions, $posterOptions);
    } else {
        //handleUserTags($msgOptions['body']);
        createPost($msgOptions, $topicOptions, $posterOptions);
        if (isset($topicOptions['id'])) {
            $topic = $topicOptions['id'];
        }
        if (isset($_REQUEST['tags']) && !isset($_REQUEST['num_replies'])) {
            global $user_info;
            $result = smf_db_query('
              SELECT COUNT(*) as total
              FROM {db_prefix}tags_log
              WHERE ID_TOPIC = {int:id_topic}', array('id_topic' => $topic));
            $row = mysql_fetch_assoc($result);
            $nr_tags = $row['total'];
            mysql_free_result($result);
            // Check Tag restrictions
            $tags = explode(',', htmlspecialchars($_REQUEST['tags'], ENT_QUOTES));
            if ($nr_tags < $modSettings['smftags_set_maxtags']) {
                $count = 0;
                foreach ($tags as $tag) {
                    $tag = trim($tag);
                    if (empty($tag)) {
                        continue;
                    }
                    if ($count >= $modSettings['smftags_set_maxtags']) {
                        continue;
                    }
                    if (strlen($tag) < $modSettings['smftags_set_mintaglength']) {
                        continue;
                    }
                    if (strlen($tag) > $modSettings['smftags_set_maxtaglength']) {
                        continue;
                    }
                    $result = smf_db_query('
                      SELECT ID_TAG
                      FROM {db_prefix}tags
                      WHERE tag = {string:tag}', array('tag' => $tag));
                    if (0 == smf_db_affected_rows()) {
                        smf_db_query('INSERT INTO {db_prefix}tags
                          (tag, approved)
                          VALUES ({string:tag}, 1)', array('tag' => $tag));
                        $ID_TAG = smf_db_insert_id('{db_prefix}tags', 'ID_TAG');
                        smf_db_query('INSERT INTO {db_prefix}tags_log
                            (ID_TAG, ID_TOPIC, ID_MEMBER)
                            VALUES ({int:id_tag}, {int:topic}, {int:userid})', array('id_tag' => $ID_TAG, 'topic' => $topic, 'userid' => $user_info['id']));
                        $count++;
                    } else {
                        $row = mysql_fetch_assoc($result);
                        $ID_TAG = $row['ID_TAG'];
                        $result2 = smf_db_query('
                          SELECT ID FROM {db_prefix}tags_log
                          WHERE ID_TAG = {int:id_tag} AND ID_TOPIC = {int:topic}', array('id_tag' => $ID_TAG, 'topic' => $topic));
                        if (smf_db_affected_rows() != 0) {
                            continue;
                        }
                        mysql_free_result($result2);
                        smf_db_query('INSERT INTO {db_prefix}tags_log
                            (ID_TAG, ID_TOPIC, ID_MEMBER)
                            VALUES ({int:id_tag}, {int:topic}, {int:userid})', array('id_tag' => $ID_TAG, 'topic' => $topic, 'userid' => $user_info['id']));
                        $count++;
                    }
                    mysql_free_result($result);
                }
            }
        }
    }
    // Editing or posting an event?
    if (isset($_POST['calendar']) && (!isset($_REQUEST['eventid']) || $_REQUEST['eventid'] == -1)) {
        require_once $sourcedir . '/lib/Subs-Calendar.php';
        // Make sure they can link an event to this post.
        canLinkEvent();
        // Insert the event.
        $eventOptions = array('board' => $board, 'topic' => $topic, 'title' => $_POST['evtitle'], 'member' => $user_info['id'], 'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']), 'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0);
        insertEvent($eventOptions);
    } elseif (isset($_POST['calendar'])) {
        $_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
        // Validate the post...
        require_once $sourcedir . '/lib/Subs-Calendar.php';
        validateEventPost();
        // If you're not allowed to edit any events, you have to be the poster.
        if (!allowedTo('calendar_edit_any')) {
            // Get the event's poster.
            $request = smf_db_query('
				SELECT id_member
				FROM {db_prefix}calendar
				WHERE id_event = {int:id_event}', array('id_event' => $_REQUEST['eventid']));
            $row2 = mysql_fetch_assoc($request);
            mysql_free_result($request);
            // Silly hacker, Trix are for kids. ...probably trademarked somewhere, this is FAIR USE! (parody...)
            isAllowedTo('calendar_edit_' . ($row2['id_member'] == $user_info['id'] ? 'own' : 'any'));
        }
        // Delete it?
        if (isset($_REQUEST['deleteevent'])) {
            smf_db_query('
				DELETE FROM {db_prefix}calendar
				WHERE id_event = {int:id_event}', array('id_event' => $_REQUEST['eventid']));
        } else {
            $span = !empty($modSettings['cal_allowspan']) && !empty($_REQUEST['span']) ? min((int) $modSettings['cal_maxspan'], (int) $_REQUEST['span'] - 1) : 0;
            $start_time = mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year']);
            smf_db_query('
				UPDATE {db_prefix}calendar
				SET end_date = {date:end_date},
					start_date = {date:start_date},
					title = {string:title}
				WHERE id_event = {int:id_event}', array('end_date' => strftime('%Y-%m-%d', $start_time + $span * 86400), 'start_date' => strftime('%Y-%m-%d', $start_time), 'id_event' => $_REQUEST['eventid'], 'title' => commonAPI::htmlspecialchars($_REQUEST['evtitle'], ENT_QUOTES)));
        }
        updateSettings(array('calendar_updated' => time()));
    }
    // Marking read should be done even for editing messages....
    // Mark all the parents read.  (since you just posted and they will be unread.)
    if (!$user_info['is_guest'] && !empty($board_info['parent_boards'])) {
        smf_db_query('
			UPDATE {db_prefix}log_boards
			SET id_msg = {int:id_msg}
			WHERE id_member = {int:current_member}
				AND id_board IN ({array_int:board_list})', array('current_member' => $user_info['id'], 'board_list' => array_keys($board_info['parent_boards']), 'id_msg' => $modSettings['maxMsgID']));
    }
    // Turn notification on or off.  (note this just blows smoke if it's already on or off.)
    if (!empty($_POST['notify']) && allowedTo('mark_any_notify')) {
        smf_db_insert('ignore', '{db_prefix}log_notify', array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int'), array($user_info['id'], $topic, 0), array('id_member', 'id_topic', 'id_board'));
    } elseif (!$newTopic) {
        smf_db_query('
			DELETE FROM {db_prefix}log_notify
			WHERE id_member = {int:current_member}
				AND id_topic = {int:current_topic}', array('current_member' => $user_info['id'], 'current_topic' => $topic));
    }
    // Log an act of moderation - modifying.
    if (!empty($moderationAction)) {
        logAction('modify', array('topic' => $topic, 'message' => (int) $_REQUEST['msg'], 'member' => $row['id_member'], 'board' => $board));
    }
    if (isset($_POST['lock']) && $_POST['lock'] != 2) {
        logAction('lock', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
    }
    if (isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics'])) {
        logAction('sticky', array('topic' => $topicOptions['id'], 'board' => $topicOptions['board']));
    }
    // Notify any members who have notification turned on for this topic - only do this if it's going to be approved(!)
    if ($becomesApproved) {
        if ($newTopic) {
            $notifyData = array('body' => $_POST['message'], 'subject' => $_POST['subject'], 'name' => $user_info['name'], 'poster' => $user_info['id'], 'msg' => $msgOptions['id'], 'board' => $board, 'topic' => $topic);
            notifyMembersBoard($notifyData);
        } elseif (empty($_REQUEST['msg'])) {
            // Only send it to everyone if the topic is approved, otherwise just to the topic starter if they want it.
            if ($topic_info['approved']) {
                sendNotifications($topic, 'reply');
            } else {
                sendNotifications($topic, 'reply', array(), $topic_info['id_member_started']);
            }
        }
    }
    // Returning to the topic?
    // Um, did this come from a draft?
    if (!empty($_POST['draft_id']) && !empty($user_info['id'])) {
        $_POST['draft_id'] = (int) $_POST['draft_id'];
        smf_db_query('
			DELETE FROM {db_prefix}drafts
			WHERE id_draft = {int:draft}
				AND id_member = {int:member}
			LIMIT 1', array('draft' => $_POST['draft_id'], 'member' => $user_info['id']));
    }
    if (!empty($_REQUEST['goback'])) {
        // Mark the board as read.... because it might get confusing otherwise.
        smf_db_query('
			UPDATE {db_prefix}log_boards
			SET id_msg = {int:maxMsgID}
			WHERE id_member = {int:current_member}
				AND id_board = {int:current_board}', array('current_board' => $board, 'current_member' => $user_info['id'], 'maxMsgID' => $modSettings['maxMsgID']));
    }
    if ($board_info['num_topics'] == 0) {
        CacheAPI::putCache('board-' . $board, null, 120);
    }
    if (!empty($_POST['announce_topic'])) {
        redirectexit('action=announce;sa=selectgroup;topic=' . $topic . (!empty($_POST['move']) && allowedTo('move_any') ? ';move' : '') . (empty($_REQUEST['goback']) ? '' : ';goback'));
    }
    if (!empty($_POST['move']) && allowedTo('move_any')) {
        redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
    }
    // Return to post if the mod is on.
    if (isset($_REQUEST['msg']) && !empty($_REQUEST['goback'])) {
        redirectexit('topic=' . $topic . '.msg' . $_REQUEST['msg'] . '#msg' . $_REQUEST['msg'], $context['browser']['is_ie']);
    } elseif (!empty($_REQUEST['goback'])) {
        redirectexit('topic=' . $topic . '.new#new', $context['browser']['is_ie']);
    } else {
        redirectexit('board=' . $board . '.0');
    }
}
Example #7
0
function TagCleanUp($id_tag)
{
    global $smcFunc;
    $result = smf_db_query('
		SELECT id FROM {db_prefix}tags_log WHERE id_tag = {int:id}', array('id' => $id_tag));
    if (smf_db_affected_rows() == 0) {
        smf_db_query('DELETE FROM {db_prefix}tags WHERE id_tag = {int:id}', array('id' => $id_tag));
    }
    mysql_free_result($result);
}
Example #8
0
function PlushSearch2()
{
    global $scripturl, $modSettings, $sourcedir, $txt;
    global $user_info, $context, $options, $messages_request, $boards_can;
    global $excludedWords, $participants, $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);
    }
    $_ctx = new SearchContext();
    // 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');
    // Are you allowed?
    isAllowedTo('search_posts');
    require_once $sourcedir . '/Display.php';
    require_once $sourcedir . '/lib/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 = smf_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) = 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(commonAPI::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[] = smf_db_quote('{string:possible_user}', array('possible_user' => $possible_user));
        }
        // Retrieve a list of possible members.
        $request = smf_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 (mysql_num_rows($request) > $maxMembersToSearch) {
            $userQuery = '';
        } elseif (mysql_num_rows($request) == 0) {
            $userQuery = smf_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 = mysql_fetch_assoc($request)) {
                $memberlist[] = $row['id_member'];
            }
            $userQuery = smf_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)));
        }
        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 = smf_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 (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 {
        $see_board = empty($search_params['advanced']) ? 'query_wanna_see_board' : 'query_see_board';
        $request = smf_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 = 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) {
        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 = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}boards
			WHERE redirect = {string:empty_string}', array('empty_string' => ''));
        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'];
    EoS_Smarty::loadTemplate('search/base');
    if (!isset($_REQUEST['xml'])) {
        EoS_Smarty::getConfigInstance()->registerHookTemplate('search_content_area', $context['compact'] ? 'search/results_compact' : 'search/results_as_messages');
    } else {
        EoS_Smarty::getConfigInstance()->registerHookTemplate('search_content_area', 'search/results_xml');
    }
    // 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 (commonAPI::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['server']['complex_preg_chars'] ? '\\x{A0}' : " ") . '\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~u', ' ', $search_params['search']);
    // Make the query lower case. It's gonna be case insensitive anyway.
    $stripped_query = un_htmlspecialchars(commonAPI::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)~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 (commonAPI::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);
        }
    }
    // 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'] = commonAPI::htmlspecialchars($context['search_params']['search']);
    }
    if (isset($context['search_params']['userspec'])) {
        $context['search_params']['userspec'] = commonAPI::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 . '/lib/Subs-Editor.php';
            $verificationOptions = array('id' => 'search', 'skip_template' => true);
            $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'];
        EoS_Smarty::resetTemplates();
        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 {
        log_error('update cache');
        $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.
            smf_db_query('
				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 = smf_db_query((1 ? '
						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)));
                    $numSubjectResults += smf_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)) {
                    smf_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.
                    smf_db_query('
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_topics', array('db_error_skip' => true));
                    $createTemporary = smf_db_query('
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_topics (
							id_topic mediumint(8) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_topic)
						) TYPE=HEAP', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clean up some previous cache.
                    if (!$createTemporary) {
                        smf_db_query('
							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 = smf_db_query((1 ? '
							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!
                        $numSubjectResults += smf_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)) {
                        smf_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();
                    smf_db_query('
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_messages', array('db_error_skip' => true));
                    $createTemporary = smf_db_query('
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_messages (
							id_msg int(10) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_msg)
						) TYPE=HEAP', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clear, all clear!
                    if (!$createTemporary) {
                        smf_db_query('
							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);
                            $indexedResults += smf_db_affected_rows();
                            if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) {
                                break;
                            }
                        }
                    }
                    // More non-MySQL stuff needed?
                    if (!empty($inserts)) {
                        smf_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'];
                        EoS_Smarty::resetTemplates();
                        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 = smf_db_query((1 ? '
						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']);
                    $_SESSION['search_cache']['num_results'] = smf_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 = smf_db_query((1 ? '
						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!
                    $_SESSION['search_cache']['num_results'] += smf_db_affected_rows();
                } else {
                    $_SESSION['search_cache']['num_results'] = 0;
                }
            }
        }
        // *** Retrieve the results to be shown on the page
        $participants = array();
        $request = smf_db_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 = mysql_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;
        }
        mysql_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 = smf_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 = 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 = smf_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 (mysql_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 = smf_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 = mysql_fetch_assoc($result)) {
                $participants[$row['id_topic']] = true;
            }
            mysql_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) {
        CacheAPI::putCache('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $user_info['id']), null, 90);
    }
    $context['key_words'] =& $searchArray;
    if (empty($context['compact'])) {
        $context['need_synhlt'] = 1;
    }
    $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'])));
}
Example #9
0
function markMessages($personal_messages = null, $label = null, $owner = null)
{
    global $user_info, $context, $smcFunc;
    if ($owner === null) {
        $owner = $user_info['id'];
    }
    smf_db_query('
		UPDATE {db_prefix}pm_recipients
		SET is_read = is_read | 1
		WHERE id_member = {int:id_member}
			AND NOT (is_read & 1 >= 1)' . ($label === null ? '' : '
			AND FIND_IN_SET({string:label}, labels) != 0') . ($personal_messages !== null ? '
			AND id_pm IN ({array_int:personal_messages})' : ''), array('personal_messages' => $personal_messages, 'id_member' => $owner, 'label' => $label));
    // If something wasn't marked as read, get the number of unread messages remaining.
    if (smf_db_affected_rows() > 0) {
        if ($owner == $user_info['id']) {
            foreach ($context['labels'] as $label) {
                $context['labels'][(int) $label['id']]['unread_messages'] = 0;
            }
        }
        $result = smf_db_query('
			SELECT labels, COUNT(*) AS num
			FROM {db_prefix}pm_recipients
			WHERE id_member = {int:id_member}
				AND NOT (is_read & 1 >= 1)
				AND deleted = {int:is_not_deleted}
			GROUP BY labels', array('id_member' => $owner, 'is_not_deleted' => 0));
        $total_unread = 0;
        while ($row = mysql_fetch_assoc($result)) {
            $total_unread += $row['num'];
            if ($owner != $user_info['id']) {
                continue;
            }
            $this_labels = explode(',', $row['labels']);
            foreach ($this_labels as $this_label) {
                $context['labels'][(int) $this_label]['unread_messages'] += $row['num'];
            }
        }
        mysql_free_result($result);
        // Need to store all this.
        CacheAPI::putCache('labelCounts:' . $owner, $context['labels'], 720);
        updateMemberData($owner, array('unread_messages' => $total_unread));
        // If it was for the current member, reflect this in the $user_info array too.
        if ($owner == $user_info['id']) {
            $user_info['unread_messages'] = $total_unread;
        }
    }
}
Example #10
0
/**
* This function attempts to protect from spammed messages and the like.
* The time taken depends on error_type - generally uses the modSetting.
*
* @param string $error_type, used also as a $txt index. (not an actual string.)
* @return boolean
*/
function spamProtection($error_type)
{
    global $modSettings, $user_info;
    // Certain types take less/more time.
    $timeOverrides = array('login' => 2, 'register' => 2, 'pwremind' => 30, 'sendtopic' => $modSettings['spamWaitTime'] * 4, 'sendmail' => $modSettings['spamWaitTime'] * 5, 'reporttm' => $modSettings['spamWaitTime'] * 4, 'search' => !empty($modSettings['search_floodcontrol_time']) ? $modSettings['search_floodcontrol_time'] : 1);
    // Moderators are free...
    if (!allowedTo('moderate_board')) {
        $timeLimit = isset($timeOverrides[$error_type]) ? $timeOverrides[$error_type] : $modSettings['spamWaitTime'];
    } else {
        $timeLimit = 2;
    }
    // Delete old entries...
    smf_db_query('
		DELETE FROM {db_prefix}log_floodcontrol
		WHERE log_time < {int:log_time}
			AND log_type = {string:log_type}', array('log_time' => time() - $timeLimit, 'log_type' => $error_type));
    // Add a new entry, deleting the old if necessary.
    smf_db_insert('replace', '{db_prefix}log_floodcontrol', array('ip' => 'string-16', 'log_time' => 'int', 'log_type' => 'string'), array($user_info['ip'], time(), $error_type), array('ip', 'log_type'));
    // If affected is 0 or 2, it was there already.
    if (smf_db_affected_rows() != 1) {
        // Spammer!  You only have to wait a *few* seconds!
        fatal_lang_error($error_type . 'WaitTime_broken', false, array($timeLimit));
        return true;
    }
    // They haven't posted within the limit.
    return false;
}
Example #11
0
function removeMessage($message, $decreasePostCount = true)
{
    global $board, $sourcedir, $backend_subdir, $modSettings, $user_info;
    if (empty($message) || !is_numeric($message)) {
        return false;
    }
    $request = smf_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 (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'] == $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.
    smf_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 (smf_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 = smf_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 = mysql_fetch_assoc($request);
        mysql_free_result($request);
        smf_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 {
        smf_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 = smf_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 (mysql_num_rows($request) == 0) {
            fatal_lang_error('recycle_no_valid_board');
        }
        list($isRead, $last_board_msg) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Is there an existing topic in the recycle board to group this post with?
        $request = smf_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) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Insert a new topic in the recycle board if $id_recycle_topic is empty.
        if (empty($id_recycle_topic)) {
            smf_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) ? smf_db_insert_id('{db_prefix}topics', 'id_topic') : $id_recycle_topic;
        // If the topic creation went successful, move the message.
        if ($topicID > 0) {
            smf_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...
            smf_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']) {
                smf_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']) {
                smf_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.
            smf_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)) {
                smf_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']) {
            smf_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));
        }
    }
    smf_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) {
        require_once $sourcedir . '/lib/Subs-Ratings.php';
        require_once $sourcedir . '/lib/Subs-Activities.php';
        // Remove the message + maybe its cached version
        smf_db_query('
			DELETE m.*, c.* FROM {db_prefix}messages AS m LEFT JOIN {db_prefix}messages_cache AS c ON (c.id_msg = m.id_msg)
			WHERE m.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)) {
                smf_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 . '/lib/Subs-ManageAttachments.php';
        $attachmentQuery = array('attachment_type' => 0, 'id_msg' => $message);
        removeAttachments($attachmentQuery);
        // remove likes and like_cache
        $likes_to_remove = array($message);
        Ratings::removeByPosts($likes_to_remove);
        // remove activities related to this post
        aStreamRemoveByContent($likes_to_remove);
    }
    // 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 . '/lib/Subs-Post.php';
    if ($recycle) {
        updateLastMessages(array($row['id_board'], $modSettings['recycle_board']));
    } else {
        updateLastMessages($row['id_board']);
    }
    return false;
}
Example #12
0
function createSalvageArea()
{
    global $txt, $language, $salvageBoardID, $salvageCatID, $smcFunc;
    static $createOnce = false;
    // Have we already created it?
    if ($createOnce) {
        return;
    } else {
        $createOnce = true;
    }
    // Back to the forum's default language.
    loadLanguage('Admin', $language);
    // Check to see if a 'Salvage Category' exists, if not => insert one.
    $result = smf_db_query('
		SELECT id_cat
		FROM {db_prefix}categories
		WHERE name = {string:cat_name}
		LIMIT 1', array('cat_name' => $txt['salvaged_category_name']));
    if (mysql_num_rows($result) != 0) {
        list($salvageCatID) = mysql_fetch_row($result);
    }
    mysql_free_result($result);
    if (empty($salveageCatID)) {
        smf_db_insert('', '{db_prefix}categories', array('name' => 'string-255', 'cat_order' => 'int'), array($txt['salvaged_category_name'], -1), array('id_cat'));
        if (smf_db_affected_rows() <= 0) {
            loadLanguage('Admin');
            fatal_lang_error('salvaged_category_error', false);
        }
        $salvageCatID = smf_db_insert_id('{db_prefix}categories', 'id_cat');
    }
    // Check to see if a 'Salvage Board' exists, if not => insert one.
    $result = smf_db_query('
		SELECT id_board
		FROM {db_prefix}boards
		WHERE id_cat = {int:id_cat}
			AND name = {string:board_name}
		LIMIT 1', array('id_cat' => $salvageCatID, 'board_name' => $txt['salvaged_board_name']));
    if (mysql_num_rows($result) != 0) {
        list($salvageBoardID) = mysql_fetch_row($result);
    }
    mysql_free_result($result);
    if (empty($salvageBoardID)) {
        smf_db_insert('', '{db_prefix}boards', array('name' => 'string-255', 'description' => 'string-255', 'id_cat' => 'int', 'member_groups' => 'string', 'board_order' => 'int', 'redirect' => 'string'), array($txt['salvaged_board_name'], $txt['salvaged_board_description'], $salvageCatID, '1', -1, ''), array('id_board'));
        if (smf_db_affected_rows() <= 0) {
            loadLanguage('Admin');
            fatal_lang_error('salvaged_board_error', false);
        }
        $salvageBoardID = smf_db_insert_id('{db_prefix}boards', 'id_board');
    }
    smf_db_query('
		ALTER TABLE {db_prefix}boards
		ORDER BY board_order', array());
    // Restore the user's language.
    loadLanguage('Admin');
}
Example #13
0
function trackStats($stats = array())
{
    global $modSettings;
    static $cache_stats = array();
    if (empty($modSettings['trackStats'])) {
        return false;
    }
    if (!empty($stats)) {
        return $cache_stats = array_merge($cache_stats, $stats);
    } elseif (empty($cache_stats)) {
        return false;
    }
    $setStringUpdate = '';
    $insert_keys = array();
    $date = strftime('%Y-%m-%d', forum_time(false));
    $update_parameters = array('current_date' => $date);
    foreach ($cache_stats as $field => $change) {
        $setStringUpdate .= '
			' . $field . ' = ' . ($change === '+' ? $field . ' + 1' : '{int:' . $field . '}') . ',';
        if ($change === '+') {
            $cache_stats[$field] = 1;
        } else {
            $update_parameters[$field] = $change;
        }
        $insert_keys[$field] = 'int';
    }
    smf_db_query('
		UPDATE {db_prefix}log_activity
		SET' . substr($setStringUpdate, 0, -1) . '
		WHERE date = {date:current_date}', $update_parameters);
    if (smf_db_affected_rows() == 0) {
        smf_db_insert('ignore', '{db_prefix}log_activity', array_merge($insert_keys, array('date' => 'date')), array_merge($cache_stats, array($date)), array('date'));
    }
    // Don't do this again.
    $cache_stats = array();
    return true;
}
Example #14
0
function smf_db_insert($method = 'replace', $table, $columns, $data, $keys, $disable_trans = false, $connection = null)
{
    global $db_replace_result, $db_in_transact, $smcFunc, $db_connection, $db_prefix;
    $connection = $connection === null ? $db_connection : $connection;
    if (empty($data)) {
        return;
    }
    if (!is_array($data[array_rand($data)])) {
        $data = array($data);
    }
    // Replace the prefix holder with the actual prefix.
    $table = str_replace('{db_prefix}', $db_prefix, $table);
    $priv_trans = false;
    if (count($data) > 1 && !$db_in_transact && !$disable_trans) {
        $smcFunc['db_transaction']('begin', $connection);
        $priv_trans = true;
    }
    // PostgreSQL doesn't support replace or insert ignore so we need to work around it.
    if ($method == 'replace') {
        // Setup an UPDATE template.
        $updateData = '';
        $where = '';
        foreach ($columns as $columnName => $type) {
            // Are we restricting the length?
            if (strpos($type, 'string-') !== false) {
                $actualType = sprintf($columnName . ' = SUBSTRING({string:%1$s}, 1, ' . substr($type, 7) . '), ', $columnName);
            } else {
                $actualType = sprintf($columnName . ' = {%1$s:%2$s}, ', $type, $columnName);
            }
            // Has it got a key?
            if (in_array($columnName, $keys)) {
                $where .= (empty($where) ? '' : ' AND ') . substr($actualType, 0, -2);
            } else {
                $updateData .= $actualType;
            }
        }
        $updateData = substr($updateData, 0, -2);
        // Try and update the entries.
        if (!empty($updateData)) {
            foreach ($data as $k => $entry) {
                $smcFunc['db_query']('', '
					UPDATE ' . $table . '
					SET ' . $updateData . '
					' . (empty($where) ? '' : ' WHERE ' . $where), array_combine(array_keys($columns), $entry), $connection);
                // Make a note that the replace actually overwrote.
                if (smf_db_affected_rows() != 0) {
                    unset($data[$k]);
                    $db_replace_result = 2;
                }
            }
        }
    }
    if (!empty($data)) {
        // Create the mold for a single row insert.
        $insertData = '(';
        foreach ($columns as $columnName => $type) {
            // Are we restricting the length?
            if (strpos($type, 'string-') !== false) {
                $insertData .= sprintf('SUBSTRING({string:%1$s}, 1, ' . substr($type, 7) . '), ', $columnName);
            } else {
                $insertData .= sprintf('{%1$s:%2$s}, ', $type, $columnName);
            }
        }
        $insertData = substr($insertData, 0, -2) . ')';
        // Create an array consisting of only the columns.
        $indexed_columns = array_keys($columns);
        // Here's where the variables are injected to the query.
        $insertRows = array();
        foreach ($data as $dataRow) {
            $insertRows[] = smf_db_quote($insertData, array_combine($indexed_columns, $dataRow), $connection);
        }
        foreach ($insertRows as $entry) {
            // Do the insert.
            $smcFunc['db_query']('', '
				INSERT INTO ' . $table . '("' . implode('", "', $indexed_columns) . '")
				VALUES
					' . $entry, array('security_override' => true, 'db_error_skip' => $method == 'ignore'), $connection);
        }
    }
    if ($priv_trans) {
        $smcFunc['db_transaction']('commit', $connection);
    }
}
Example #15
0
function consolidateSpiderStats()
{
    $request = smf_db_query('
		SELECT id_spider, MAX(log_time) AS last_seen, COUNT(*) AS num_hits
		FROM {db_prefix}log_spider_hits
		WHERE processed = {int:not_processed}
		GROUP BY id_spider, MONTH(log_time), DAYOFMONTH(log_time)', array('not_processed' => 0));
    $spider_hits = array();
    while ($row = mysql_fetch_assoc($request)) {
        $spider_hits[] = $row;
    }
    mysql_free_result($request);
    if (empty($spider_hits)) {
        return;
    }
    // Attempt to update the master data.
    $stat_inserts = array();
    foreach ($spider_hits as $stat) {
        // We assume the max date is within the right day.
        $date = strftime('%Y-%m-%d', $stat['last_seen']);
        smf_db_query('
			UPDATE {db_prefix}log_spider_stats
			SET page_hits = page_hits + ' . $stat['num_hits'] . ',
				last_seen = CASE WHEN last_seen > {int:last_seen} THEN last_seen ELSE {int:last_seen} END
			WHERE id_spider = {int:current_spider}
				AND stat_date = {date:last_seen_date}', array('last_seen_date' => $date, 'last_seen' => $stat['last_seen'], 'current_spider' => $stat['id_spider']));
        if (smf_db_affected_rows() == 0) {
            $stat_inserts[] = array($date, $stat['id_spider'], $stat['num_hits'], $stat['last_seen']);
        }
    }
    // New stats?
    if (!empty($stat_inserts)) {
        smf_db_insert('ignore', '{db_prefix}log_spider_stats', array('stat_date' => 'date', 'id_spider' => 'int', 'page_hits' => 'int', 'last_seen' => 'int'), $stat_inserts, array('stat_date', 'id_spider'));
    }
    // All processed.
    smf_db_query('
		UPDATE {db_prefix}log_spider_hits
		SET processed = {int:is_processed}
		WHERE processed = {int:not_processed}', array('is_processed' => 1, 'not_processed' => 0));
}