Beispiel #1
0
function AutoSuggest_Search_Tags()
{
    global $user_info, $txt, $smcFunc;
    $_REQUEST['search'] = trim(commonAPI::strtolower($_REQUEST['search'])) . '*';
    $_REQUEST['search'] = strtr($_REQUEST['search'], array('%' => '\\%', '_' => '\\_', '*' => '%', '?' => '_', '&' => '&'));
    // Find tags
    $request = smf_db_query('
		SELECT id_member, real_name
		FROM {db_prefix}tags
		WHERE tag LIKE {string:search} 
		LIMIT ' . (strlen($_REQUEST['search']) <= 2 ? '100' : '800'), array('search' => $_REQUEST['search']));
    $xml_data = array('tags' => array('identifier' => 'tag', 'children' => array()));
    while ($row = mysql_fetch_assoc($request)) {
        $xml_data['tags']['children'][] = array('attributes' => array('id' => $row['id_tag']), 'value' => $row['tag']);
    }
    mysql_free_result($request);
    return $xml_data;
}
Beispiel #2
0
function sendpm($recipients, $subject, $message, $store_outbox = false, $from = null, $pm_head = 0)
{
    global $scripturl, $txt, $user_info, $language;
    global $modSettings, $sourcedir;
    // Make sure the PM language file is loaded, we might need something out of it.
    loadLanguage('PersonalMessage');
    $onBehalf = $from !== null;
    // Initialize log array.
    $log = array('failed' => array(), 'sent' => array());
    if ($from === null) {
        $from = array('id' => $user_info['id'], 'name' => $user_info['name'], 'username' => $user_info['username']);
    } else {
        $user_info['name'] = $from['name'];
    }
    // This is the one that will go in their inbox.
    $htmlmessage = commonAPI::htmlspecialchars($message, ENT_QUOTES);
    $htmlsubject = commonAPI::htmlspecialchars($subject);
    preparsecode($htmlmessage);
    // Integrated PMs
    HookAPI::callHook('integrate_personal_message', array($recipients, $from['username'], $subject, $message));
    // Get a list of usernames and convert them to IDs.
    $usernames = array();
    foreach ($recipients as $rec_type => $rec) {
        foreach ($rec as $id => $member) {
            if (!is_numeric($recipients[$rec_type][$id])) {
                //$recipients[$rec_type][$id] = commonAPI::strtolower(trim(preg_replace('/[<>&"\'=\\\]/', '', $recipients[$rec_type][$id])));
                $recipients[$rec_type][$id] = commonAPI::strtolower(trim(preg_replace('/[<>&"\'=\\]/', '', $recipients[$rec_type][$id])));
                $usernames[$recipients[$rec_type][$id]] = 0;
            }
        }
    }
    if (!empty($usernames)) {
        $request = smf_db_query('
			SELECT id_member, member_name
			FROM {db_prefix}members
			WHERE ' . 'member_name' . ' IN ({array_string:usernames})', array('usernames' => array_keys($usernames)));
        while ($row = mysql_fetch_assoc($request)) {
            if (isset($usernames[commonAPI::strtolower($row['member_name'])])) {
                $usernames[commonAPI::strtolower($row['member_name'])] = $row['id_member'];
            }
        }
        mysql_free_result($request);
        // Replace the usernames with IDs. Drop usernames that couldn't be found.
        foreach ($recipients as $rec_type => $rec) {
            foreach ($rec as $id => $member) {
                if (is_numeric($recipients[$rec_type][$id])) {
                    continue;
                }
                if (!empty($usernames[$member])) {
                    $recipients[$rec_type][$id] = $usernames[$member];
                } else {
                    $log['failed'][$id] = sprintf($txt['pm_error_user_not_found'], $recipients[$rec_type][$id]);
                    unset($recipients[$rec_type][$id]);
                }
            }
        }
    }
    // Make sure there are no duplicate 'to' members.
    $recipients['to'] = array_unique($recipients['to']);
    // Only 'bcc' members that aren't already in 'to'.
    $recipients['bcc'] = array_diff(array_unique($recipients['bcc']), $recipients['to']);
    // Combine 'to' and 'bcc' recipients.
    $all_to = array_merge($recipients['to'], $recipients['bcc']);
    // Check no-one will want it deleted right away!
    $request = smf_db_query('
		SELECT
			id_member, criteria, is_or
		FROM {db_prefix}pm_rules
		WHERE id_member IN ({array_int:to_members})
			AND delete_pm = {int:delete_pm}', array('to_members' => $all_to, 'delete_pm' => 1));
    $deletes = array();
    // Check whether we have to apply anything...
    while ($row = mysql_fetch_assoc($request)) {
        $criteria = unserialize($row['criteria']);
        // Note we don't check the buddy status, cause deletion from buddy = madness!
        $delete = false;
        foreach ($criteria as $criterium) {
            $match = false;
            if ($criterium['t'] == 'mid' && $criterium['v'] == $from['id'] || $criterium['t'] == 'gid' && in_array($criterium['v'], $user_info['groups']) || $criterium['t'] == 'sub' && strpos($subject, $criterium['v']) !== false || $criterium['t'] == 'msg' && strpos($message, $criterium['v']) !== false) {
                $delete = true;
            } elseif (!$row['is_or']) {
                $delete = false;
                break;
            }
        }
        if ($delete) {
            $deletes[$row['id_member']] = 1;
        }
    }
    mysql_free_result($request);
    // Load the membergrounp message limits.
    //!!! Consider caching this?
    static $message_limit_cache = array();
    if (!allowedTo('moderate_forum') && empty($message_limit_cache)) {
        $request = smf_db_query('
			SELECT id_group, max_messages
			FROM {db_prefix}membergroups', array());
        while ($row = mysql_fetch_assoc($request)) {
            $message_limit_cache[$row['id_group']] = $row['max_messages'];
        }
        mysql_free_result($request);
    }
    // Load the groups that are allowed to read PMs.
    $allowed_groups = array();
    $disallowed_groups = array();
    $request = smf_db_query('
		SELECT id_group, add_deny
		FROM {db_prefix}permissions
		WHERE permission = {string:read_permission}', array('read_permission' => 'pm_read'));
    while ($row = mysql_fetch_assoc($request)) {
        if (empty($row['add_deny'])) {
            $disallowed_groups[] = $row['id_group'];
        } else {
            $allowed_groups[] = $row['id_group'];
        }
    }
    mysql_free_result($request);
    if (empty($modSettings['permission_enable_deny'])) {
        $disallowed_groups = array();
    }
    $request = smf_db_query('
		SELECT
			member_name, real_name, id_member, email_address, lngfile,
			pm_email_notify, instant_messages,' . (allowedTo('moderate_forum') ? ' 0' : '
			(pm_receive_from = {int:admins_only}' . (empty($modSettings['enable_buddylist']) ? '' : ' OR
			(pm_receive_from = {int:buddies_only} AND FIND_IN_SET({string:from_id}, buddy_list) = 0) OR
			(pm_receive_from = {int:not_on_ignore_list} AND FIND_IN_SET({string:from_id}, pm_ignore_list) != 0)') . ')') . ' AS ignored,
			FIND_IN_SET({string:from_id}, buddy_list) != 0 AS is_buddy, is_activated,
			additional_groups, id_group, id_post_group
		FROM {db_prefix}members
		WHERE id_member IN ({array_int:recipients})
		ORDER BY lngfile
		LIMIT {int:count_recipients}', array('not_on_ignore_list' => 1, 'buddies_only' => 2, 'admins_only' => 3, 'recipients' => $all_to, 'count_recipients' => count($all_to), 'from_id' => $from['id']));
    $notifications = array();
    $as_notifications = array();
    while ($row = mysql_fetch_assoc($request)) {
        // Don't do anything for members to be deleted!
        if (isset($deletes[$row['id_member']])) {
            continue;
        }
        // We need to know this members groups.
        $groups = explode(',', $row['additional_groups']);
        $groups[] = $row['id_group'];
        $groups[] = $row['id_post_group'];
        $message_limit = -1;
        // For each group see whether they've gone over their limit - assuming they're not an admin.
        if (!in_array(1, $groups)) {
            foreach ($groups as $id) {
                if (isset($message_limit_cache[$id]) && $message_limit != 0 && $message_limit < $message_limit_cache[$id]) {
                    $message_limit = $message_limit_cache[$id];
                }
            }
            if ($message_limit > 0 && $message_limit <= $row['instant_messages']) {
                $log['failed'][$row['id_member']] = sprintf($txt['pm_error_data_limit_reached'], $row['real_name']);
                unset($all_to[array_search($row['id_member'], $all_to)]);
                continue;
            }
            // Do they have any of the allowed groups?
            if (count(array_intersect($allowed_groups, $groups)) == 0 || count(array_intersect($disallowed_groups, $groups)) != 0) {
                $log['failed'][$row['id_member']] = sprintf($txt['pm_error_user_cannot_read'], $row['real_name']);
                unset($all_to[array_search($row['id_member'], $all_to)]);
                continue;
            }
        }
        // Note that PostgreSQL can return a lowercase t/f for FIND_IN_SET
        if (!empty($row['ignored']) && $row['ignored'] != 'f' && $row['id_member'] != $from['id']) {
            $log['failed'][$row['id_member']] = sprintf($txt['pm_error_ignored_by_user'], $row['real_name']);
            unset($all_to[array_search($row['id_member'], $all_to)]);
            continue;
        }
        // If the receiving account is banned (>=10) or pending deletion (4), refuse to send the PM.
        if ($row['is_activated'] >= 10 || $row['is_activated'] == 4 && !$user_info['is_admin']) {
            $log['failed'][$row['id_member']] = sprintf($txt['pm_error_user_cannot_read'], $row['real_name']);
            unset($all_to[array_search($row['id_member'], $all_to)]);
            continue;
        }
        // Send a notification, if enabled - taking the buddy list into account.
        if (!empty($row['email_address']) && ($row['pm_email_notify'] == 1 || $row['pm_email_notify'] > 1 && (!empty($modSettings['enable_buddylist']) && $row['is_buddy'])) && $row['is_activated'] == 1) {
            $notifications[empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']][] = $row['email_address'];
        }
        $as_notifications[] = $row['id_member'];
        $log['sent'][$row['id_member']] = sprintf(isset($txt['pm_successfully_sent']) ? $txt['pm_successfully_sent'] : '', $row['real_name']);
    }
    mysql_free_result($request);
    // Only 'send' the message if there are any recipients left.
    if (empty($all_to)) {
        return $log;
    }
    // Insert the message itself and then grab the last insert id.
    smf_db_insert('', '{db_prefix}personal_messages', array('id_pm_head' => 'int', 'id_member_from' => 'int', 'deleted_by_sender' => 'int', 'from_name' => 'string-255', 'msgtime' => 'int', 'subject' => 'string-255', 'body' => 'string-65534'), array($pm_head, $from['id'], $store_outbox ? 0 : 1, $from['username'], time(), $htmlsubject, $htmlmessage), array('id_pm'));
    $id_pm = smf_db_insert_id('{db_prefix}personal_messages', 'id_pm');
    if ($modSettings['astream_active']) {
        require_once $sourcedir . '/lib/Subs-Activities.php';
        $id_act = aStreamAdd($from['id'], ACT_PM, array('member_name' => $from['username']), 0, 0, $id_pm, $from['id'], ACT_PLEVEL_PRIVATE);
        if ((int) $id_act > 0) {
            aStreamAddNotification($as_notifications, $id_act, ACT_PM);
        }
    }
    // Add the recipients.
    if (!empty($id_pm)) {
        // If this is new we need to set it part of it's own conversation.
        if (empty($pm_head)) {
            smf_db_query('
				UPDATE {db_prefix}personal_messages
				SET id_pm_head = {int:id_pm_head}
				WHERE id_pm = {int:id_pm_head}', array('id_pm_head' => $id_pm));
        }
        // Some people think manually deleting personal_messages is fun... it's not. We protect against it though :)
        smf_db_query('
			DELETE FROM {db_prefix}pm_recipients
			WHERE id_pm = {int:id_pm}', array('id_pm' => $id_pm));
        $insertRows = array();
        foreach ($all_to as $to) {
            $insertRows[] = array($id_pm, $to, in_array($to, $recipients['bcc']) ? 1 : 0, isset($deletes[$to]) ? 1 : 0, 1);
        }
        smf_db_insert('insert', '{db_prefix}pm_recipients', array('id_pm' => 'int', 'id_member' => 'int', 'bcc' => 'int', 'deleted' => 'int', 'is_new' => 'int'), $insertRows, array('id_pm', 'id_member'));
    }
    censorText($message);
    censorText($subject);
    $message = trim(un_htmlspecialchars(strip_tags(strtr(parse_bbc(htmlspecialchars($message), false), array('<br />' => "\n", '</div>' => "\n", '</li>' => "\n", '&#91;' => '[', '&#93;' => ']')))));
    foreach ($notifications as $lang => $notification_list) {
        // Make sure to use the right language.
        loadLanguage('index+PersonalMessage', $lang, false);
        // Replace the right things in the message strings.
        $mailsubject = str_replace(array('SUBJECT', 'SENDER'), array($subject, un_htmlspecialchars($from['name'])), $txt['new_pm_subject']);
        $mailmessage = str_replace(array('SUBJECT', 'MESSAGE', 'SENDER'), array($subject, $message, un_htmlspecialchars($from['name'])), $txt['pm_email']);
        $mailmessage .= "\n\n" . $txt['instant_reply'] . ' ' . $scripturl . '?action=pm;sa=send;f=inbox;pmsg=' . $id_pm . ';quote;u=' . $from['id'];
        // Off the notification email goes!
        sendmail($notification_list, $mailsubject, $mailmessage, null, 'p' . $id_pm, false, 2, null, true);
    }
    // Back to what we were on before!
    loadLanguage('index+PersonalMessage');
    // Add one to their unread and read message counts.
    foreach ($all_to as $k => $id) {
        if (isset($deletes[$id])) {
            unset($all_to[$k]);
        }
    }
    if (!empty($all_to)) {
        updateMemberData($all_to, array('instant_messages' => '+', 'unread_messages' => '+', 'new_pm' => 1));
    }
    return $log;
}
Beispiel #3
0
function isReservedName($name, $current_ID_MEMBER = 0, $is_name = true, $fatal = true)
{
    global $modSettings, $context;
    // No cheating with entities please.
    $replaceEntities = create_function('$string', '
		$num = substr($string, 0, 1) === \'x\' ? hexdec(substr($string, 1)) : (int) $string;
		if ($num === 0x202E || $num === 0x202D) return \'\'; if (in_array($num, array(0x22, 0x26, 0x27, 0x3C, 0x3E))) return \'&#\' . $num . \';\';' . 'return $num < 0x20 || $num > 0x10FFFF || ($num >= 0xD800 && $num <= 0xDFFF) ? \'\' : ($num < 0x80 ? chr($num) : ($num < 0x800 ? chr(192 | $num >> 6) . chr(128 | $num & 63) : ($num < 0x10000 ? chr(224 | $num >> 12) . chr(128 | $num >> 6 & 63) . chr(128 | $num & 63) : chr(240 | $num >> 18) . chr(128 | $num >> 12 & 63) . chr(128 | $num >> 6 & 63) . chr(128 | $num & 63))));');
    $name = preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~e', '$replaceEntities(\'\\2\')', $name);
    $checkName = commonAPI::strtolower($name);
    // Administrators are never restricted ;).
    if (!allowedTo('moderate_forum') && (!empty($modSettings['reserveName']) && $is_name || !empty($modSettings['reserveUser']) && !$is_name)) {
        $reservedNames = explode("\n", $modSettings['reserveNames']);
        // Case sensitive check?
        $checkMe = empty($modSettings['reserveCase']) ? $checkName : $name;
        // Check each name in the list...
        foreach ($reservedNames as $reserved) {
            if ($reserved == '') {
                continue;
            }
            // The admin might've used entities too, level the playing field.
            $reservedCheck = preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~e', '$replaceEntities(\'\\2\')', $reserved);
            // Case sensitive name?
            if (empty($modSettings['reserveCase'])) {
                $reservedCheck = commonAPI::strtolower($reservedCheck);
            }
            // If it's not just entire word, check for it in there somewhere...
            if ($checkMe == $reservedCheck || commonAPI::strpos($checkMe, $reservedCheck) !== false && empty($modSettings['reserveWord'])) {
                if ($fatal) {
                    fatal_lang_error('username_reserved', 'password', array($reserved));
                } else {
                    return true;
                }
            }
        }
        $censor_name = $name;
        if (censorText($censor_name) != $name) {
            if ($fatal) {
                fatal_lang_error('name_censored', 'password', array($name));
            } else {
                return true;
            }
        }
    }
    // Characters we just shouldn't allow, regardless.
    foreach (array('*') as $char) {
        if (strpos($checkName, $char) !== false) {
            if ($fatal) {
                fatal_lang_error('username_reserved', 'password', array($char));
            } else {
                return true;
            }
        }
    }
    // Get rid of any SQL parts of the reserved name...
    $checkName = strtr($name, array('_' => '\\_', '%' => '\\%'));
    // Make sure they don't want someone else's name.
    $request = smf_db_query('
		SELECT id_member
		FROM {db_prefix}members
		WHERE ' . (empty($current_ID_MEMBER) ? '' : 'id_member != {int:current_member}
			AND ') . '(real_name LIKE {string:check_name} OR member_name LIKE {string:check_name})
		LIMIT 1', array('current_member' => $current_ID_MEMBER, 'check_name' => $checkName));
    if (mysql_num_rows($request) > 0) {
        mysql_free_result($request);
        return true;
    }
    // Does name case insensitive match a member group name?
    $request = smf_db_query('
		SELECT id_group
		FROM {db_prefix}membergroups
		WHERE group_name LIKE {string:check_name}
		LIMIT 1', array('check_name' => $checkName));
    if (mysql_num_rows($request) > 0) {
        mysql_free_result($request);
        return true;
    }
    // Okay, they passed.
    return false;
}
Beispiel #4
0
function template_package_list()
{
    global $context, $settings, $options, $txt, $scripturl, $smcFunc;
    echo '
	<div id="admincenter">
		<div class="cat_bar">
			<h3>' . $context['page_title'] . '</h3>
		</div>
		<div class="blue_container">
			<div class="content">';
    // No packages, as yet.
    if (empty($context['package_list'])) {
        echo '
				<ul>
					<li>', $txt['no_packages'], '</li>
				</ul>';
    } else {
        echo '
				<ul id="package_list">';
        foreach ($context['package_list'] as $i => $packageSection) {
            echo '
					<li>
						<strong><img id="ps_img_', $i, '" src="', $settings['images_url'], '/upshrink.png" alt="*" style="display: none;" /> ', $packageSection['title'], '</strong>';
            if (!empty($packageSection['text'])) {
                echo '
						<div class="information">', $packageSection['text'], '</div>';
            }
            echo '
						<', $context['list_type'], ' id="package_section_', $i, '" class="packages">';
            $alt = false;
            foreach ($packageSection['items'] as $id => $package) {
                echo '
							<li>';
                // Textual message. Could be empty just for a blank line...
                if ($package['is_text']) {
                    echo '
								', empty($package['name']) ? '&nbsp;' : $package['name'];
                } elseif ($package['is_line']) {
                    echo '
							<hr class="hrcolor" />';
                } elseif ($package['is_remote']) {
                    echo '
							<strong>', $package['link'], '</strong>';
                } elseif ($package['is_heading'] || $package['is_title']) {
                    echo '
							<strong>', $package['name'], '</strong>';
                } else {
                    // 1. Some mod [ Download ].
                    echo '
							<strong><img id="ps_img_', $i, '_pkg_', $id, '" src="', $settings['images_url'], '/upshrink.png" alt="*" style="display: none;" /> ', $package['can_install'] ? '<strong>' . $package['name'] . '</strong> <a href="' . $package['download']['href'] . '">[ ' . $txt['download'] . ' ]</a>' : $package['name'];
                    // Mark as installed and current?
                    if ($package['is_installed'] && !$package['is_newer']) {
                        echo '<img src="', $settings['images_url'], '/icons/package_', $package['is_current'] ? 'installed' : 'old', '.gif" width="12" height="11" align="middle" style="margin-left: 2ex;" alt="', $package['is_current'] ? $txt['package_installed_current'] : $txt['package_installed_old'], '" />';
                    }
                    echo '
							</strong>
							<ul id="package_section_', $i, '_pkg_', $id, '" class="package_section">';
                    // Show the mod type?
                    if ($package['type'] != '') {
                        echo '
								<li class="package_section">', $txt['package_type'], ':&nbsp; ', commonAPI::ucwords(commonAPI::strtolower($package['type'])), '</li>';
                    }
                    // Show the version number?
                    if ($package['version'] != '') {
                        echo '
								<li class="package_section">', $txt['mod_version'], ':&nbsp; ', $package['version'], '</li>';
                    }
                    // How 'bout the author?
                    if (!empty($package['author']) && $package['author']['name'] != '' && isset($package['author']['link'])) {
                        echo '
								<li class="package_section">', $txt['mod_author'], ':&nbsp; ', $package['author']['link'], '</li>';
                    }
                    // The homepage....
                    if ($package['author']['website']['link'] != '') {
                        echo '
								<li class="package_section">', $txt['author_website'], ':&nbsp; ', $package['author']['website']['link'], '</li>';
                    }
                    // Desciption: bleh bleh!
                    // Location of file: http://someplace/.
                    echo '
								<li class="package_section">', $txt['file_location'], ':&nbsp; <a href="', $package['href'], '">', $package['href'], '</a></li>
								<li class="package_section"><div class="information">', $txt['package_description'], ':&nbsp; ', $package['description'], '</div></li>
							</ul>';
                }
                $alt = !$alt;
                echo '
						</li>';
            }
            echo '
					</', $context['list_type'], '>
						</li>';
        }
        echo '
				</ul>';
    }
    echo '
			</div>
		</div>
		<div class="padding smalltext floatleft">
			', $txt['package_installed_key'], '
			<img src="', $settings['images_url'], '/icons/package_installed.gif" alt="" align="middle" style="margin-left: 1ex;" /> ', $txt['package_installed_current'], '
			<img src="', $settings['images_url'], '/icons/package_old.gif" alt="" align="middle" style="margin-left: 2ex;" /> ', $txt['package_installed_old'], '
		</div>
	</div>
	<br class="clear" />

		';
    // Now go through and turn off all the sections.
    if (!empty($context['package_list'])) {
        $section_count = count($context['package_list']);
        echo '
			<script type="text/javascript"><!-- // --><![CDATA[';
        foreach ($context['package_list'] as $section => $ps) {
            echo '';
            foreach ($ps['items'] as $id => $package) {
                if (!$package['is_text'] && !$package['is_line'] && !$package['is_remote']) {
                    echo '';
                }
            }
        }
        echo '
			// ]]></script>';
    }
}
Beispiel #5
0
function AddLanguage()
{
    global $context, $sourcedir, $forum_version, $scripturl;
    // Are we searching for new languages courtesy of Simple Machines?
    if (!empty($_POST['smf_add_sub'])) {
        // Need fetch_web_data.
        require_once $sourcedir . '/lib/Subs-Package.php';
        $context['smf_search_term'] = htmlspecialchars(trim($_POST['smf_add']));
        // We're going to use this URL.
        $url = 'http://download.simplemachines.org/fetch_language.php?version=' . urlencode(strtr($forum_version, array('SMF ' => '')));
        // Load the class file and stick it into an array.
        loadClassFile('Class-Package.php');
        $language_list = new xmlArray(fetch_web_data($url), true);
        // Check it exists.
        if (!$language_list->exists('languages')) {
            $context['smf_error'] = 'no_response';
        } else {
            $language_list = $language_list->path('languages[0]');
            $lang_files = $language_list->set('language');
            $context['smf_languages'] = array();
            foreach ($lang_files as $file) {
                // Were we searching?
                if (!empty($context['smf_search_term']) && strpos($file->fetch('name'), commonAPI::strtolower($context['smf_search_term'])) === false) {
                    continue;
                }
                $context['smf_languages'][] = array('id' => $file->fetch('id'), 'name' => commonAPI::ucwords($file->fetch('name')), 'version' => $file->fetch('version'), 'utf8' => $file->fetch('utf8'), 'description' => $file->fetch('description'), 'link' => $scripturl . '?action=admin;area=languages;sa=downloadlang;did=' . $file->fetch('id') . ';' . $context['session_var'] . '=' . $context['session_id']);
            }
            if (empty($context['smf_languages'])) {
                $context['smf_error'] = 'no_files';
            }
        }
    }
    $context['sub_template'] = 'add_language';
}
Beispiel #6
0
function MembergroupMembers()
{
    global $txt, $scripturl, $context, $modSettings, $sourcedir, $user_info, $settings, $smcFunc;
    $_REQUEST['group'] = isset($_REQUEST['group']) ? (int) $_REQUEST['group'] : 0;
    // No browsing of guests, membergroup 0 or moderators.
    if (in_array($_REQUEST['group'], array(-1, 0, 3))) {
        fatal_lang_error('membergroup_does_not_exist', false);
    }
    // Load up the group details.
    $request = smf_db_query('
		SELECT id_group AS id, group_name AS name, CASE WHEN min_posts = {int:min_posts} THEN 1 ELSE 0 END AS assignable, hidden, online_color,
			stars, description, CASE WHEN min_posts != {int:min_posts} THEN 1 ELSE 0 END AS is_post_group, group_type
		FROM {db_prefix}membergroups
		WHERE id_group = {int:id_group}
		LIMIT 1', array('min_posts' => -1, 'id_group' => $_REQUEST['group']));
    // Doesn't exist?
    if (mysql_num_rows($request) == 0) {
        fatal_lang_error('membergroup_does_not_exist', false);
    }
    $context['group'] = mysql_fetch_assoc($request);
    mysql_free_result($request);
    // Fix the stars.
    $context['group']['stars'] = explode('#', $context['group']['stars']);
    $context['group']['stars'] = !empty($context['group']['stars'][0]) && !empty($context['group']['stars'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/' . $context['group']['stars'][1] . '" alt="*" />', $context['group']['stars'][0]) : '';
    $context['group']['can_moderate'] = allowedTo('manage_membergroups') && (allowedTo('admin_forum') || $context['group']['group_type'] != 1);
    $context['linktree'][] = array('url' => $scripturl . '?action=groups;sa=members;group=' . $context['group']['id'], 'name' => $context['group']['name']);
    // Load all the group moderators, for fun.
    $request = smf_db_query('
		SELECT mem.id_member, mem.real_name
		FROM {db_prefix}group_moderators AS mods
			INNER JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
		WHERE mods.id_group = {int:id_group}', array('id_group' => $_REQUEST['group']));
    $context['group']['moderators'] = array();
    while ($row = mysql_fetch_assoc($request)) {
        $context['group']['moderators'][] = array('id' => $row['id_member'], 'name' => $row['real_name']);
        if ($user_info['id'] == $row['id_member'] && $context['group']['group_type'] != 1) {
            $context['group']['can_moderate'] = true;
        }
    }
    mysql_free_result($request);
    // If this group is hidden then it can only "exists" if the user can moderate it!
    if ($context['group']['hidden'] && !$context['group']['can_moderate']) {
        fatal_lang_error('membergroup_does_not_exist', false);
    }
    // You can only assign membership if you are the moderator and/or can manage groups!
    if (!$context['group']['can_moderate']) {
        $context['group']['assignable'] = 0;
    } elseif ($context['group']['id'] == 1 && !allowedTo('admin_forum')) {
        $context['group']['assignable'] = 0;
    }
    // Removing member from group?
    if (isset($_POST['remove']) && !empty($_REQUEST['rem']) && is_array($_REQUEST['rem']) && $context['group']['assignable']) {
        checkSession();
        // Make sure we're dealing with integers only.
        foreach ($_REQUEST['rem'] as $key => $group) {
            $_REQUEST['rem'][$key] = (int) $group;
        }
        require_once $sourcedir . '/lib/Subs-Membergroups.php';
        removeMembersFromGroups($_REQUEST['rem'], $_REQUEST['group'], true);
    } elseif (isset($_REQUEST['add']) && (!empty($_REQUEST['toAdd']) || !empty($_REQUEST['member_add'])) && $context['group']['assignable']) {
        checkSession();
        $member_query = array();
        $member_parameters = array();
        // Get all the members to be added... taking into account names can be quoted ;)
        $_REQUEST['toAdd'] = strtr(commonAPI::htmlspecialchars($_REQUEST['toAdd'], ENT_QUOTES), array('&quot;' => '"'));
        preg_match_all('~"([^"]+)"~', $_REQUEST['toAdd'], $matches);
        $member_names = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_REQUEST['toAdd']))));
        foreach ($member_names as $index => $member_name) {
            $member_names[$index] = trim(commonAPI::strtolower($member_names[$index]));
            if (strlen($member_names[$index]) == 0) {
                unset($member_names[$index]);
            }
        }
        // Any passed by ID?
        $member_ids = array();
        if (!empty($_REQUEST['member_add'])) {
            foreach ($_REQUEST['member_add'] as $id) {
                if ($id > 0) {
                    $member_ids[] = (int) $id;
                }
            }
        }
        // Construct the query pelements.
        if (!empty($member_ids)) {
            $member_query[] = 'id_member IN ({array_int:member_ids})';
            $member_parameters['member_ids'] = $member_ids;
        }
        if (!empty($member_names)) {
            $member_query[] = 'LOWER(member_name) IN ({array_string:member_names})';
            $member_query[] = 'LOWER(real_name) IN ({array_string:member_names})';
            $member_parameters['member_names'] = $member_names;
        }
        $members = array();
        if (!empty($member_query)) {
            $request = smf_db_query('
				SELECT id_member
				FROM {db_prefix}members
				WHERE (' . implode(' OR ', $member_query) . ')
					AND id_group != {int:id_group}
					AND FIND_IN_SET({int:id_group}, additional_groups) = 0', array_merge($member_parameters, array('id_group' => $_REQUEST['group'])));
            while ($row = mysql_fetch_assoc($request)) {
                $members[] = $row['id_member'];
            }
            mysql_free_result($request);
        }
        // !!! Add $_POST['additional'] to templates!
        // Do the updates...
        if (!empty($members)) {
            require_once $sourcedir . '/lib/Subs-Membergroups.php';
            addMembersToGroup($members, $_REQUEST['group'], isset($_POST['additional']) || $context['group']['hidden'] ? 'only_additional' : 'auto', true);
        }
    }
    // Sort out the sorting!
    $sort_methods = array('name' => 'real_name', 'email' => allowedTo('moderate_forum') ? 'email_address' : 'hide_email ' . (isset($_REQUEST['desc']) ? 'DESC' : 'ASC') . ', email_address', 'active' => 'last_login', 'registered' => 'date_registered', 'posts' => 'posts');
    // They didn't pick one, default to by name..
    if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
        $context['sort_by'] = 'name';
        $querySort = 'real_name';
    } else {
        $context['sort_by'] = $_REQUEST['sort'];
        $querySort = $sort_methods[$_REQUEST['sort']];
    }
    $context['sort_direction'] = isset($_REQUEST['desc']) ? 'down' : 'up';
    // The where on the query is interesting. Non-moderators should only see people who are in this group as primary.
    if ($context['group']['can_moderate']) {
        $where = $context['group']['is_post_group'] ? 'id_post_group = {int:group}' : 'id_group = {int:group} OR FIND_IN_SET({int:group}, additional_groups) != 0';
    } else {
        $where = $context['group']['is_post_group'] ? 'id_post_group = {int:group}' : 'id_group = {int:group}';
    }
    // Count members of the group.
    $request = smf_db_query('
		SELECT COUNT(*)
		FROM {db_prefix}members
		WHERE ' . $where, array('group' => $_REQUEST['group']));
    list($context['total_members']) = mysql_fetch_row($request);
    mysql_free_result($request);
    $context['total_members'] = comma_format($context['total_members']);
    // Create the page index.
    $context['page_index'] = constructPageIndex($scripturl . '?action=' . ($context['group']['can_moderate'] ? 'moderate;area=viewgroups' : 'groups') . ';sa=members;group=' . $_REQUEST['group'] . ';sort=' . $context['sort_by'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $context['total_members'], $modSettings['defaultMaxMembers']);
    $context['start'] = $_REQUEST['start'];
    $context['can_moderate_forum'] = allowedTo('moderate_forum');
    // Load up all members of this group.
    $request = smf_db_query('
		SELECT id_member, member_name, real_name, email_address, member_ip, date_registered, last_login,
			hide_email, posts, is_activated, real_name
		FROM {db_prefix}members
		WHERE ' . $where . '
		ORDER BY ' . $querySort . ' ' . ($context['sort_direction'] == 'down' ? 'DESC' : 'ASC') . '
		LIMIT ' . $context['start'] . ', ' . $modSettings['defaultMaxMembers'], array('group' => $_REQUEST['group']));
    $context['members'] = array();
    while ($row = mysql_fetch_assoc($request)) {
        $last_online = empty($row['last_login']) ? $txt['never'] : timeformat($row['last_login']);
        // Italicize the online note if they aren't activated.
        if ($row['is_activated'] % 10 != 1) {
            $last_online = '<em title="' . $txt['not_activated'] . '">' . $last_online . '</em>';
        }
        $context['members'][] = array('id' => $row['id_member'], 'name' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>', 'email' => $row['email_address'], 'show_email' => showEmailAddress(!empty($row['hide_email']), $row['id_member']), 'ip' => '<a href="' . $scripturl . '?action=trackip;searchip=' . $row['member_ip'] . '">' . $row['member_ip'] . '</a>', 'registered' => timeformat($row['date_registered']), 'last_online' => $last_online, 'posts' => comma_format($row['posts']), 'is_activated' => $row['is_activated'] % 10 == 1);
    }
    mysql_free_result($request);
    if (isset($_REQUEST['action']) && $_REQUEST['action'] === 'moderate') {
        EoS_Smarty::loadTemplate('modcenter/modcenter_base');
        EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'admin/group_list_members');
    } else {
        $context['sub_template'] = 'group_members';
    }
    $context['page_title'] = $txt['membergroups_members_title'] . ': ' . $context['group']['name'];
}
Beispiel #7
0
function validatePassword($password, $username, $restrict_in = array())
{
    global $modSettings, $smcFunc;
    // Perform basic requirements first.
    if (commonAPI::strlen($password) < (empty($modSettings['password_strength']) ? 4 : 8)) {
        return 'short';
    }
    // Is this enough?
    if (empty($modSettings['password_strength'])) {
        return null;
    }
    // Otherwise, perform the medium strength test - checking if password appears in the restricted string.
    if (preg_match('~\\b' . preg_quote($password, '~') . '\\b~', implode(' ', $restrict_in)) != 0) {
        return 'restricted_words';
    } elseif (commonAPI::strpos($password, $username) !== false) {
        return 'restricted_words';
    }
    // !!! If pspell is available, use it on the word, and return restricted_words if it doesn't give "bad spelling"?
    // If just medium, we're done.
    if ($modSettings['password_strength'] == 1) {
        return null;
    }
    // Otherwise, hard test next, check for numbers and letters, uppercase too.
    $good = preg_match('~(\\D\\d|\\d\\D)~', $password) != 0;
    $good &= commonAPI::strtolower($password) != $password;
    return $good ? null : 'chars';
}
Beispiel #8
0
function ModifySpamSettings($return_config = false)
{
    global $txt, $scripturl, $context, $settings, $sc, $modSettings, $smcFunc;
    // Generate a sample registration image.
    $context['use_graphic_library'] = in_array('gd', get_loaded_extensions());
    $context['verification_image_href'] = $scripturl . '?action=verificationcode;rand=' . md5(mt_rand());
    $config_vars = array(array('check', 'reg_verification'), array('check', 'search_enable_captcha'), 'guest_verify' => array('check', 'guests_require_captcha', 'subtext' => $txt['setting_guests_require_captcha_desc']), array('int', 'posts_require_captcha', 'subtext' => $txt['posts_require_captcha_desc'], 'onchange' => 'if (this.value > 0){ document.getElementById(\'guests_require_captcha\').checked = true; document.getElementById(\'guests_require_captcha\').disabled = true;} else {document.getElementById(\'guests_require_captcha\').disabled = false;}'), array('check', 'guests_report_require_captcha'), '', 'pm1' => array('int', 'max_pm_recipients'), 'pm2' => array('int', 'pm_posts_verification'), 'pm3' => array('int', 'pm_posts_per_hour'), array('title', 'configure_verification_means'), array('desc', 'configure_verification_means_desc'), 'vv' => array('select', 'visual_verification_type', array($txt['setting_image_verification_off'], $txt['setting_image_verification_vsimple'], $txt['setting_image_verification_simple'], $txt['setting_image_verification_medium'], $txt['setting_image_verification_high'], $txt['setting_image_verification_extreme']), 'subtext' => $txt['setting_visual_verification_type_desc'], 'onchange' => $context['use_graphic_library'] ? 'refreshImages();' : ''), array('int', 'qa_verification_number', 'subtext' => $txt['setting_qa_verification_number_desc']), array('title', 'setup_verification_questions'), array('desc', 'setup_verification_questions_desc'), array('callback', 'question_answer_list'));
    if ($return_config) {
        return $config_vars;
    }
    // Load any question and answers!
    $context['question_answers'] = array();
    $request = smf_db_query('
		SELECT id_comment, body AS question, recipient_name AS answer
		FROM {db_prefix}log_comments
		WHERE comment_type = {string:ver_test}', array('ver_test' => 'ver_test'));
    while ($row = mysql_fetch_assoc($request)) {
        $context['question_answers'][$row['id_comment']] = array('id' => $row['id_comment'], 'question' => $row['question'], 'answer' => $row['answer']);
    }
    mysql_free_result($request);
    // Saving?
    if (isset($_GET['save'])) {
        checkSession();
        // Fix PM settings.
        $_POST['pm_spam_settings'] = (int) $_POST['max_pm_recipients'] . ',' . (int) $_POST['pm_posts_verification'] . ',' . (int) $_POST['pm_posts_per_hour'];
        // Hack in guest requiring verification!
        if (empty($_POST['posts_require_captcha']) && !empty($_POST['guests_require_captcha'])) {
            $_POST['posts_require_captcha'] = -1;
        }
        $save_vars = $config_vars;
        unset($save_vars['pm1'], $save_vars['pm2'], $save_vars['pm3'], $save_vars['guest_verify']);
        $save_vars[] = array('text', 'pm_spam_settings');
        // Handle verification questions.
        $questionInserts = array();
        $count_questions = 0;
        foreach ($_POST['question'] as $id => $question) {
            $question = trim(commonAPI::htmlspecialchars($question, ENT_COMPAT));
            $answer = trim(commonAPI::strtolower(commonAPI::htmlspecialchars($_POST['answer'][$id], ENT_COMPAT)));
            // Already existed?
            if (isset($context['question_answers'][$id])) {
                $count_questions++;
                // Changed?
                if ($context['question_answers'][$id]['question'] != $question || $context['question_answers'][$id]['answer'] != $answer) {
                    if ($question == '' || $answer == '') {
                        smf_db_query('
							DELETE FROM {db_prefix}log_comments
							WHERE comment_type = {string:ver_test}
								AND id_comment = {int:id}', array('id' => $id, 'ver_test' => 'ver_test'));
                        $count_questions--;
                    } else {
                        $request = smf_db_query('
							UPDATE {db_prefix}log_comments
							SET body = {string:question}, recipient_name = {string:answer}
							WHERE comment_type = {string:ver_test}
								AND id_comment = {int:id}', array('id' => $id, 'ver_test' => 'ver_test', 'question' => $question, 'answer' => $answer));
                    }
                }
            } elseif ($question != '' && $answer != '') {
                $questionInserts[] = array('comment_type' => 'ver_test', 'body' => $question, 'recipient_name' => $answer);
            }
        }
        // Any questions to insert?
        if (!empty($questionInserts)) {
            smf_db_insert('', '{db_prefix}log_comments', array('comment_type' => 'string', 'body' => 'string-65535', 'recipient_name' => 'string-80'), $questionInserts, array('id_comment'));
            $count_questions++;
        }
        if (empty($count_questions) || $_POST['qa_verification_number'] > $count_questions) {
            $_POST['qa_verification_number'] = $count_questions;
        }
        // Now save.
        saveDBSettings($save_vars);
        CacheAPI::putCache('verificationQuestionIds', null, 300);
        redirectexit('action=admin;area=securitysettings;sa=spam');
    }
    $character_range = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P', 'R'), range('T', 'Y'));
    $_SESSION['visual_verification_code'] = '';
    for ($i = 0; $i < 6; $i++) {
        $_SESSION['visual_verification_code'] .= $character_range[array_rand($character_range)];
    }
    // Some javascript for CAPTCHA.
    $context['settings_post_javascript'] = '';
    if ($context['use_graphic_library']) {
        $context['settings_post_javascript'] .= '
		function refreshImages()
		{
			var imageType = document.getElementById(\'visual_verification_type\').value;
			document.getElementById(\'verification_image\').src = \'' . $context['verification_image_href'] . ';type=\' + imageType;
		}';
    }
    // Show the image itself, or text saying we can't.
    if ($context['use_graphic_library']) {
        $config_vars['vv']['postinput'] = '<br /><img src="' . $context['verification_image_href'] . ';type=' . (empty($modSettings['visual_verification_type']) ? 0 : $modSettings['visual_verification_type']) . '" alt="' . $txt['setting_image_verification_sample'] . '" id="verification_image" /><br />';
    } else {
        $config_vars['vv']['postinput'] = '<br /><span class="smalltext">' . $txt['setting_image_verification_nogd'] . '</span>';
    }
    // Hack for PM spam settings.
    list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
    // Hack for guests requiring verification.
    $modSettings['guests_require_captcha'] = !empty($modSettings['posts_require_captcha']);
    $modSettings['posts_require_captcha'] = !isset($modSettings['posts_require_captcha']) || $modSettings['posts_require_captcha'] == -1 ? 0 : $modSettings['posts_require_captcha'];
    // Some minor javascript for the guest post setting.
    if ($modSettings['posts_require_captcha']) {
        $context['settings_post_javascript'] .= '
		document.getElementById(\'guests_require_captcha\').disabled = true;';
    }
    $context['post_url'] = $scripturl . '?action=admin;area=securitysettings;save;sa=spam';
    $context['settings_title'] = $txt['antispam_Settings'];
    prepareDBSettingContext($config_vars);
}
Beispiel #9
0
function MLAll()
{
    global $txt, $scripturl, $user_info;
    global $modSettings, $context, $smcFunc;
    // The chunk size for the cached index.
    $cache_step_size = 500;
    // Only use caching if:
    // 1. there are at least 2k members,
    // 2. the default sorting method (real_name) is being used,
    // 3. the page shown is high enough to make a DB filesort unprofitable.
    $use_cache = $modSettings['totalMembers'] > 2000 && (!isset($_REQUEST['sort']) || $_REQUEST['sort'] === 'real_name') && isset($_REQUEST['start']) && $_REQUEST['start'] > $cache_step_size;
    if ($use_cache) {
        // Maybe there's something cached already.
        if (!empty($modSettings['memberlist_cache'])) {
            $memberlist_cache = @unserialize($modSettings['memberlist_cache']);
        }
        // The chunk size for the cached index.
        $cache_step_size = 500;
        // Only update the cache if something changed or no cache existed yet.
        if (empty($memberlist_cache) || empty($modSettings['memberlist_updated']) || $memberlist_cache['last_update'] < $modSettings['memberlist_updated']) {
            $request = smf_db_query('
				SELECT real_name
				FROM {db_prefix}members
				WHERE is_activated = {int:is_activated}
				ORDER BY real_name', array('is_activated' => 1));
            $memberlist_cache = array('last_update' => time(), 'num_members' => mysql_num_rows($request), 'index' => array());
            for ($i = 0, $n = mysql_num_rows($request); $i < $n; $i += $cache_step_size) {
                mysql_data_seek($request, $i);
                list($memberlist_cache['index'][$i]) = mysql_fetch_row($request);
            }
            mysql_data_seek($request, $memberlist_cache['num_members'] - 1);
            list($memberlist_cache['index'][$i]) = mysql_fetch_row($request);
            mysql_free_result($request);
            // Now we've got the cache...store it.
            updateSettings(array('memberlist_cache' => serialize($memberlist_cache)));
        }
        $context['num_members'] = $memberlist_cache['num_members'];
    } else {
        $request = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}members
			WHERE is_activated = {int:is_activated}', array('is_activated' => 1));
        list($context['num_members']) = mysql_fetch_row($request);
        mysql_free_result($request);
    }
    // Set defaults for sort (real_name) and start. (0)
    if (!isset($_REQUEST['sort']) || !isset($context['columns'][$_REQUEST['sort']])) {
        $_REQUEST['sort'] = 'real_name';
    }
    if (!is_numeric($_REQUEST['start'])) {
        if (preg_match('~^[^\'\\\\/]~u', commonAPI::strtolower($_REQUEST['start']), $match) === 0) {
            fatal_error('Hacker?', false);
        }
        $_REQUEST['start'] = $match[0];
        $request = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}members
			WHERE LOWER(SUBSTRING(real_name, 1, 1)) < {string:first_letter}
				AND is_activated = {int:is_activated}', array('is_activated' => 1, 'first_letter' => $_REQUEST['start']));
        list($_REQUEST['start']) = mysql_fetch_row($request);
        mysql_free_result($request);
    }
    $context['letter_links'] = '';
    for ($i = 97; $i < 123; $i++) {
        $context['letter_links'] .= '<a href="' . $scripturl . '?action=mlist;sa=all;start=' . chr($i) . '#letter' . chr($i) . '">' . strtoupper(chr($i)) . '</a> ';
    }
    // Sort out the column information.
    foreach ($context['columns'] as $col => $column_details) {
        $context['columns'][$col]['href'] = $scripturl . '?action=mlist;sort=' . $col . ';start=0';
        if (!isset($_REQUEST['desc']) && $col == $_REQUEST['sort'] || $col != $_REQUEST['sort'] && !empty($column_details['default_sort_rev'])) {
            $context['columns'][$col]['href'] .= ';desc';
        }
        $context['columns'][$col]['link'] = '<a href="' . $context['columns'][$col]['href'] . '" rel="nofollow">' . $context['columns'][$col]['label'] . '</a>';
        $context['columns'][$col]['selected'] = $_REQUEST['sort'] == $col;
    }
    $context['sort_by'] = $_REQUEST['sort'];
    $context['sort_direction'] = !isset($_REQUEST['desc']) ? 'up' : 'down';
    // Construct the page index.
    $context['page_index'] = constructPageIndex($scripturl . '?action=mlist;sort=' . $_REQUEST['sort'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $context['num_members'], $modSettings['defaultMaxMembers']);
    // Send the data to the template.
    $context['start'] = $_REQUEST['start'] + 1;
    $context['end'] = min($_REQUEST['start'] + $modSettings['defaultMaxMembers'], $context['num_members']);
    $context['can_moderate_forum'] = allowedTo('moderate_forum');
    $context['page_title'] = sprintf($txt['viewing_members'], $context['start'], $context['end']);
    $context['linktree'][] = array('url' => $scripturl . '?action=mlist;sort=' . $_REQUEST['sort'] . ';start=' . $_REQUEST['start'], 'name' => &$context['page_title'], 'extra_after' => ' (' . sprintf($txt['of_total_members'], $context['num_members']) . ')');
    // List out the different sorting methods...
    $sort_methods = array('is_online' => array('down' => allowedTo('moderate_forum') ? 'IFNULL(lo.log_time, 1) ASC, real_name ASC' : 'IF(mem.show_online, IFNULL(lo.log_time, 1), 1) ASC, real_name ASC', 'up' => allowedTo('moderate_forum') ? 'IFNULL(lo.log_time, 1) DESC, real_name DESC' : 'IF(mem.show_online, IFNULL(lo.log_time, 1), 1) DESC, real_name DESC'), 'real_name' => array('down' => 'mem.real_name DESC', 'up' => 'mem.real_name ASC'), 'email_address' => array('down' => allowedTo('moderate_forum') ? 'mem.email_address DESC' : 'mem.hide_email DESC, mem.email_address DESC', 'up' => allowedTo('moderate_forum') ? 'mem.email_address ASC' : 'mem.hide_email ASC, mem.email_address ASC'), 'registered' => array('down' => 'mem.date_registered DESC', 'up' => 'mem.date_registered ASC'), 'id_group' => array('down' => 'IFNULL(mg.group_name, 1=1) DESC, mg.group_name DESC', 'up' => 'IFNULL(mg.group_name, 1=1) ASC, mg.group_name ASC'), 'posts' => array('down' => 'mem.posts DESC', 'up' => 'mem.posts ASC'));
    $limit = $_REQUEST['start'];
    $query_parameters = array('regular_id_group' => 0, 'is_activated' => 1, 'sort' => $sort_methods[$_REQUEST['sort']][$context['sort_direction']]);
    // Using cache allows to narrow down the list to be retrieved.
    if ($use_cache && $_REQUEST['sort'] === 'real_name' && !isset($_REQUEST['desc'])) {
        $first_offset = $_REQUEST['start'] - $_REQUEST['start'] % $cache_step_size;
        $second_offset = ceil(($_REQUEST['start'] + $modSettings['defaultMaxMembers']) / $cache_step_size) * $cache_step_size;
        $where = 'mem.real_name BETWEEN {string:real_name_low} AND {string:real_name_high}';
        $query_parameters['real_name_low'] = $memberlist_cache['index'][$first_offset];
        $query_parameters['real_name_high'] = $memberlist_cache['index'][$second_offset];
        $limit -= $first_offset;
    } elseif ($use_cache && $_REQUEST['sort'] === 'real_name') {
        $first_offset = floor(($memberlist_cache['num_members'] - $modSettings['defaultMaxMembers'] - $_REQUEST['start']) / $cache_step_size) * $cache_step_size;
        if ($first_offset < 0) {
            $first_offset = 0;
        }
        $second_offset = ceil(($memberlist_cache['num_members'] - $_REQUEST['start']) / $cache_step_size) * $cache_step_size;
        $where = 'mem.real_name BETWEEN {string:real_name_low} AND {string:real_name_high}';
        $query_parameters['real_name_low'] = $memberlist_cache['index'][$first_offset];
        $query_parameters['real_name_high'] = $memberlist_cache['index'][$second_offset];
        $limit = $second_offset - ($memberlist_cache['num_members'] - $_REQUEST['start']) - ($second_offset > $memberlist_cache['num_members'] ? $cache_step_size - $memberlist_cache['num_members'] % $cache_step_size : 0);
    }
    // Select the members from the database.
    $request = smf_db_query('
		SELECT mem.id_member
		FROM {db_prefix}members AS mem' . ($_REQUEST['sort'] === 'is_online' ? '
			LEFT JOIN {db_prefix}log_online AS lo ON (lo.id_member = mem.id_member)' : '') . ($_REQUEST['sort'] === 'id_group' ? '
			LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:regular_id_group} THEN mem.id_post_group ELSE mem.id_group END)' : '') . '
		WHERE mem.is_activated = {int:is_activated}' . (empty($where) ? '' : '
			AND ' . $where) . '
		ORDER BY {raw:sort}
		LIMIT ' . $limit . ', ' . $modSettings['defaultMaxMembers'], $query_parameters);
    printMemberListRows($request);
    mysql_free_result($request);
    // Add anchors at the start of each letter.
    if ($_REQUEST['sort'] == 'real_name') {
        $last_letter = '';
        foreach ($context['members'] as $i => $dummy) {
            $this_letter = commonAPI::strtolower(commonAPI::substr($context['members'][$i]['name'], 0, 1));
            if ($this_letter != $last_letter && preg_match('~[a-z]~', $this_letter) === 1) {
                $context['members'][$i]['sort_letter'] = htmlspecialchars($this_letter);
                $last_letter = $this_letter;
            }
        }
    }
}
Beispiel #10
0
function ThemeInstall()
{
    global $sourcedir, $boarddir, $boardurl, $txt, $context, $settings, $modSettings, $smcFunc;
    checkSession('request');
    isAllowedTo('admin_forum');
    checkSession('request');
    require_once $sourcedir . '/lib/Subs-Package.php';
    loadTemplate('Themes');
    if (isset($_GET['theme_id'])) {
        $result = smf_db_query('
			SELECT value
			FROM {db_prefix}themes
			WHERE id_theme = {int:current_theme}
				AND id_member = {int:no_member}
				AND variable = {string:name}
			LIMIT 1', array('current_theme' => (int) $_GET['theme_id'], 'no_member' => 0, 'name' => 'name'));
        list($theme_name) = mysql_fetch_row($result);
        mysql_free_result($result);
        $context['sub_template'] = 'installed';
        $context['page_title'] = $txt['theme_installed'];
        $context['installed_theme'] = array('id' => (int) $_GET['theme_id'], 'name' => $theme_name);
        return;
    }
    if (!empty($_FILES['theme_gz']) && (!isset($_FILES['theme_gz']['error']) || $_FILES['theme_gz']['error'] != 4) || !empty($_REQUEST['theme_gz'])) {
        $method = 'upload';
    } elseif (isset($_REQUEST['theme_dir']) && rtrim(realpath($_REQUEST['theme_dir']), '/\\') != realpath($boarddir . '/Themes') && file_exists($_REQUEST['theme_dir'])) {
        $method = 'path';
    } else {
        $method = 'copy';
    }
    if (!empty($_REQUEST['copy']) && $method == 'copy') {
        // Hopefully the themes directory is writable, or we might have a problem.
        if (!is_writable($boarddir . '/Themes')) {
            fatal_lang_error('theme_install_write_error', 'critical');
        }
        $theme_dir = $boarddir . '/Themes/' . preg_replace('~[^A-Za-z0-9_\\- ]~', '', $_REQUEST['copy']);
        umask(0);
        mkdir($theme_dir, 0777);
        @set_time_limit(600);
        if (function_exists('apache_reset_timeout')) {
            @apache_reset_timeout();
        }
        // Create subdirectories for css and javascript files.
        mkdir($theme_dir . '/css', 0777);
        mkdir($theme_dir . '/scripts', 0777);
        // Copy over the default non-theme files.
        $to_copy = array('/index.php', '/index.template.php', '/css/index.css', '/css/rtl.css', '/scripts/theme.js');
        foreach ($to_copy as $file) {
            copy($settings['default_theme_dir'] . $file, $theme_dir . $file);
            @chmod($theme_dir . $file, 0777);
        }
        // And now the entire images directory!
        copytree($settings['default_theme_dir'] . '/images', $theme_dir . '/images');
        package_flush_cache();
        $theme_name = $_REQUEST['copy'];
        $images_url = $boardurl . '/Themes/' . basename($theme_dir) . '/images';
        $theme_dir = realpath($theme_dir);
        // Lets get some data for the new theme.
        $request = smf_db_query('
			SELECT variable, value
			FROM {db_prefix}themes
			WHERE variable IN ({string:theme_templates}, {string:theme_layers})
				AND id_member = {int:no_member}
				AND id_theme = {int:default_theme}', array('no_member' => 0, 'default_theme' => 1, 'theme_templates' => 'theme_templates', 'theme_layers' => 'theme_layers'));
        while ($row = mysql_fetch_assoc($request)) {
            if ($row['variable'] == 'theme_templates') {
                $theme_templates = $row['value'];
            } elseif ($row['variable'] == 'theme_layers') {
                $theme_layers = $row['value'];
            } else {
                continue;
            }
        }
        mysql_free_result($request);
        // Lets add a theme_info.xml to this theme.
        $xml_info = '<' . '?xml version="1.0"?' . '>
<theme-info xmlns="http://www.simplemachines.org/xml/theme-info" xmlns:smf="http://www.simplemachines.org/">
	<!-- For the id, always use something unique - put your name, a colon, and then the package name. -->
	<id>smf:' . commonAPI::strtolower(str_replace(array(' '), '_', $_REQUEST['copy'])) . '</id>
	<version>' . $modSettings['smfVersion'] . '</version>
	<!-- Theme name, used purely for aesthetics. -->
	<name>' . $_REQUEST['copy'] . '</name>
	<!-- Author: your email address or contact information. The name attribute is optional. -->
	<author name="Simple Machines">info@simplemachines.org</author>
	<!-- Website... where to get updates and more information. -->
	<website>http://www.simplemachines.org/</website>
	<!-- Template layers to use, defaults to "html,body". -->
	<layers>' . (empty($theme_layers) ? 'html,body' : $theme_layers) . '</layers>
	<!-- Templates to load on startup. Default is "index". -->
	<templates>' . (empty($theme_templates) ? 'index' : $theme_templates) . '</templates>
	<!-- Base this theme off another? Default is blank, or no. It could be "default". -->
	<based-on></based-on>
</theme-info>';
        // Now write it.
        $fp = @fopen($theme_dir . '/theme_info.xml', 'w+');
        if ($fp) {
            fwrite($fp, $xml_info);
            fclose($fp);
        }
    } elseif (isset($_REQUEST['theme_dir']) && $method == 'path') {
        if (!is_dir($_REQUEST['theme_dir']) || !file_exists($_REQUEST['theme_dir'] . '/theme_info.xml')) {
            fatal_lang_error('theme_install_error', false);
        }
        $theme_name = basename($_REQUEST['theme_dir']);
        $theme_dir = $_REQUEST['theme_dir'];
    } elseif ($method = 'upload') {
        // Hopefully the themes directory is writable, or we might have a problem.
        if (!is_writable($boarddir . '/Themes')) {
            fatal_lang_error('theme_install_write_error', 'critical');
        }
        require_once $sourcedir . '/lib/Subs-Package.php';
        // Set the default settings...
        $theme_name = strtok(basename(isset($_FILES['theme_gz']) ? $_FILES['theme_gz']['name'] : $_REQUEST['theme_gz']), '.');
        $theme_name = preg_replace(array('/\\s/', '/\\.[\\.]+/', '/[^\\w_\\.\\-]/'), array('_', '.', ''), $theme_name);
        $theme_dir = $boarddir . '/Themes/' . $theme_name;
        if (isset($_FILES['theme_gz']) && is_uploaded_file($_FILES['theme_gz']['tmp_name']) && (@ini_get('open_basedir') != '' || file_exists($_FILES['theme_gz']['tmp_name']))) {
            $extracted = read_tgz_file($_FILES['theme_gz']['tmp_name'], $boarddir . '/Themes/' . $theme_name, false, true);
        } elseif (isset($_REQUEST['theme_gz'])) {
            // Check that the theme is from simplemachines.org, for now... maybe add mirroring later.
            if (preg_match('~^http://[\\w_\\-]+\\.simplemachines\\.org/~', $_REQUEST['theme_gz']) == 0 || strpos($_REQUEST['theme_gz'], 'dlattach') !== false) {
                fatal_lang_error('not_on_simplemachines');
            }
            $extracted = read_tgz_file($_REQUEST['theme_gz'], $boarddir . '/Themes/' . $theme_name, false, true);
        } else {
            redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']);
        }
    }
    // Something go wrong?
    if ($theme_dir != '' && basename($theme_dir) != 'Themes') {
        // Defaults.
        $install_info = array('theme_url' => $boardurl . '/Themes/' . basename($theme_dir), 'images_url' => isset($images_url) ? $images_url : $boardurl . '/Themes/' . basename($theme_dir) . '/images', 'theme_dir' => $theme_dir, 'name' => $theme_name);
        if (file_exists($theme_dir . '/theme_info.xml')) {
            $theme_info = file_get_contents($theme_dir . '/theme_info.xml');
            $xml_elements = array('name' => 'name', 'theme_layers' => 'layers', 'theme_templates' => 'templates', 'based_on' => 'based-on');
            foreach ($xml_elements as $var => $name) {
                if (preg_match('~<' . $name . '>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</' . $name . '>~', $theme_info, $match) == 1) {
                    $install_info[$var] = $match[1];
                }
            }
            if (preg_match('~<images>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</images>~', $theme_info, $match) == 1) {
                $install_info['images_url'] = $install_info['theme_url'] . '/' . $match[1];
                $explicit_images = true;
            }
            if (preg_match('~<extra>(?:<!\\[CDATA\\[)?(.+?)(?:\\]\\]>)?</extra>~', $theme_info, $match) == 1) {
                $install_info += unserialize($match[1]);
            }
        }
        if (isset($install_info['based_on'])) {
            if ($install_info['based_on'] == 'default') {
                $install_info['theme_url'] = $settings['default_theme_url'];
                $install_info['images_url'] = $settings['default_images_url'];
            } elseif ($install_info['based_on'] != '') {
                $install_info['based_on'] = preg_replace('~[^A-Za-z0-9\\-_ ]~', '', $install_info['based_on']);
                $request = smf_db_query('
					SELECT th.value AS base_theme_dir, th2.value AS base_theme_url' . (!empty($explicit_images) ? '' : ', th3.value AS images_url') . '
					FROM {db_prefix}themes AS th
						INNER JOIN {db_prefix}themes AS th2 ON (th2.id_theme = th.id_theme
							AND th2.id_member = {int:no_member}
							AND th2.variable = {string:theme_url})' . (!empty($explicit_images) ? '' : '
						INNER JOIN {db_prefix}themes AS th3 ON (th3.id_theme = th.id_theme
							AND th3.id_member = {int:no_member}
							AND th3.variable = {string:images_url})') . '
					WHERE th.id_member = {int:no_member}
						AND (th.value LIKE {string:based_on} OR th.value LIKE {string:based_on_path})
						AND th.variable = {string:theme_dir}
					LIMIT 1', array('no_member' => 0, 'theme_url' => 'theme_url', 'images_url' => 'images_url', 'theme_dir' => 'theme_dir', 'based_on' => '%/' . $install_info['based_on'], 'based_on_path' => '%' . "\\" . $install_info['based_on']));
                $temp = mysql_fetch_assoc($request);
                mysql_free_result($request);
                // !!! An error otherwise?
                if (is_array($temp)) {
                    $install_info = $temp + $install_info;
                    if (empty($explicit_images) && !empty($install_info['base_theme_url'])) {
                        $install_info['theme_url'] = $install_info['base_theme_url'];
                    }
                }
            }
            unset($install_info['based_on']);
        }
        // Find the newest id_theme.
        $result = smf_db_query('
			SELECT MAX(id_theme)
			FROM {db_prefix}themes', array());
        list($id_theme) = mysql_fetch_row($result);
        mysql_free_result($result);
        // This will be theme number...
        $id_theme++;
        $inserts = array();
        foreach ($install_info as $var => $val) {
            $inserts[] = array($id_theme, $var, $val);
        }
        if (!empty($inserts)) {
            smf_db_insert('insert', '{db_prefix}themes', array('id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), $inserts, array('id_theme', 'variable'));
        }
        updateSettings(array('knownThemes' => strtr($modSettings['knownThemes'] . ',' . $id_theme, array(',,' => ','))));
    }
    redirectexit('action=admin;area=theme;sa=install;theme_id=' . $id_theme . ';' . $context['session_var'] . '=' . $context['session_id']);
}
Beispiel #11
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'])));
}
Beispiel #12
0
function MessagePost2()
{
    global $txt, $context, $sourcedir;
    global $user_info, $modSettings, $scripturl, $smcFunc;
    isAllowedTo('pm_send');
    require_once $sourcedir . '/lib/Subs-Auth.php';
    loadLanguage('PersonalMessage', '', false);
    // Extract out the spam settings - it saves database space!
    list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
    // Check whether we've gone over the limit of messages we can send per hour - fatal error if fails!
    if (!empty($modSettings['pm_posts_per_hour']) && !allowedTo(array('admin_forum', 'moderate_forum', 'send_mail')) && $user_info['mod_cache']['bq'] == '0=1' && $user_info['mod_cache']['gq'] == '0=1') {
        // How many have they sent this last hour?
        $request = smf_db_query('
			SELECT COUNT(pr.id_pm) AS post_count
			FROM {db_prefix}personal_messages AS pm
				INNER JOIN {db_prefix}pm_recipients AS pr ON (pr.id_pm = pm.id_pm)
			WHERE pm.id_member_from = {int:current_member}
				AND pm.msgtime > {int:msgtime}', array('current_member' => $user_info['id'], 'msgtime' => time() - 3600));
        list($postCount) = mysql_fetch_row($request);
        mysql_free_result($request);
        if (!empty($postCount) && $postCount >= $modSettings['pm_posts_per_hour']) {
            fatal_lang_error('pm_too_many_per_hour', true, array($modSettings['pm_posts_per_hour']));
        }
    }
    // If we came from WYSIWYG then turn it back into BBC regardless.
    if (!empty($_POST['message_mode']) && isset($_POST['message'])) {
        require_once $sourcedir . '/lib/Subs-Editor.php';
        $_POST['message'] = html_to_bbc($_POST['message']);
        // We need to unhtml it now as it gets done shortly.
        $_POST['message'] = un_htmlspecialchars($_POST['message']);
        // We need this in case of errors etc.
        $_REQUEST['message'] = $_POST['message'];
    }
    // Initialize the errors we're about to make.
    $post_errors = array();
    // If your session timed out, show an error, but do allow to re-submit.
    if (checkSession('post', '', false) != '') {
        $post_errors[] = 'session_timeout';
    }
    $_REQUEST['subject'] = isset($_REQUEST['subject']) ? trim($_REQUEST['subject']) : '';
    $_REQUEST['to'] = empty($_POST['to']) ? empty($_GET['to']) ? '' : $_GET['to'] : $_POST['to'];
    $_REQUEST['bcc'] = empty($_POST['bcc']) ? empty($_GET['bcc']) ? '' : $_GET['bcc'] : $_POST['bcc'];
    // Route the input from the 'u' parameter to the 'to'-list.
    if (!empty($_POST['u'])) {
        $_POST['recipient_to'] = explode(',', $_POST['u']);
    }
    // Construct the list of recipients.
    $recipientList = array();
    $namedRecipientList = array();
    $namesNotFound = array();
    foreach (array('to', 'bcc') as $recipientType) {
        // First, let's see if there's user ID's given.
        $recipientList[$recipientType] = array();
        if (!empty($_POST['recipient_' . $recipientType]) && is_array($_POST['recipient_' . $recipientType])) {
            foreach ($_POST['recipient_' . $recipientType] as $recipient) {
                $recipientList[$recipientType][] = (int) $recipient;
            }
        }
        // Are there also literal names set?
        if (!empty($_REQUEST[$recipientType])) {
            // We're going to take out the "s anyway ;).
            $recipientString = strtr($_REQUEST[$recipientType], array('\\"' => '"'));
            preg_match_all('~"([^"]+)"~', $recipientString, $matches);
            $namedRecipientList[$recipientType] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $recipientString))));
            foreach ($namedRecipientList[$recipientType] as $index => $recipient) {
                if (strlen(trim($recipient)) > 0) {
                    $namedRecipientList[$recipientType][$index] = commonAPI::htmlspecialchars(commonAPI::strtolower(trim($recipient)));
                } else {
                    unset($namedRecipientList[$recipientType][$index]);
                }
            }
            if (!empty($namedRecipientList[$recipientType])) {
                $foundMembers = findMembers($namedRecipientList[$recipientType]);
                // Assume all are not found, until proven otherwise.
                $namesNotFound[$recipientType] = $namedRecipientList[$recipientType];
                foreach ($foundMembers as $member) {
                    $testNames = array(commonAPI::strtolower($member['username']), commonAPI::strtolower($member['name']), commonAPI::strtolower($member['email']));
                    if (count(array_intersect($testNames, $namedRecipientList[$recipientType])) !== 0) {
                        $recipientList[$recipientType][] = $member['id'];
                        // Get rid of this username, since we found it.
                        $namesNotFound[$recipientType] = array_diff($namesNotFound[$recipientType], $testNames);
                    }
                }
            }
        }
        // Selected a recipient to be deleted? Remove them now.
        if (!empty($_POST['delete_recipient'])) {
            $recipientList[$recipientType] = array_diff($recipientList[$recipientType], array((int) $_POST['delete_recipient']));
        }
        // Make sure we don't include the same name twice
        $recipientList[$recipientType] = array_unique($recipientList[$recipientType]);
    }
    // Are we changing the recipients some how?
    $is_recipient_change = !empty($_POST['delete_recipient']) || !empty($_POST['to_submit']) || !empty($_POST['bcc_submit']);
    // Check if there's at least one recipient.
    if (empty($recipientList['to']) && empty($recipientList['bcc'])) {
        $post_errors[] = 'no_to';
    }
    // Make sure that we remove the members who did get it from the screen.
    if (!$is_recipient_change) {
        foreach ($recipientList as $recipientType => $dummy) {
            if (!empty($namesNotFound[$recipientType])) {
                $post_errors[] = 'bad_' . $recipientType;
                // Since we already have a post error, remove the previous one.
                $post_errors = array_diff($post_errors, array('no_to'));
                foreach ($namesNotFound[$recipientType] as $name) {
                    $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
                }
            }
        }
    }
    // Did they make any mistakes?
    if ($_REQUEST['subject'] == '') {
        $post_errors[] = 'no_subject';
    }
    if (!isset($_REQUEST['message']) || $_REQUEST['message'] == '') {
        $post_errors[] = 'no_message';
    } elseif (!empty($modSettings['max_messageLength']) && commonAPI::strlen($_REQUEST['message']) > $modSettings['max_messageLength']) {
        $post_errors[] = 'long_message';
    } else {
        // Preparse the message.
        $message = $_REQUEST['message'];
        preparsecode($message);
        // Make sure there's still some content left without the tags.
        if (commonAPI::htmltrim(strip_tags(parse_bbc(commonAPI::htmlspecialchars($message, ENT_QUOTES), false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($message, '[html]') === false)) {
            $post_errors[] = 'no_message';
        }
    }
    // Wrong verification code?
    if (!$user_info['is_admin'] && !empty($modSettings['pm_posts_verification']) && $user_info['posts'] < $modSettings['pm_posts_verification']) {
        require_once $sourcedir . '/lib/Subs-Editor.php';
        $verificationOptions = array('id' => 'pm', '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']);
        }
    }
    // If they did, give a chance to make ammends.
    if (!empty($post_errors) && !$is_recipient_change && !isset($_REQUEST['preview'])) {
        return messagePostError($post_errors, $namedRecipientList, $recipientList);
    }
    // Want to take a second glance before you send?
    if (isset($_REQUEST['preview'])) {
        // Set everything up to be displayed.
        $context['preview_subject'] = commonAPI::htmlspecialchars($_REQUEST['subject']);
        $context['preview_message'] = commonAPI::htmlspecialchars($_REQUEST['message'], ENT_QUOTES);
        preparsecode($context['preview_message'], true);
        // Parse out the BBC if it is enabled.
        $context['preview_message'] = parse_bbc($context['preview_message']);
        // Censor, as always.
        censorText($context['preview_subject']);
        censorText($context['preview_message']);
        // Set a descriptive title.
        $context['page_title'] = $txt['preview'] . ' - ' . $context['preview_subject'];
        // Pretend they messed up but don't ignore if they really did :P.
        return messagePostError($post_errors, $namedRecipientList, $recipientList);
    } elseif ($is_recipient_change) {
        // Maybe we couldn't find one?
        foreach ($namesNotFound as $recipientType => $names) {
            $post_errors[] = 'bad_' . $recipientType;
            foreach ($names as $name) {
                $context['send_log']['failed'][] = sprintf($txt['pm_error_user_not_found'], $name);
            }
        }
        return messagePostError(array(), $namedRecipientList, $recipientList);
    } elseif (!empty($modSettings['max_pm_recipients']) && count($recipientList['to']) + count($recipientList['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum'))) {
        $context['send_log'] = array('sent' => array(), 'failed' => array(sprintf($txt['pm_too_many_recipients'], $modSettings['max_pm_recipients'])));
        return messagePostError($post_errors, $namedRecipientList, $recipientList);
    }
    // Protect from message spamming.
    spamProtection('pm');
    // Prevent double submission of this form.
    checkSubmitOnce('check');
    // Do the actual sending of the PM.
    if (!empty($recipientList['to']) || !empty($recipientList['bcc'])) {
        $context['send_log'] = sendpm($recipientList, $_REQUEST['subject'], $_REQUEST['message'], !empty($_REQUEST['outbox']), null, !empty($_REQUEST['pm_head']) ? (int) $_REQUEST['pm_head'] : 0);
    } else {
        $context['send_log'] = array('sent' => array(), 'failed' => array());
    }
    // Mark the message as "replied to".
    if (!empty($context['send_log']['sent']) && !empty($_REQUEST['replied_to']) && isset($_REQUEST['f']) && $_REQUEST['f'] == 'inbox') {
        smf_db_query('
			UPDATE {db_prefix}pm_recipients
			SET is_read = is_read | 2
			WHERE id_pm = {int:replied_to}
				AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'replied_to' => (int) $_REQUEST['replied_to']));
    }
    // If one or more of the recipient were invalid, go back to the post screen with the failed usernames.
    if (!empty($context['send_log']['failed'])) {
        return messagePostError($post_errors, $namesNotFound, array('to' => array_intersect($recipientList['to'], $context['send_log']['failed']), 'bcc' => array_intersect($recipientList['bcc'], $context['send_log']['failed'])));
    }
    // Message sent successfully?
    if (!empty($context['send_log']) && empty($context['send_log']['failed'])) {
        $context['current_label_redirect'] = $context['current_label_redirect'] . ';done=sent';
    }
    // Go back to the where they sent from, if possible...
    redirectexit($context['current_label_redirect']);
}
Beispiel #13
0
function text2words($text, $max_chars = 20, $encrypt = false)
{
    global $context;
    // Step 1: Remove entities/things we don't consider words:
    $words = preg_replace('~(?:[\\x0B\\0' . ($context['server']['complex_preg_chars'] ? '\\x{A0}' : " ") . '\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~u', ' ', strtr($text, array('<br />' => ' ')));
    // Step 2: Entities we left to letters, where applicable, lowercase.
    $words = un_htmlspecialchars(commonAPI::strtolower($words));
    // Step 3: Ready to split apart and index!
    $words = explode(' ', $words);
    if ($encrypt) {
        $possible_chars = array_flip(array_merge(range(46, 57), range(65, 90), range(97, 122)));
        $returned_ints = array();
        foreach ($words as $word) {
            if (($word = trim($word, '-_\'')) !== '') {
                $encrypted = substr(crypt($word, 'uk'), 2, $max_chars);
                $total = 0;
                for ($i = 0; $i < $max_chars; $i++) {
                    $total += $possible_chars[ord($encrypted[$i])] * pow(63, $i);
                }
                $returned_ints[] = $max_chars == 4 ? min($total, 16777215) : $total;
            }
        }
        return array_unique($returned_ints);
    } else {
        // Trim characters before and after and add slashes for database insertion.
        $returned_words = array();
        foreach ($words as $word) {
            if (($word = trim($word, '-_\'')) !== '') {
                $returned_words[] = $max_chars === null ? $word : substr($word, 0, $max_chars);
            }
        }
        // Filter out all words that occur more than once.
        return array_unique($returned_words);
    }
}
Beispiel #14
0
function ComposeMailing()
{
    global $txt, $sourcedir, $context, $smcFunc;
    // Start by finding any members!
    $toClean = array();
    if (!empty($_POST['members'])) {
        $toClean[] = 'members';
    }
    if (!empty($_POST['exclude_members'])) {
        $toClean[] = 'exclude_members';
    }
    if (!empty($toClean)) {
        require_once $sourcedir . '/lib/Subs-Auth.php';
        foreach ($toClean as $type) {
            // Remove the quotes.
            $_POST[$type] = strtr($_POST[$type], array('\\"' => '"'));
            preg_match_all('~"([^"]+)"~', $_POST[$type], $matches);
            $_POST[$type] = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_POST[$type]))));
            foreach ($_POST[$type] as $index => $member) {
                if (strlen(trim($member)) > 0) {
                    $_POST[$type][$index] = commonAPI::htmlspecialchars(commonAPI::strtolower(trim($member)));
                } else {
                    unset($_POST[$type][$index]);
                }
            }
            // Find the members
            $_POST[$type] = implode(',', array_keys(findMembers($_POST[$type])));
        }
    }
    if (isset($_POST['member_list']) && is_array($_POST['member_list'])) {
        $members = array();
        foreach ($_POST['member_list'] as $member_id) {
            $members[] = (int) $member_id;
        }
        $_POST['members'] = implode(',', $members);
    }
    if (isset($_POST['exclude_member_list']) && is_array($_POST['exclude_member_list'])) {
        $members = array();
        foreach ($_POST['exclude_member_list'] as $member_id) {
            $members[] = (int) $member_id;
        }
        $_POST['exclude_members'] = implode(',', $members);
    }
    // Clean the other vars.
    SendMailing(true);
    // We need a couple strings from the email template file
    loadLanguage('EmailTemplates');
    // Get a list of all full banned users.  Use their Username and email to find them.  Only get the ones that can't login to turn off notification.
    $request = smf_db_query('
		SELECT DISTINCT mem.id_member
		FROM {db_prefix}ban_groups AS bg
			INNER JOIN {db_prefix}ban_items AS bi ON (bg.id_ban_group = bi.id_ban_group)
			INNER JOIN {db_prefix}members AS mem ON (bi.id_member = mem.id_member)
		WHERE (bg.cannot_access = {int:cannot_access} OR bg.cannot_login = {int:cannot_login})
			AND (bg.expire_time IS NULL OR bg.expire_time > {int:current_time})', array('cannot_access' => 1, 'cannot_login' => 1, 'current_time' => time()));
    while ($row = mysql_fetch_assoc($request)) {
        $context['recipients']['exclude_members'][] = $row['id_member'];
    }
    mysql_free_result($request);
    $request = smf_db_query('
		SELECT DISTINCT bi.email_address
		FROM {db_prefix}ban_items AS bi
			INNER JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group)
		WHERE (bg.cannot_access = {int:cannot_access} OR bg.cannot_login = {int:cannot_login})
			AND (COALESCE(bg.expire_time, 1=1) OR bg.expire_time > {int:current_time})
			AND bi.email_address != {string:blank_string}', array('cannot_access' => 1, 'cannot_login' => 1, 'current_time' => time(), 'blank_string' => ''));
    $condition_array = array();
    $condition_array_params = array();
    $count = 0;
    while ($row = mysql_fetch_assoc($request)) {
        $condition_array[] = '{string:email_' . $count . '}';
        $condition_array_params['email_' . $count++] = $row['email_address'];
    }
    if (!empty($condition_array)) {
        $request = smf_db_query('
			SELECT id_member
			FROM {db_prefix}members
			WHERE email_address IN(' . implode(', ', $condition_array) . ')', $condition_array_params);
        while ($row = mysql_fetch_assoc($request)) {
            $context['recipients']['exclude_members'][] = $row['id_member'];
        }
    }
    // Did they select moderators - if so add them as specific members...
    if (!empty($context['recipients']['groups']) && in_array(3, $context['recipients']['groups']) || !empty($context['recipients']['exclude_groups']) && in_array(3, $context['recipients']['exclude_groups'])) {
        $request = smf_db_query('
			SELECT DISTINCT mem.id_member AS identifier
			FROM {db_prefix}members AS mem
				INNER JOIN {db_prefix}moderators AS mods ON (mods.id_member = mem.id_member)
			WHERE mem.is_activated = {int:is_activated}', array('is_activated' => 1));
        while ($row = mysql_fetch_assoc($request)) {
            if (in_array(3, $context['recipients'])) {
                $context['recipients']['exclude_members'][] = $row['identifier'];
            } else {
                $context['recipients']['members'][] = $row['identifier'];
            }
        }
        mysql_free_result($request);
    }
    // For progress bar!
    $context['total_emails'] = count($context['recipients']['emails']);
    $request = smf_db_query('
		SELECT MAX(id_member)
		FROM {db_prefix}members', array());
    list($context['max_id_member']) = mysql_fetch_row($request);
    mysql_free_result($request);
    // Clean up the arrays.
    $context['recipients']['members'] = array_unique($context['recipients']['members']);
    $context['recipients']['exclude_members'] = array_unique($context['recipients']['exclude_members']);
    // Setup the template!
    $context['page_title'] = $txt['admin_newsletters'];
    $context['sub_template'] = 'email_members_compose';
    $context['default_subject'] = htmlspecialchars($context['forum_name'] . ': ' . $txt['subject']);
    $context['default_message'] = htmlspecialchars($txt['message'] . "\n\n" . $txt['regards_team'] . "\n\n" . '{$board_url}');
}