Exemple #1
0
 /**
  * Search for a member - by real_name or member_name by default.
  *
  * @return string
  */
 public function member()
 {
     global $user_info, $context;
     $search = trim(Util::strtolower($_REQUEST['search'])) . '*';
     $search = strtr($search, array('%' => '\\%', '_' => '\\_', '*' => '%', '?' => '_', '&' => '&'));
     require_once SUBSDIR . '/Members.subs.php';
     // Find the member.
     $xml_data = getMember($search, !empty($context['search_param']['buddies']) ? $user_info['buddies'] : array());
     return $xml_data;
 }
/**
 * Shows all of the addon packs available on the package server
 */
function template_package_list()
{
    global $context, $settings, $txt;
    echo '
	<div id="admincenter">
		<h2 class="category_header">' . $context['page_title'] . '</h2>
			<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>
						<span class="package_toggle">&nbsp;
							<span id="ps_img_', $i, '" class="collapse" style="display: none;" title="', $txt['hide'], '"></span>
						</span>
						<a href="#" id="upshrink_link_', $i, '" class="highlight">', $packageSection['title'], '</a>';
            if (!empty($packageSection['text'])) {
                echo '
						<div class="content">', $packageSection['text'], '</div>';
            }
            // List of addons available in this section
            echo '
						<ol id="package_section_', $i, '" class="packages">';
            $alt = false;
            foreach ($packageSection['items'] as $id => $package) {
                echo '
							<li>';
                // 1. Some addon [ Download ].
                echo '
							<strong>
								<img id="ps_img_', $i, '_pkg_', $id, '" src="', $settings['images_url'], '/selected_open.png" alt="*" style="display: none;" /> ', $package['can_install'] ? '<strong>' . $package['name'] . '</strong> <a class="linkbutton" 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', '.png" class="centericon package_img" 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 addon type?
                if ($package['type'] != '') {
                    echo '
								<li class="package_section">', $txt['package_type'], ':&nbsp; ', Util::ucwords(Util::strtolower($package['type'])), '</li>';
                }
                // Show the version number?
                if ($package['version'] != '') {
                    echo '
								<li class="package_section">', $txt['mod_version'], ':&nbsp; ', $package['version'], '</li>';
                }
                // Show the last date?
                if ($package['date'] != '') {
                    echo '
								<li class="package_section">', $txt['mod_date'], ':&nbsp; ', $package['date'], '</li>';
                }
                // How 'bout the author?
                if (!empty($package['author'])) {
                    echo '
								<li class="package_section">', $txt['mod_author'], ':&nbsp; ', $package['author'], '</li>';
                }
                // Nothing but hooks ?
                if ($package['hooks'] != '' && in_array($package['hooks'], array('yes', 'true'))) {
                    echo '
								<li class="package_section">', $txt['mod_hooks'], ' <i class="fa fa-check-circle-o"></i></li>';
                }
                // Location of file: http://someplace/.
                echo '
								<ul style="margin-left: 5em">
									<li class="package_section"><i class="fa fa-cloud-download"></i> ', $txt['file_location'], ':&nbsp; <a href="', $package['server']['download'], '">', $package['server']['download'], '</a></li>';
                // Location of issues?
                if (!empty($package['server']['bugs'])) {
                    echo '
									<li class="package_section"><i class="fa fa-bug"></i> ', $txt['bug_location'], ':&nbsp; <a href="', $package['server']['bugs'], '">', $package['server']['bugs'], '</a></li>';
                }
                // Location of support?
                if (!empty($package['server']['support'])) {
                    echo '
									<li class="package_section"><i class="fa fa-support"></i> ', $txt['support_location'], ':&nbsp; <a href="', $package['server']['support'], '">', $package['server']['support'], '</a></li>';
                }
                // Description: bleh bleh!
                echo '
								</ul>
								<li class="package_section"><div class="infobox">', $txt['package_description'], ':&nbsp; ', $package['description'], '</div></li>
							</ul>';
                $alt = !$alt;
                echo '
						</li>';
            }
            echo '
					</ol>
						</li>';
        }
        echo '
				</ul>';
    }
    echo '
		</div>
		<div>
			', $txt['package_installed_key'], '
			<img src="', $settings['images_url'], '/icons/package_installed.png" alt="" class="centericon" style="margin-left: 1ex;" /> ', $txt['package_installed_current'], '
			<img src="', $settings['images_url'], '/icons/package_old.png" alt="" class="centericon" style="margin-left: 2ex;" /> ', $txt['package_installed_old'], '
		</div>
	</div>';
    // Now go through and turn off / collapse all the sections.
    if (!empty($context['package_list'])) {
        echo '
			<script><!-- // --><![CDATA[';
        foreach ($context['package_list'] as $section => $ps) {
            echo '
				var oPackageServerToggle_', $section, ' = new elk_Toggle({
					bToggleEnabled: true,
					bCurrentlyCollapsed: true,
					aSwappableContainers: [
						\'package_section_', $section, '\'
					],
					aSwapClasses: [
						{
							sId: \'ps_img_', $section, '\',
							classExpanded: \'collapse\',
							titleExpanded: ', JavaScriptEscape($txt['hide']), ',
							classCollapsed: \'expand\',
							titleCollapsed: ', JavaScriptEscape($txt['show']), '
						}
					],
					aSwapLinks: [
						{
							sId: \'upshrink_link_', $section, '\',
							msgExpanded: ', JavaScriptEscape($ps['title']), ',
							msgCollapsed: ', JavaScriptEscape($ps['title']), '
						}
					]
				});';
            foreach ($ps['items'] as $id => $package) {
                echo '
				var oPackageToggle_', $section, '_pkg_', $id, ' = new elk_Toggle({
					bToggleEnabled: true,
					bCurrentlyCollapsed: true,
					aSwappableContainers: [
						\'package_section_', $section, '_pkg_', $id, '\'
					],
					aSwapImages: [
						{
							sId: \'ps_img_', $section, '_pkg_', $id, '\',
							srcExpanded: elk_images_url + \'/selected.png\',
							altExpanded: \'*\',
							srcCollapsed: elk_images_url + \'/selected_open.png\',
							altCollapsed: \'*\'
						}
					]
				});';
            }
        }
        echo '
			// ]]></script>';
    }
}
/**
 * Sends a personal message from the specified person to the specified people
 * ($from defaults to the user)
 *
 * @package PersonalMessage
 * @param mixed[] $recipients - an array containing the arrays 'to' and 'bcc', both containing id_member's.
 * @param string $subject - should have no slashes and no html entities
 * @param string $message - should have no slashes and no html entities
 * @param bool $store_outbox
 * @param mixed[]|null $from - an array with the id, name, and username of the member.
 * @param int $pm_head - the ID of the chain being replied to - if any.
 * @return mixed[] an array with log entries telling how many recipients were successful and which recipients it failed to send to.
 */
function sendpm($recipients, $subject, $message, $store_outbox = true, $from = null, $pm_head = 0)
{
    global $scripturl, $txt, $user_info, $language, $modSettings, $webmaster_email;
    $db = database();
    // Make sure the PM language file is loaded, we might need something out of it.
    loadLanguage('PersonalMessage');
    // Needed for our email and post functions
    require_once SUBSDIR . '/Mail.subs.php';
    require_once SUBSDIR . '/Post.subs.php';
    // 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 = Util::htmlspecialchars($message, ENT_QUOTES, 'UTF-8', true);
    preparsecode($htmlmessage);
    $htmlsubject = strtr(Util::htmlspecialchars($subject), array("\r" => '', "\n" => '', "\t" => ''));
    if (Util::strlen($htmlsubject) > 100) {
        $htmlsubject = Util::substr($htmlsubject, 0, 100);
    }
    // Make sure is an array
    if (!is_array($recipients)) {
        $recipients = array($recipients);
    }
    // Integrated PMs
    call_integration_hook('integrate_personal_message', array(&$recipients, &$from, &$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] = Util::strtolower(trim(preg_replace('/[<>&"\'=\\\\]/', '', $recipients[$rec_type][$id])));
                $usernames[$recipients[$rec_type][$id]] = 0;
            }
        }
    }
    if (!empty($usernames)) {
        $request = $db->query('pm_find_username', '
			SELECT
				id_member, member_name
			FROM {db_prefix}members
			WHERE ' . (defined('DB_CASE_SENSITIVE') ? 'LOWER(member_name)' : 'member_name') . ' IN ({array_string:usernames})', array('usernames' => array_keys($usernames)));
        while ($row = $db->fetch_assoc($request)) {
            if (isset($usernames[Util::strtolower($row['member_name'])])) {
                $usernames[Util::strtolower($row['member_name'])] = $row['id_member'];
            }
        }
        $db->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 = $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 = $db->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) {
            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;
        }
    }
    $db->free_result($request);
    // Load the membergrounp message limits.
    static $message_limit_cache = array();
    if (!allowedTo('moderate_forum') && empty($message_limit_cache)) {
        $request = $db->query('', '
			SELECT
				id_group, max_messages
			FROM {db_prefix}membergroups', array());
        while ($row = $db->fetch_assoc($request)) {
            $message_limit_cache[$row['id_group']] = $row['max_messages'];
        }
        $db->free_result($request);
    }
    // Load the groups that are allowed to read PMs.
    // @todo move into a separate function on $permission.
    $allowed_groups = array();
    $disallowed_groups = array();
    $request = $db->query('', '
		SELECT
			id_group, add_deny
		FROM {db_prefix}permissions
		WHERE permission = {string:read_permission}', array('read_permission' => 'pm_read'));
    while ($row = $db->fetch_assoc($request)) {
        if (empty($row['add_deny'])) {
            $disallowed_groups[] = $row['id_group'];
        } else {
            $allowed_groups[] = $row['id_group'];
        }
    }
    $db->free_result($request);
    if (empty($modSettings['permission_enable_deny'])) {
        $disallowed_groups = array();
    }
    $request = $db->query('', '
		SELECT
			member_name, real_name, id_member, email_address, lngfile,
			pm_email_notify, personal_messages,' . (allowedTo('moderate_forum') ? ' 0' : '
			(receive_from = {int:admins_only}' . (empty($modSettings['enable_buddylist']) ? '' : ' OR
			(receive_from = {int:buddies_only} AND FIND_IN_SET({string:from_id}, buddy_list) = 0) OR
			(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();
    while ($row = $db->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['personal_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'];
        }
        $log['sent'][$row['id_member']] = sprintf(isset($txt['pm_successfully_sent']) ? $txt['pm_successfully_sent'] : '', $row['real_name']);
    }
    $db->free_result($request);
    // Only 'send' the message if there are any recipients left.
    if (empty($all_to)) {
        return $log;
    }
    // Track the pm count for our stats
    if (!empty($modSettings['trackStats'])) {
        trackStats(array('pm' => '+'));
    }
    // Insert the message itself and then grab the last insert id.
    $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 = $db->insert_id('{db_prefix}personal_messages', 'id_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)) {
            $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 :)
        $db->query('', '
			DELETE FROM {db_prefix}pm_recipients
			WHERE id_pm = {int:id_pm}', array('id_pm' => $id_pm));
        $insertRows = array();
        $to_list = array();
        foreach ($all_to as $to) {
            $insertRows[] = array($id_pm, $to, in_array($to, $recipients['bcc']) ? 1 : 0, isset($deletes[$to]) ? 1 : 0, 1);
            if (!in_array($to, $recipients['bcc'])) {
                $to_list[] = $to;
            }
        }
        $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'));
    }
    $maillist = !empty($modSettings['maillist_enabled']) && !empty($modSettings['pbe_pm_enabled']);
    // If they have post by email enabled, override disallow_sendBody
    if (!$maillist && !empty($modSettings['disallow_sendBody'])) {
        $message = '';
        censorText($subject);
    } else {
        require_once SUBSDIR . '/Emailpost.subs.php';
        pbe_prepare_text($message, $subject);
    }
    $to_names = array();
    if (count($to_list) > 1) {
        require_once SUBSDIR . '/Members.subs.php';
        $result = getBasicMemberData($to_list);
        foreach ($result as $row) {
            $to_names[] = un_htmlspecialchars($row['real_name']);
        }
    }
    $replacements = array('SUBJECT' => $subject, 'MESSAGE' => $message, 'SENDER' => un_htmlspecialchars($from['name']), 'READLINK' => $scripturl . '?action=pm;pmsg=' . $id_pm . '#msg' . $id_pm, 'REPLYLINK' => $scripturl . '?action=pm;sa=send;f=inbox;pmsg=' . $id_pm . ';quote;u=' . $from['id'], 'TOLIST' => implode(', ', $to_names));
    // Select the right template
    $email_template = ($maillist && empty($modSettings['disallow_sendBody']) ? 'pbe_' : '') . 'new_pm' . (empty($modSettings['disallow_sendBody']) ? '_body' : '') . (!empty($to_names) ? '_tolist' : '');
    foreach ($notifications as $lang => $notification_list) {
        // Using maillist functionality
        if ($maillist) {
            $sender_details = query_sender_wrapper($from['id']);
            $from_wrapper = !empty($modSettings['maillist_mail_from']) ? $modSettings['maillist_mail_from'] : (empty($modSettings['maillist_sitename_address']) ? $webmaster_email : $modSettings['maillist_sitename_address']);
            // Add in the signature
            $replacements['SIGNATURE'] = $sender_details['signature'];
            // And off it goes, looking a bit more personal
            $mail = loadEmailTemplate($email_template, $replacements, $lang);
            $reference = !empty($pm_head) ? $pm_head : null;
            sendmail($notification_list, $mail['subject'], $mail['body'], $from['name'], 'p' . $id_pm, false, 2, null, true, $from_wrapper, $reference);
        } else {
            // Off the notification email goes!
            $mail = loadEmailTemplate($email_template, $replacements, $lang);
            sendmail($notification_list, $mail['subject'], $mail['body'], null, 'p' . $id_pm, false, 2, null, true);
        }
    }
    // Integrated After PMs
    call_integration_hook('integrate_personal_message_after', array(&$id_pm, &$log, &$recipients, &$from, &$subject, &$message));
    // 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('personal_messages' => '+', 'unread_messages' => '+', 'new_pm' => 1));
    }
    return $log;
}
/**
 * Loads all the shouts for a given shoutbox
 *
 * @param int $shoutbox id of the shoutbox to get data from
 * @param mixed[] $parameters
 *
 * @return type
 */
function sportal_get_shouts($shoutbox, $parameters)
{
    global $scripturl, $context, $user_info, $modSettings, $txt;
    $db = database();
    // Set defaults or used what was passed
    $shoutbox = !empty($shoutbox) ? (int) $shoutbox : 0;
    $start = !empty($parameters['start']) ? (int) $parameters['start'] : 0;
    $limit = !empty($parameters['limit']) ? (int) $parameters['limit'] : 20;
    $bbc = !empty($parameters['bbc']) ? $parameters['bbc'] : array();
    $reverse = !empty($parameters['reverse']);
    $cache = !empty($parameters['cache']);
    $can_delete = !empty($parameters['can_moderate']);
    // Cached, use it first
    if (!empty($start) || !$cache || ($shouts = cache_get_data('shoutbox_shouts-' . $shoutbox, 240)) === null) {
        $request = $db->query('', '
			SELECT
				sh.id_shout, sh.body, IFNULL(mem.id_member, 0) AS id_member,
				IFNULL(mem.real_name, sh.member_name) AS member_name, sh.log_time,
				mg.online_color AS member_group_color, pg.online_color AS post_group_color
			FROM {db_prefix}sp_shouts AS sh
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = sh.id_member)
				LEFT JOIN {db_prefix}membergroups AS pg ON (pg.id_group = mem.id_post_group)
				LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = mem.id_group)
			WHERE sh.id_shoutbox = {int:id_shoutbox}
			ORDER BY sh.id_shout DESC
			LIMIT {int:start}, {int:limit}', array('id_shoutbox' => $shoutbox, 'start' => $start, 'limit' => $limit));
        $shouts = array();
        while ($row = $db->fetch_assoc($request)) {
            // Disable the aeva mod for the shoutbox.
            $context['aeva_disable'] = true;
            $online_color = !empty($row['member_group_color']) ? $row['member_group_color'] : $row['post_group_color'];
            $shouts[$row['id_shout']] = array('id' => $row['id_shout'], 'author' => array('id' => $row['id_member'], 'name' => $row['member_name'], 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '" title="' . $txt['on'] . ' ' . strip_tags(standardTime($row['log_time'])) . '"' . (!empty($online_color) ? ' style="color: ' . $online_color . ';"' : '') . '>' . $row['member_name'] . '</a>' : $row['member_name'], 'color' => $online_color), 'time' => $row['log_time'], 'text' => parse_bbc($row['body'], true, '', $bbc));
        }
        $db->free_result($request);
        if (empty($start) && $cache) {
            cache_put_data('shoutbox_shouts-' . $shoutbox, $shouts, 240);
        }
    }
    foreach ($shouts as $shout) {
        // Private shouts @username: only get shown to the shouter and shoutee, and the admin
        if (preg_match('~^@(.+?): ~u', $shout['text'], $target) && Util::strtolower($target[1]) !== Util::strtolower($user_info['name']) && $shout['author']['id'] != $user_info['id'] && !$user_info['is_admin']) {
            unset($shouts[$shout['id']]);
            continue;
        }
        $shouts[$shout['id']] += array('is_me' => preg_match('~^<div\\sclass="meaction">\\* ' . preg_quote($shout['author']['name'], '~') . '.+</div>$~', $shout['text']) != 0, 'delete_link' => $can_delete ? '<a class="dot dotdelete" href="' . $scripturl . '?action=shoutbox;shoutbox_id=' . $shoutbox . ';delete=' . $shout['id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '"></a> ' : '', 'delete_link_js' => $can_delete ? '<a class="dot dotdelete" href="' . $scripturl . '?action=shoutbox;shoutbox_id=' . $shoutbox . ';delete=' . $shout['id'] . ';' . $context['session_var'] . '=' . $context['session_id'] . '" onclick="sp_delete_shout(' . $shoutbox . ', ' . $shout['id'] . ', \'' . $context['session_var'] . '\', \'' . $context['session_id'] . '\'); return false;"></a> ' : '');
        // Prepare for display in the box
        $shouts[$shout['id']]['time'] = standardTime($shouts[$shout['id']]['time']);
        $shouts[$shout['id']]['text'] = preg_replace('~(</?)div([^<]*>)~', '$1span$2', $shouts[$shout['id']]['text']);
        $shouts[$shout['id']]['text'] = preg_replace('~<a([^>]+>)([^<]+)</a>~', '<a$1' . $txt['sp_link'] . '</a>', $shouts[$shout['id']]['text']);
        $shouts[$shout['id']]['text'] = censorText($shouts[$shout['id']]['text']);
        // Ignored user, hide the shout with option to show it
        if (!empty($modSettings['enable_buddylist']) && in_array($shout['author']['id'], $context['user']['ignoreusers'])) {
            $shouts[$shout['id']]['text'] = '<a href="#toggle" id="ignored_shout_link_' . $shout['id'] . '" onclick="sp_show_ignored_shout(' . $shout['id'] . '); return false;">[' . $txt['sp_shoutbox_show_ignored'] . ']</a><span id="ignored_shout_' . $shout['id'] . '" style="display: none;">' . $shouts[$shout['id']]['text'] . '</span>';
        }
    }
    if ($reverse) {
        $shouts = array_reverse($shouts);
    }
    return $shouts;
}
Exemple #5
0
/**
 * Reload a users settings.
 */
function profileReloadUser()
{
    global $modSettings, $context, $cur_profile;
    // Log them back in - using the verify password as they must have matched and this one doesn't get changed by anyone!
    if (isset($_POST['passwrd2']) && $_POST['passwrd2'] != '') {
        require_once SUBSDIR . '/Auth.subs.php';
        setLoginCookie(60 * $modSettings['cookieTime'], $context['id_member'], hash('sha256', Util::strtolower($cur_profile['member_name']) . un_htmlspecialchars($_POST['passwrd2']) . $cur_profile['password_salt']));
    }
    loadUserSettings();
    writeLog();
}
/**
 * Shows all of the addon packs available on the package server
 */
function template_package_list()
{
    global $context, $settings, $txt;
    echo '
	<div id="admincenter">
		<h2 class="category_header">' . $context['page_title'] . '</h2>
		<div class="windowbg">
			<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>
						<img id="ps_img_', $i, '" src="', $settings['images_url'], '/collapse.png" class="floatright" alt="*" style="display: none;" /><strong>', $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 />';
                } elseif ($package['is_remote']) {
                    echo '
							<strong>', $package['link'], '</strong>';
                } elseif ($package['is_heading'] || $package['is_title']) {
                    echo '
							<strong>', $package['name'], '</strong>';
                } else {
                    // 1. Some addon [ Download ].
                    echo '
							<strong><img id="ps_img_', $i, '_pkg_', $id, '" src="', $settings['images_url'], '/selected_open.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', '.png" class="centericon" style="width: 12px; height: 11px; 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 addon type?
                    if ($package['type'] != '') {
                        echo '
								<li class="package_section">', $txt['package_type'], ':&nbsp; ', Util::ucwords(Util::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>';
                    }
                    // Description: 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>
			', $txt['package_installed_key'], '
			<img src="', $settings['images_url'], '/icons/package_installed.png" alt="" class="centericon" style="margin-left: 1ex;" /> ', $txt['package_installed_current'], '
			<img src="', $settings['images_url'], '/icons/package_old.png" alt="" class="centericon" style="margin-left: 2ex;" /> ', $txt['package_installed_old'], '
		</div>
	</div>';
    // Now go through and turn off / collapse all the sections.
    if (!empty($context['package_list'])) {
        $section_count = count($context['package_list']);
        echo '
			<script><!-- // --><![CDATA[';
        foreach ($context['package_list'] as $section => $ps) {
            echo '
				var oPackageServerToggle_', $section, ' = new elk_Toggle({
					bToggleEnabled: true,
					bCurrentlyCollapsed: ', count($ps['items']) == 1 || $section_count == 1 ? 'false' : 'true', ',
					aSwappableContainers: [
						\'package_section_', $section, '\'
					],
					aSwapImages: [
						{
							sId: \'ps_img_', $section, '\',
							srcExpanded: elk_images_url + \'/collapse.png\',
							altExpanded: \'*\',
							srcCollapsed: elk_images_url + \'/expand.png\',
							altCollapsed: \'*\'
						}
					]
				});';
            foreach ($ps['items'] as $id => $package) {
                if (!$package['is_text'] && !$package['is_line'] && !$package['is_remote']) {
                    echo '
				var oPackageToggle_', $section, '_pkg_', $id, ' = new elk_Toggle({
					bToggleEnabled: true,
					bCurrentlyCollapsed: true,
					aSwappableContainers: [
						\'package_section_', $section, '_pkg_', $id, '\'
					],
					aSwapImages: [
						{
							sId: \'ps_img_', $section, '_pkg_', $id, '\',
							srcExpanded: elk_images_url + \'/selected.png\',
							altExpanded: \'*\',
							srcCollapsed: elk_images_url + \'/selected_open.png\',
							altCollapsed: \'*\'
						}
					]
				});';
                }
            }
        }
        echo '
			// ]]></script>';
    }
}
 /**
  * Shows a form to edit a forum mailing and its recipients.
  *
  * What it does:
  * - Called by ?action=admin;area=news;sa=mailingcompose.
  * - Requires the send_mail permission.
  * - Form is submitted to ?action=admin;area=news;sa=mailingsend.
  *
  * @uses ManageNews template, email_members_compose sub-template.
  */
 public function action_mailingcompose()
 {
     global $txt, $context;
     // Setup the template!
     $context['page_title'] = $txt['admin_newsletters'];
     $context['sub_template'] = 'email_members_compose';
     $context['subject'] = !empty($_POST['subject']) ? $_POST['subject'] : $context['forum_name'] . ': ' . htmlspecialchars($txt['subject'], ENT_COMPAT, 'UTF-8');
     $context['message'] = !empty($_POST['message']) ? $_POST['message'] : htmlspecialchars($txt['message'] . "\n\n" . replaceBasicActionUrl($txt['regards_team']) . "\n\n" . '{$board_url}', ENT_COMPAT, 'UTF-8');
     // Needed for the WYSIWYG editor.
     require_once SUBSDIR . '/Editor.subs.php';
     // Now create the editor.
     $editorOptions = array('id' => 'message', 'value' => $context['message'], 'height' => '250px', 'width' => '100%', 'labels' => array('post_button' => $txt['sendtopic_send']), 'preview_type' => 2);
     create_control_richedit($editorOptions);
     if (isset($context['preview'])) {
         require_once SUBSDIR . '/Mail.subs.php';
         $context['recipients']['members'] = !empty($_POST['members']) ? explode(',', $_POST['members']) : array();
         $context['recipients']['exclude_members'] = !empty($_POST['exclude_members']) ? explode(',', $_POST['exclude_members']) : array();
         $context['recipients']['groups'] = !empty($_POST['groups']) ? explode(',', $_POST['groups']) : array();
         $context['recipients']['exclude_groups'] = !empty($_POST['exclude_groups']) ? explode(',', $_POST['exclude_groups']) : array();
         $context['recipients']['emails'] = !empty($_POST['emails']) ? explode(';', $_POST['emails']) : array();
         $context['email_force'] = !empty($_POST['email_force']) ? 1 : 0;
         $context['total_emails'] = !empty($_POST['total_emails']) ? (int) $_POST['total_emails'] : 0;
         $context['max_id_member'] = !empty($_POST['max_id_member']) ? (int) $_POST['max_id_member'] : 0;
         $context['send_pm'] = !empty($_POST['send_pm']) ? 1 : 0;
         $context['send_html'] = !empty($_POST['send_html']) ? '1' : '0';
         return prepareMailingForPreview();
     }
     // 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 SUBSDIR . '/Auth.subs.php';
         foreach ($toClean as $type) {
             // Remove the quotes.
             $_POST[$type] = strtr((string) $_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] = Util::htmlspecialchars(Util::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.
     $this->action_mailingsend(true);
     // We need a couple strings from the email template file
     loadLanguage('EmailTemplates');
     require_once SUBSDIR . '/News.subs.php';
     // 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.
     $context['recipients']['exclude_members'] = excludeBannedMembers();
     // 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'])) {
         $mods = getModerators();
         foreach ($mods as $row) {
             if (in_array(3, $context['recipients'])) {
                 $context['recipients']['exclude_members'][] = $row;
             } else {
                 $context['recipients']['members'][] = $row;
             }
         }
     }
     require_once SUBSDIR . '/Members.subs.php';
     // For progress bar!
     $context['total_emails'] = count($context['recipients']['emails']);
     $context['max_id_member'] = maxMemberID();
     // Clean up the arrays.
     $context['recipients']['members'] = array_unique($context['recipients']['members']);
     $context['recipients']['exclude_members'] = array_unique($context['recipients']['exclude_members']);
 }
Exemple #8
0
/**
 * Builds a theme-info.xml file for use when a new theme is installed by copying
 * an existing theme
 *
 * @param string $name
 * @param string $version
 * @param string $theme_dir
 * @param mixed[] $theme_values
 */
function write_theme_info($name, $version, $theme_dir, $theme_values)
{
    $xml_info = '<' . '?xml version="1.0"?' . '>
	<theme-info xmlns="http://www.elkarte.net/xml/theme-info" xmlns:elk="http://www.elkarte.net/">
		<!-- For the id, always use something unique - put your name, a colon, and then the package name. -->
		<id>elk:' . Util::strtolower(str_replace(array(' '), '_', $name)) . '</id>
		<version>' . $version . '</version>
		<!-- Theme name, used purely for aesthetics. -->
		<name>' . $name . '</name>
		<!-- Author: your email address or contact information. The name attribute is optional. -->
		<author name="Your Name">info@youremailaddress.tld</author>
		<!-- Website... where to get updates and more information. -->
		<website>http://www.yourdomain.tld/</website>
		<!-- Template layers to use, defaults to "html,body". -->
		<layers>' . (empty($theme_values['theme_layers']) ? 'html,body' : $theme_values['theme_layers']) . '</layers>
		<!-- Templates to load on startup. Default is "index". -->
		<templates>' . (empty($theme_values['theme_templates']) ? 'index' : $theme_values['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.
    file_put_contents($theme_dir . '/theme_info.xml', $xml_info);
}
Exemple #9
0
/**
 * Checks whether an entered password is correct for the user
 *
 * What it does:
 * - called when logging in or whenever a password needs to be validated for a user
 * - used to generate a new hash for the db, used during registration or any password changes
 * - if a non SHA256 password is sent, will generate one with SHA256(user + password) and return it in password
 *
 * @package Authorization
 * @param string $password user password if not already 64 characters long will be SHA256 with the user name
 * @param string $hash hash as generated from a SHA256 password
 * @param string $user user name only required if creating a SHA-256 password
 * @param boolean $returnhash flag to determine if we are returning a hash suitable for the database
 */
function validateLoginPassword(&$password, $hash, $user = '', $returnhash = false)
{
    // Our hashing controller
    require_once EXTDIR . '/PasswordHash.php';
    // Base-2 logarithm of the iteration count used for password stretching, the
    // higher the number the more secure and CPU time consuming
    $hash_cost_log2 = 10;
    // Do we require the hashes to be portable to older systems (less secure)?
    $hash_portable = false;
    // Get an instance of the hasher
    $hasher = new PasswordHash($hash_cost_log2, $hash_portable);
    // Guilty until we know otherwise
    $passhash = false;
    // If the password is not 64 characters, lets make it a (SHA-256)
    if (strlen($password) !== 64) {
        $password = hash('sha256', Util::strtolower($user) . un_htmlspecialchars($password));
    }
    // They need a password hash, something to save in the db?
    if ($returnhash) {
        $passhash = $hasher->HashPassword($password);
        // Something is not right, we can not generate a valid hash thats <20 characters
        if (strlen($passhash) < 20) {
            $passhash = false;
        }
    } else {
        $passhash = (bool) $hasher->CheckPassword($password, $hash);
    }
    unset($hasher);
    return $passhash;
}
Exemple #10
0
/**
 * Finds a member from the database using supplied string as real_name
 *
 * - Optionaly will only search/find the member in a buddy list
 *
 * @package Members
 * @param string $search string to search real_name for like finds
 * @param int[]|null $buddies
 */
function getMember($search, $buddies = array())
{
    $db = database();
    // Find the member.
    $request = $db->query('', '
		SELECT id_member, real_name
		FROM {db_prefix}members
		WHERE {raw:real_name} LIKE {string:search}' . (!empty($buddies) ? '
			AND id_member IN ({array_int:buddy_list})' : '') . '
			AND is_activated IN ({array_int:activation_status})
		LIMIT {int:limit}', array('real_name' => defined('DB_CASE_SENSITIVE') ? 'LOWER(real_name)' : 'real_name', 'buddy_list' => $buddies, 'search' => Util::strtolower($search), 'activation_status' => array(1, 12), 'limit' => Util::strlen($search) <= 2 ? 100 : 800));
    $xml_data = array('items' => array('identifier' => 'item', 'children' => array()));
    while ($row = $db->fetch_assoc($request)) {
        $row['real_name'] = strtr($row['real_name'], array('&amp;' => '&#038;', '&lt;' => '&#060;', '&gt;' => '&#062;', '&quot;' => '&#034;'));
        $xml_data['items']['children'][] = array('attributes' => array('id' => $row['id_member']), 'value' => $row['real_name']);
    }
    $db->free_result($request);
    return $xml_data;
}
Exemple #11
0
    /**
     * Spell checks the post for typos ;).
     * It uses the pspell library, which MUST be installed.
     * It has problems with internationalization.
     * It is accessed via ?action=spellcheck.
     */
    public function action_spellcheck()
    {
        global $txt, $context;
        // A list of "words" we know about but pspell doesn't.
        $known_words = array('elkarte', 'php', 'mysql', 'www', 'gif', 'jpeg', 'png', 'http');
        loadLanguage('Post');
        loadTemplate('Post');
        // Okay, this looks funny, but it actually fixes a weird bug.
        ob_start();
        $old = error_reporting(0);
        // See, first, some windows machines don't load pspell properly on the first try.  Dumb, but this is a workaround.
        pspell_new('en');
        // Next, the dictionary in question may not exist. So, we try it... but...
        $pspell_link = pspell_new($txt['lang_dictionary'], $txt['lang_spelling'], '', 'utf-8', PSPELL_FAST | PSPELL_RUN_TOGETHER);
        // Most people don't have anything but English installed... So we use English as a last resort.
        if (!$pspell_link) {
            $pspell_link = pspell_new('en', '', '', '', PSPELL_FAST | PSPELL_RUN_TOGETHER);
        }
        error_reporting($old);
        @ob_end_clean();
        if (!isset($_POST['spellstring']) || !$pspell_link) {
            die;
        }
        // Construct a bit of Javascript code.
        $context['spell_js'] = '
			var txt = {"done": "' . $txt['spellcheck_done'] . '"},
				mispstr = ' . ($_POST['fulleditor'] === 'true' ? 'window.opener.spellCheckGetText(spell_fieldname)' : 'window.opener.document.forms[spell_formname][spell_fieldname].value') . ',
				misps = Array(';
        // Get all the words (Javascript already separated them).
        $alphas = explode("\n", strtr($_POST['spellstring'], array("\r" => '')));
        $found_words = false;
        for ($i = 0, $n = count($alphas); $i < $n; $i++) {
            // Words are sent like 'word|offset_begin|offset_end'.
            $check_word = explode('|', $alphas[$i]);
            // If the word is a known word, or spelled right...
            if (in_array(Util::strtolower($check_word[0]), $known_words) || pspell_check($pspell_link, $check_word[0]) || !isset($check_word[2])) {
                continue;
            }
            // Find the word, and move up the "last occurance" to here.
            $found_words = true;
            // Add on the javascript for this misspelling.
            $context['spell_js'] .= '
				new misp("' . strtr($check_word[0], array('\\' => '\\\\', '"' => '\\"', '<' => '', '&gt;' => '')) . '", ' . (int) $check_word[1] . ', ' . (int) $check_word[2] . ', [';
            // If there are suggestions, add them in...
            $suggestions = pspell_suggest($pspell_link, $check_word[0]);
            if (!empty($suggestions)) {
                // But first check they aren't going to be censored - no naughty words!
                foreach ($suggestions as $k => $word) {
                    if ($suggestions[$k] != censorText($word)) {
                        unset($suggestions[$k]);
                    }
                }
                if (!empty($suggestions)) {
                    $context['spell_js'] .= '"' . implode('", "', $suggestions) . '"';
                }
            }
            $context['spell_js'] .= ']),';
        }
        // If words were found, take off the last comma.
        if ($found_words) {
            $context['spell_js'] = substr($context['spell_js'], 0, -1);
        }
        $context['spell_js'] .= '
			);';
        // And instruct the template system to just show the spellcheck sub template.
        Template_Layers::getInstance()->removeAll();
        $context['sub_template'] = 'spellcheck';
    }
    /**
     * Actually do the search of personal messages and show the results
     *
     * What it does:
     * - accessed with ?action=pm;sa=search2
     * - checks user input and searches the pm table for messages matching the query.
     * - uses the search_results sub template of the PersonalMessage template.
     * - show the results of the search query.
     */
    public function action_search2()
    {
        global $scripturl, $modSettings, $context, $txt, $memberContext;
        $db = database();
        // Make sure the server is able to do this right now
        if (!empty($modSettings['loadavg_search']) && $modSettings['current_load'] >= $modSettings['loadavg_search']) {
            fatal_lang_error('loadavg_search_disabled', false);
        }
        // Some useful general permissions.
        $context['can_send_pm'] = allowedTo('pm_send');
        // Some hardcoded variables that can be tweaked if required.
        $maxMembersToSearch = 500;
        // Extract all the search parameters.
        $search_params = array();
        if (isset($_REQUEST['params'])) {
            $temp_params = explode('|"|', base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))));
            foreach ($temp_params as $i => $data) {
                @(list($k, $v) = explode('|\'|', $data));
                $search_params[$k] = $v;
            }
        }
        $context['start'] = isset($_GET['start']) ? (int) $_GET['start'] : 0;
        // 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'];
        }
        // Search modifiers
        $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
        $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
        $search_params['sent_only'] = !empty($search_params['sent_only']) || !empty($_REQUEST['sent_only']);
        $context['folder'] = empty($search_params['sent_only']) ? 'inbox' : 'sent';
        // 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'];
        }
        // This will be full of all kinds of parameters!
        $searchq_parameters = array();
        // If there's no specific user, then don't mention it in the main query.
        if (empty($search_params['userspec'])) {
            $userQuery = '';
        } else {
            // Set up so we can seach by user name, wildcards, like, etc
            $userString = strtr(Util::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)));
            require_once SUBSDIR . '/Members.subs.php';
            // Who matches those criteria?
            $members = membersBy('member_names', array('member_names' => $possible_users));
            foreach ($possible_users as $key => $possible_user) {
                $searchq_parameters['guest_user_name_implode_' . $key] = defined('DB_CASE_SENSITIVE') ? strtolower($possible_user) : $possible_user;
            }
            // Simply do nothing if there are too many members matching the criteria.
            if (count($members) > $maxMembersToSearch) {
                $userQuery = '';
            } elseif (count($members) == 0) {
                if ($context['folder'] === 'inbox') {
                    $uq = array();
                    $name = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                    foreach (array_keys($possible_users) as $key) {
                        $uq[] = 'AND pm.id_member_from = 0 AND (' . $name . ' LIKE {string:guest_user_name_implode_' . $key . '})';
                    }
                    $userQuery = implode(' ', $uq);
                    $searchq_parameters['pm_from_name'] = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                } else {
                    $userQuery = '';
                }
            } else {
                $memberlist = array();
                foreach ($members as $id) {
                    $memberlist[] = $id;
                }
                // Use the name as as sent from or sent to
                if ($context['folder'] === 'inbox') {
                    $uq = array();
                    $name = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                    foreach (array_keys($possible_users) as $key) {
                        $uq[] = 'AND (pm.id_member_from IN ({array_int:member_list}) OR (pm.id_member_from = 0 AND (' . $name . ' LIKE {string:guest_user_name_implode_' . $key . '})))';
                    }
                    $userQuery = implode(' ', $uq);
                } else {
                    $userQuery = 'AND (pmr.id_member IN ({array_int:member_list}))';
                }
                $searchq_parameters['pm_from_name'] = defined('DB_CASE_SENSITIVE') ? 'LOWER(pm.from_name)' : 'pm.from_name';
                $searchq_parameters['member_list'] = $memberlist;
            }
        }
        // Setup the sorting variables...
        $sort_columns = array('pm.id_pm');
        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'] : 'pm.id_pm';
        $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
        // Sort out any labels we may be searching by.
        $labelQuery = '';
        if ($context['folder'] == 'inbox' && !empty($search_params['advanced']) && $context['currently_using_labels']) {
            // Came here from pagination?  Put them back into $_REQUEST for sanitization.
            if (isset($search_params['labels'])) {
                $_REQUEST['searchlabel'] = explode(',', $search_params['labels']);
            }
            // Assuming we have some labels - make them all integers.
            if (!empty($_REQUEST['searchlabel']) && is_array($_REQUEST['searchlabel'])) {
                $_REQUEST['searchlabel'] = array_map('intval', $_REQUEST['searchlabel']);
            } else {
                $_REQUEST['searchlabel'] = array();
            }
            // Now that everything is cleaned up a bit, make the labels a param.
            $search_params['labels'] = implode(',', $_REQUEST['searchlabel']);
            // No labels selected? That must be an error!
            if (empty($_REQUEST['searchlabel'])) {
                $context['search_errors']['no_labels_selected'] = true;
            } elseif (count($_REQUEST['searchlabel']) != count($context['labels'])) {
                $labelQuery = '
				AND {raw:label_implode}';
                $labelStatements = array();
                foreach ($_REQUEST['searchlabel'] as $label) {
                    $labelStatements[] = $db->quote('FIND_IN_SET({string:label}, pmr.labels) != 0', array('label' => $label));
                }
                $searchq_parameters['label_implode'] = '(' . implode(' OR ', $labelStatements) . ')';
            }
        }
        // Unfortunately, searching for words like this is going to be slow, so we're blacklisting them.
        $blacklisted_words = array('quote', 'the', 'is', 'it', 'are', 'if');
        // What are we actually searching for?
        $search_params['search'] = !empty($search_params['search']) ? $search_params['search'] : (isset($_REQUEST['search']) ? $_REQUEST['search'] : '');
        // If nothing is left to search on - we set an error!
        if (!isset($search_params['search']) || $search_params['search'] == '') {
            $context['search_errors']['invalid_search_string'] = true;
        }
        // Change non-word characters into spaces.
        $stripped_query = preg_replace('~(?:[\\x0B\\0\\x{A0}\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~u', ' ', $search_params['search']);
        // Make the query lower case since it will case insensitive anyway.
        $stripped_query = un_htmlspecialchars(Util::strtolower($stripped_query));
        // 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 = preg_replace('~(?:^|\\s)(?:[-]?)"(?:[^"]+)"(?:$|\\s)~u', ' ', $search_params['search']);
        $wordArray = explode(' ', Util::htmlspecialchars(un_htmlspecialchars($wordArray), ENT_QUOTES));
        // A minus sign in front of a word excludes the word.... so...
        $excludedWords = array();
        // 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
        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 thats close to empty.
            if (($searchArray[$index] = trim($value, '-_\' ')) === '') {
                unset($searchArray[$index]);
            } elseif (in_array($searchArray[$index], $blacklisted_words)) {
                $foundBlackListedWords = true;
                unset($searchArray[$index]);
            }
            $searchArray[$index] = Util::strtolower(trim($value));
            if ($searchArray[$index] == '') {
                unset($searchArray[$index]);
            } else {
                // Sort out entities first.
                $searchArray[$index] = Util::htmlspecialchars($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>';
        }
        // This contains *everything*
        $searchWords = array_merge($searchArray, $excludedWords);
        // Make sure at least one word is being searched for.
        if (empty($searchArray)) {
            $context['search_errors']['invalid_search_string' . (!empty($foundBlackListedWords) ? '_blacklist' : '')] = true;
        }
        // Sort out the search query so the user can edit it - if they want.
        $context['search_params'] = $search_params;
        if (isset($context['search_params']['search'])) {
            $context['search_params']['search'] = Util::htmlspecialchars($context['search_params']['search']);
        }
        if (isset($context['search_params']['userspec'])) {
            $context['search_params']['userspec'] = Util::htmlspecialchars($context['search_params']['userspec']);
        }
        // Now we have all the parameters, combine them together for pagination and the like...
        $context['params'] = array();
        foreach ($search_params as $k => $v) {
            $context['params'][] = $k . '|\'|' . $v;
        }
        $context['params'] = base64_encode(implode('|"|', $context['params']));
        // Compile the subject query part.
        $andQueryParts = array();
        foreach ($searchWords as $index => $word) {
            if ($word == '') {
                continue;
            }
            if ($search_params['subject_only']) {
                $andQueryParts[] = 'pm.subject' . (in_array($word, $excludedWords) ? ' NOT' : '') . ' LIKE {string:search_' . $index . '}';
            } else {
                $andQueryParts[] = '(pm.subject' . (in_array($word, $excludedWords) ? ' NOT' : '') . ' LIKE {string:search_' . $index . '} ' . (in_array($word, $excludedWords) ? 'AND pm.body NOT' : 'OR pm.body') . ' LIKE {string:search_' . $index . '})';
            }
            $searchq_parameters['search_' . $index] = '%' . strtr($word, array('_' => '\\_', '%' => '\\%')) . '%';
        }
        $searchQuery = ' 1=1';
        if (!empty($andQueryParts)) {
            $searchQuery = implode(!empty($search_params['searchtype']) && $search_params['searchtype'] == 2 ? ' OR ' : ' AND ', $andQueryParts);
        }
        // Age limits?
        $timeQuery = '';
        if (!empty($search_params['minage'])) {
            $timeQuery .= ' AND pm.msgtime < ' . (time() - $search_params['minage'] * 86400);
        }
        if (!empty($search_params['maxage'])) {
            $timeQuery .= ' AND pm.msgtime > ' . (time() - $search_params['maxage'] * 86400);
        }
        // If we have errors - return back to the first screen...
        if (!empty($context['search_errors'])) {
            $_REQUEST['params'] = $context['params'];
            return $this->action_search();
        }
        // Get the number of results.
        $numResults = numPMSeachResults($userQuery, $labelQuery, $timeQuery, $searchQuery, $searchq_parameters);
        // Get all the matching message ids, senders and head pm nodes
        list($foundMessages, $posters, $head_pms) = loadPMSearchMessages($userQuery, $labelQuery, $timeQuery, $searchQuery, $searchq_parameters, $search_params);
        // Find the real head pm when in converstaion view
        if ($context['display_mode'] == 2 && !empty($head_pms)) {
            $real_pm_ids = loadPMSearchHeads($head_pms);
        }
        // Load the found user data
        $posters = array_unique($posters);
        if (!empty($posters)) {
            loadMemberData($posters);
        }
        // Sort out the page index.
        $context['page_index'] = constructPageIndex($scripturl . '?action=pm;sa=search2;params=' . $context['params'], $_GET['start'], $numResults, $modSettings['search_results_per_page'], false);
        $context['message_labels'] = array();
        $context['message_replied'] = array();
        $context['personal_messages'] = array();
        $context['first_label'] = array();
        // If we have results, we have work to do!
        if (!empty($foundMessages)) {
            $recipients = array();
            list($context['message_labels'], $context['message_replied'], $context['message_unread'], $context['first_label']) = loadPMRecipientInfo($foundMessages, $recipients, $context['folder'], true);
            // Prepare for the callback!
            $search_results = loadPMSearchResults($foundMessages, $search_params);
            $counter = 0;
            foreach ($search_results as $row) {
                // If there's no subject, use the default.
                $row['subject'] = $row['subject'] == '' ? $txt['no_subject'] : $row['subject'];
                // Load this posters context info, if its not there then fill in the essentials...
                if (!loadMemberContext($row['id_member_from'], true)) {
                    $memberContext[$row['id_member_from']]['name'] = $row['from_name'];
                    $memberContext[$row['id_member_from']]['id'] = 0;
                    $memberContext[$row['id_member_from']]['group'] = $txt['guest_title'];
                    $memberContext[$row['id_member_from']]['link'] = $row['from_name'];
                    $memberContext[$row['id_member_from']]['email'] = '';
                    $memberContext[$row['id_member_from']]['show_email'] = showEmailAddress(true, 0);
                    $memberContext[$row['id_member_from']]['is_guest'] = true;
                }
                // Censor anything we don't want to see...
                censorText($row['body']);
                censorText($row['subject']);
                // Parse out any BBC...
                $row['body'] = parse_bbc($row['body'], true, 'pm' . $row['id_pm']);
                // Highlight the hits
                $body_highlighted = '';
                $subject_highlighted = '';
                foreach ($searchArray as $query) {
                    // Fix the international characters in the keyword too.
                    $query = un_htmlspecialchars($query);
                    $query = trim($query, '\\*+');
                    $query = strtr(Util::htmlspecialchars($query), array('\\\'' => '\''));
                    $body_highlighted = preg_replace_callback('/((<[^>]*)|' . preg_quote(strtr($query, array('\'' => '&#039;')), '/') . ')/iu', array($this, '_highlighted_callback'), $row['body']);
                    $subject_highlighted = preg_replace('/(' . preg_quote($query, '/') . ')/iu', '<strong class="highlight">$1</strong>', $row['subject']);
                }
                // Set a link using the first label information
                $href = $scripturl . '?action=pm;f=' . $context['folder'] . (isset($context['first_label'][$row['id_pm']]) ? ';l=' . $context['first_label'][$row['id_pm']] : '') . ';pmid=' . ($context['display_mode'] == 2 && isset($real_pm_ids[$head_pms[$row['id_pm']]]) && $context['folder'] == 'inbox' ? $real_pm_ids[$head_pms[$row['id_pm']]] : $row['id_pm']) . '#msg_' . $row['id_pm'];
                $context['personal_messages'][] = array('id' => $row['id_pm'], 'member' => &$memberContext[$row['id_member_from']], 'subject' => $subject_highlighted, 'body' => $body_highlighted, 'time' => standardTime($row['msgtime']), 'html_time' => htmlTime($row['msgtime']), 'timestamp' => forum_time(true, $row['msgtime']), 'recipients' => &$recipients[$row['id_pm']], 'labels' => &$context['message_labels'][$row['id_pm']], 'fully_labeled' => count($context['message_labels'][$row['id_pm']]) == count($context['labels']), 'is_replied_to' => &$context['message_replied'][$row['id_pm']], 'href' => $href, 'link' => '<a href="' . $href . '">' . $subject_highlighted . '</a>', 'counter' => ++$counter);
            }
        }
        // Finish off the context.
        $context['page_title'] = $txt['pm_search_title'];
        $context['sub_template'] = 'search_results';
        $context['menu_data_' . $context['pm_menu_id']]['current_area'] = 'search';
        $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=search', 'name' => $txt['pm_search_bar_title']);
    }
 public function action_register2()
 {
     global $txt, $modSettings, $context, $user_info;
     // Start collecting together any errors.
     $reg_errors = Error_Context::context('register', 0);
     // Check they are who they should be
     checkSession();
     if (!validateToken('register', 'post', true, false)) {
         $reg_errors->addError('token_verification');
     }
     // You can't register if it's disabled.
     if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3) {
         fatal_lang_error('registration_disabled', false);
     }
     // Well, if you don't agree, you can't register.
     if (!empty($modSettings['requireAgreement']) && !isset($_POST['checkbox_agreement'])) {
         $reg_errors->addError('agreement_unchecked');
     }
     // Make sure they came from *somewhere*, have a session.
     if (!isset($_SESSION['old_url'])) {
         redirectexit('action=register');
     }
     // Check their provider deatils match up correctly in case they're pulling something funny
     if ($_POST['provider'] != $_SESSION['extauth_info']['provider']) {
         redirectexit('action=register');
     }
     // Clean up
     foreach ($_POST as $key => $value) {
         if (!is_array($_POST[$key])) {
             $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
         }
     }
     // Needed for isReservedName() and registerMember()
     require_once SUBSDIR . '/Members.subs.php';
     // Needed for generateValidationCode()
     require_once SUBSDIR . '/Auth.subs.php';
     // Set the options needed for registration.
     $regOptions = array('interface' => 'guest', 'username' => !empty($_POST['user']) ? $_POST['user'] : '', 'email' => !empty($_POST['email']) ? $_POST['email'] : '', 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => true, 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']), 'require' => empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval'));
     // Lets check for other errors before trying to register the member.
     if ($reg_errors->hasErrors()) {
         return $this->action_register();
     }
     mt_srand(time() + 1277);
     $regOptions['password'] = generateValidationCode();
     $regOptions['password_check'] = $regOptions['password'];
     // Registration needs to know your IP
     $req = request();
     $regOptions['ip'] = $user_info['ip'];
     $regOptions['ip2'] = $req->ban_ip();
     $memberID = registerMember($regOptions, 'register');
     // If there are "important" errors and you are not an admin: log the first error
     // Otherwise grab all of them and don't log anything
     if ($reg_errors->hasErrors(1) && !$user_info['is_admin']) {
         foreach ($reg_errors->prepareErrors(1) as $error) {
             fatal_error($error, 'general');
         }
     }
     // One last error check
     if ($reg_errors->hasErrors()) {
         return $this->action_register();
     }
     // Do our spam protection now.
     spamProtection('register');
     // Since all is well, we'll go ahead and associate the member's external account
     addAuth($memberID, $_SESSION['extauth_info']['provider'], $_SESSION['extauth_info']['uid'], $_SESSION['extauth_info']['name']);
     // Basic template variable setup.
     if (!empty($modSettings['registration_method'])) {
         loadTemplate('Register');
         $context += array('page_title' => $txt['register'], 'title' => $txt['registration_successful'], 'sub_template' => 'after', 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']);
     } else {
         call_integration_hook('integrate_activate', array($regOptions['username']));
         setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash('sha256', Util::strtolower($regOptions['username']) . $regOptions['password'] . $regOptions['register_vars']['password_salt']));
         redirectexit('action=auth;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
     }
 }
Exemple #14
0
/**
 * Chops a string into words and prepares them to be inserted into (or searched from) the database.
 *
 * @param string $text
 * @param int|null $max_chars = 20
 *     - if encrypt = true this is the maximum number of bytes to use in integer hashes (for searching)
 *     - if encrypt = false this is the maximum number of letters in each word
 * @param bool $encrypt = false Used for custom search indexes to return an array of ints representing the words
 */
function text2words($text, $max_chars = 20, $encrypt = false)
{
    // Step 1: Remove entities/things we don't consider words:
    $words = preg_replace('~(?:[\\x0B\\0\\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(Util::strtolower($words));
    // Step 3: Ready to split apart and index!
    $words = explode(' ', $words);
    if ($encrypt) {
        // Range of characters that crypt will produce (0-9, a-z, A-Z .)
        $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, '-_\'')) !== '') {
                // Get a crypt representation of this work
                $encrypted = substr(crypt($word, 'uk'), 2, $max_chars);
                $total = 0;
                // Create an integer reprsentation
                for ($i = 0; $i < $max_chars; $i++) {
                    $total += $possible_chars[ord($encrypted[$i])] * pow(63, $i);
                }
                // Return the value
                $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);
    }
}
Exemple #15
0
 /**
  * Display members of a group, and allow adding of members to a group.
  *
  * What it does:
  * - It can be called from ManageMembergroups if it needs templating within the admin environment.
  * - It shows a list of members that are part of a given membergroup.
  * - It is called by ?action=moderate;area=viewgroups;sa=members;group=x
  * - It requires the manage_membergroups permission.
  * - It allows to add and remove members from the selected membergroup.
  * - It allows sorting on several columns.
  * - It redirects to itself.
  * @uses ManageMembergroups template, group_members sub template.
  */
 public function action_members()
 {
     global $txt, $scripturl, $context, $modSettings, $user_info, $settings;
     $current_group = isset($_REQUEST['group']) ? (int) $_REQUEST['group'] : 0;
     // These will be needed
     require_once SUBSDIR . '/Membergroups.subs.php';
     require_once SUBSDIR . '/Members.subs.php';
     // Load up the group details.
     $context['group'] = membergroupById($current_group, true, true);
     // No browsing of guests, membergroup 0 or moderators or non-existing groups.
     if ($context['group'] === false || in_array($current_group, array(-1, 0, 3))) {
         fatal_lang_error('membergroup_does_not_exist', false);
     }
     $context['group']['id'] = $context['group']['id_group'];
     $context['group']['name'] = $context['group']['group_name'];
     // Fix the membergroup icons.
     $context['group']['icons'] = explode('#', $context['group']['icons']);
     $context['group']['icons'] = !empty($context['group']['icons'][0]) && !empty($context['group']['icons'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/group_icons/' . $context['group']['icons'][1] . '" alt="*" />', $context['group']['icons'][0]) : '';
     $context['group']['can_moderate'] = allowedTo('manage_membergroups') && (allowedTo('admin_forum') || $context['group']['group_type'] != 1);
     // The template is very needy
     $context['linktree'][] = array('url' => $scripturl . '?action=groups;sa=members;group=' . $context['group']['id'], 'name' => $context['group']['name']);
     $context['can_send_email'] = allowedTo('send_email_to_members');
     $context['sort_direction'] = isset($_REQUEST['desc']) ? 'down' : 'up';
     $context['start'] = $_REQUEST['start'];
     $context['can_moderate_forum'] = allowedTo('moderate_forum');
     // @todo: use createList
     // Load all the group moderators, for fun.
     $context['group']['moderators'] = array();
     $moderators = getGroupModerators($current_group);
     foreach ($moderators as $id_member => $name) {
         $context['group']['moderators'][] = array('id' => $id_member, 'name' => $name);
         if ($user_info['id'] == $id_member && $context['group']['group_type'] != 1) {
             $context['group']['can_moderate'] = true;
         }
     }
     // If this group is hidden then it can only "exist" 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']) {
         // Security first
         checkSession();
         validateToken('mod-mgm');
         // Make sure we're dealing with integers only.
         foreach ($_REQUEST['rem'] as $key => $group) {
             $_REQUEST['rem'][$key] = (int) $group;
         }
         removeMembersFromGroups($_REQUEST['rem'], $current_group, true);
     } elseif (isset($_REQUEST['add']) && (!empty($_REQUEST['toAdd']) || !empty($_REQUEST['member_add'])) && $context['group']['assignable']) {
         // Make sure you can do this
         checkSession();
         validateToken('mod-mgm');
         $member_query = array(array('and' => 'not_in_group'));
         $member_parameters = array('not_in_group' => $current_group);
         // Get all the members to be added... taking into account names can be quoted ;)
         $_REQUEST['toAdd'] = strtr(Util::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(Util::strtolower($member_names[$index]));
             if (strlen($member_names[$index]) == 0) {
                 unset($member_names[$index]);
             }
         }
         // Any members 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, first for adds by name
         if (!empty($member_ids)) {
             $member_query[] = array('or' => 'member_ids');
             $member_parameters['member_ids'] = $member_ids;
         }
         // And then adds by ID
         if (!empty($member_names)) {
             $member_query[] = array('or' => 'member_names');
             $member_parameters['member_names'] = $member_names;
         }
         // Get back the ones that were not already in the group
         $members = membersBy($member_query, $member_parameters);
         // Do the updates...
         if (!empty($members)) {
             addMembersToGroup($members, $current_group, $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, or tried a wrong one, so default to by name..
     if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']])) {
         $context['sort_by'] = 'name';
         $querySort = 'real_name' . (isset($_REQUEST['desc']) ? ' DESC' : ' ASC');
     } else {
         $context['sort_by'] = $_REQUEST['sort'];
         $querySort = $sort_methods[$_REQUEST['sort']] . (isset($_REQUEST['desc']) ? ' DESC' : ' ASC');
     }
     // 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'] ? 'in_post_group' : 'in_group';
     } else {
         $where = $context['group']['is_post_group'] ? 'in_post_group' : 'in_group_no_add';
     }
     // Count members of the group.
     $context['total_members'] = countMembersBy($where, array($where => $current_group));
     $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=' . $current_group . ';sort=' . $context['sort_by'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $context['total_members'], $modSettings['defaultMaxMembers']);
     // Fetch the members that meet the where criteria
     $context['members'] = membersBy($where, array($where => $current_group, 'order' => $querySort), true);
     foreach ($context['members'] as $id => $row) {
         $last_online = empty($row['last_login']) ? $txt['never'] : standardTime($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'][$id] = 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' => standardTime($row['date_registered']), 'last_online' => $last_online, 'posts' => comma_format($row['posts']), 'is_activated' => $row['is_activated'] % 10 == 1);
     }
     if (!empty($context['group']['assignable'])) {
         loadJavascriptFile('suggest.js', array('defer' => true));
     }
     // Select the template.
     $context['sub_template'] = 'group_members';
     $context['page_title'] = $txt['membergroups_members_title'] . ': ' . $context['group']['name'];
     createToken('mod-mgm');
 }
Exemple #16
0
 function text2words($text)
 {
     // Step 1: Remove entities/things we don't consider words:
     $words = preg_replace('~(?:[\\x0B\\0\\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(Util::strtolower($words));
     // Step 3: Ready to split apart and index!
     $words = explode(' ', $words);
     // 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);
 }
 /**
  * Actually register the member.
  * @todo split this function in two functions:
  *  - a function that handles action=register2, which needs no parameter;
  *  - a function that processes the case of OpenID verification.
  *
  * @param bool $verifiedOpenID = false
  */
 public function action_register2($verifiedOpenID = false)
 {
     global $txt, $modSettings, $context, $user_info;
     // Start collecting together any errors.
     $reg_errors = Error_Context::context('register', 0);
     // We can't validate the token and the session with OpenID enabled.
     if (!$verifiedOpenID) {
         checkSession();
         if (!validateToken('register', 'post', true, false)) {
             $reg_errors->addError('token_verification');
         }
     }
     // Did we save some open ID fields?
     if ($verifiedOpenID && !empty($context['openid_save_fields'])) {
         foreach ($context['openid_save_fields'] as $id => $value) {
             $_POST[$id] = $value;
         }
     }
     // You can't register if it's disabled.
     if (!empty($modSettings['registration_method']) && $modSettings['registration_method'] == 3) {
         fatal_lang_error('registration_disabled', false);
     }
     // If we're using an agreement checkbox, did they check it?
     if (!empty($modSettings['checkboxAgreement']) && !empty($_POST['checkbox_agreement'])) {
         $_SESSION['registration_agreed'] = true;
     }
     // Things we don't do for people who have already confirmed their OpenID allegances via register.
     if (!$verifiedOpenID) {
         // Well, if you don't agree, you can't register.
         if (!empty($modSettings['requireAgreement']) && empty($_SESSION['registration_agreed'])) {
             redirectexit();
         }
         // Make sure they came from *somewhere*, have a session.
         if (!isset($_SESSION['old_url'])) {
             redirectexit('action=register');
         }
         // If we don't require an agreement, we need a extra check for coppa.
         if (empty($modSettings['requireAgreement']) && !empty($modSettings['coppaAge'])) {
             $_SESSION['skip_coppa'] = !empty($_POST['accept_agreement']);
         }
         // Are they under age, and under age users are banned?
         if (!empty($modSettings['coppaAge']) && empty($modSettings['coppaType']) && empty($_SESSION['skip_coppa'])) {
             loadLanguage('Login');
             fatal_lang_error('under_age_registration_prohibited', false, array($modSettings['coppaAge']));
         }
         // Check the time gate for miscreants. First make sure they came from somewhere that actually set it up.
         if (empty($_SESSION['register']['timenow']) || empty($_SESSION['register']['limit'])) {
             redirectexit('action=register');
         }
         // Failing that, check the time limit for exessive speed.
         if (time() - $_SESSION['register']['timenow'] < $_SESSION['register']['limit']) {
             loadLanguage('Login');
             $reg_errors->addError('too_quickly');
         }
         // Check whether the visual verification code was entered correctly.
         if (!empty($modSettings['reg_verification'])) {
             require_once SUBSDIR . '/VerificationControls.class.php';
             $verificationOptions = array('id' => 'register');
             $context['visual_verification'] = create_control_verification($verificationOptions, true);
             if (is_array($context['visual_verification'])) {
                 foreach ($context['visual_verification'] as $error) {
                     $reg_errors->addError($error);
                 }
             }
         }
     }
     foreach ($_POST as $key => $value) {
         if (!is_array($_POST[$key])) {
             $_POST[$key] = htmltrim__recursive(str_replace(array("\n", "\r"), '', $_POST[$key]));
         }
     }
     // Collect all extra registration fields someone might have filled in.
     $possible_strings = array('birthdate', 'time_format', 'buddy_list', 'pm_ignore_list', 'smiley_set', 'personal_text', 'avatar', 'lngfile', 'location', 'secret_question', 'secret_answer', 'website_url', 'website_title');
     $possible_ints = array('pm_email_notify', 'notify_types', 'id_theme', 'gender');
     $possible_floats = array('time_offset');
     $possible_bools = array('notify_announcements', 'notify_regularity', 'notify_send_body', 'hide_email', 'show_online');
     if (isset($_POST['secret_answer']) && $_POST['secret_answer'] != '') {
         $_POST['secret_answer'] = md5($_POST['secret_answer']);
     }
     // Needed for isReservedName() and registerMember().
     require_once SUBSDIR . '/Members.subs.php';
     // Validation... even if we're not a mall.
     if (isset($_POST['real_name']) && (!empty($modSettings['allow_editDisplayName']) || allowedTo('moderate_forum'))) {
         $_POST['real_name'] = trim(preg_replace('~[\\t\\n\\r \\x0B\\0\\x{A0}\\x{AD}\\x{2000}-\\x{200F}\\x{201F}\\x{202F}\\x{3000}\\x{FEFF}]+~u', ' ', $_POST['real_name']));
         if (trim($_POST['real_name']) != '' && !isReservedName($_POST['real_name']) && Util::strlen($_POST['real_name']) < 60) {
             $possible_strings[] = 'real_name';
         }
     }
     // Handle a string as a birthdate...
     if (isset($_POST['birthdate']) && $_POST['birthdate'] != '') {
         $_POST['birthdate'] = strftime('%Y-%m-%d', strtotime($_POST['birthdate']));
     } elseif (!empty($_POST['bday1']) && !empty($_POST['bday2'])) {
         $_POST['birthdate'] = sprintf('%04d-%02d-%02d', empty($_POST['bday3']) ? 0 : (int) $_POST['bday3'], (int) $_POST['bday1'], (int) $_POST['bday2']);
     }
     // By default assume email is hidden, only show it if we tell it to.
     $_POST['hide_email'] = !empty($_POST['allow_email']) ? 0 : 1;
     // Validate the passed language file.
     if (isset($_POST['lngfile']) && !empty($modSettings['userLanguage'])) {
         // Do we have any languages?
         $context['languages'] = getLanguages();
         // Did we find it?
         if (isset($context['languages'][$_POST['lngfile']])) {
             $_SESSION['language'] = $_POST['lngfile'];
         } else {
             unset($_POST['lngfile']);
         }
     } else {
         unset($_POST['lngfile']);
     }
     // Some of these fields we may not want.
     if (!empty($modSettings['registration_fields'])) {
         // But we might want some of them if the admin asks for them.
         $standard_fields = array('location', 'gender');
         $reg_fields = explode(',', $modSettings['registration_fields']);
         $exclude_fields = array_diff($standard_fields, $reg_fields);
         // Website is a little different
         if (!in_array('website', $reg_fields)) {
             $exclude_fields = array_merge($exclude_fields, array('website_url', 'website_title'));
         }
         // We used to accept signature on registration but it's being abused by spammers these days, so no more.
         $exclude_fields[] = 'signature';
     } else {
         $exclude_fields = array('signature', 'location', 'gender', 'website_url', 'website_title');
     }
     $possible_strings = array_diff($possible_strings, $exclude_fields);
     $possible_ints = array_diff($possible_ints, $exclude_fields);
     $possible_floats = array_diff($possible_floats, $exclude_fields);
     $possible_bools = array_diff($possible_bools, $exclude_fields);
     // Set the options needed for registration.
     $regOptions = array('interface' => 'guest', 'username' => !empty($_POST['user']) ? $_POST['user'] : '', 'email' => !empty($_POST['email']) ? $_POST['email'] : '', 'password' => !empty($_POST['passwrd1']) ? $_POST['passwrd1'] : '', 'password_check' => !empty($_POST['passwrd2']) ? $_POST['passwrd2'] : '', 'openid' => !empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : '', 'auth_method' => !empty($_POST['authenticate']) ? $_POST['authenticate'] : '', 'check_reserved_name' => true, 'check_password_strength' => true, 'check_email_ban' => true, 'send_welcome_email' => !empty($modSettings['send_welcomeEmail']), 'require' => !empty($modSettings['coppaAge']) && !$verifiedOpenID && empty($_SESSION['skip_coppa']) ? 'coppa' : (empty($modSettings['registration_method']) ? 'nothing' : ($modSettings['registration_method'] == 1 ? 'activation' : 'approval')), 'extra_register_vars' => array(), 'theme_vars' => array());
     // Include the additional options that might have been filled in.
     foreach ($possible_strings as $var) {
         if (isset($_POST[$var])) {
             $regOptions['extra_register_vars'][$var] = Util::htmlspecialchars($_POST[$var], ENT_QUOTES);
         }
     }
     foreach ($possible_ints as $var) {
         if (isset($_POST[$var])) {
             $regOptions['extra_register_vars'][$var] = (int) $_POST[$var];
         }
     }
     foreach ($possible_floats as $var) {
         if (isset($_POST[$var])) {
             $regOptions['extra_register_vars'][$var] = (double) $_POST[$var];
         }
     }
     foreach ($possible_bools as $var) {
         if (isset($_POST[$var])) {
             $regOptions['extra_register_vars'][$var] = empty($_POST[$var]) ? 0 : 1;
         }
     }
     // Registration options are always default options...
     if (isset($_POST['default_options'])) {
         $_POST['options'] = isset($_POST['options']) ? $_POST['options'] + $_POST['default_options'] : $_POST['default_options'];
     }
     $regOptions['theme_vars'] = isset($_POST['options']) && is_array($_POST['options']) ? $_POST['options'] : array();
     // Make sure they are clean, dammit!
     $regOptions['theme_vars'] = htmlspecialchars__recursive($regOptions['theme_vars']);
     // Check whether we have fields that simply MUST be displayed?
     require_once SUBSDIR . '/Profile.subs.php';
     loadCustomFields(0, 'register');
     foreach ($context['custom_fields'] as $row) {
         // Don't allow overriding of the theme variables.
         if (isset($regOptions['theme_vars'][$row['colname']])) {
             unset($regOptions['theme_vars'][$row['colname']]);
         }
         // Prepare the value!
         $value = isset($_POST['customfield'][$row['colname']]) ? trim($_POST['customfield'][$row['colname']]) : '';
         // We only care for text fields as the others are valid to be empty.
         if (!in_array($row['type'], array('check', 'select', 'radio'))) {
             // Is it too long?
             if ($row['field_length'] && $row['field_length'] < Util::strlen($value)) {
                 $reg_errors->addError(array('custom_field_too_long', array($row['name'], $row['field_length'])));
             }
             // Any masks to apply?
             if ($row['type'] == 'text' && !empty($row['mask']) && $row['mask'] != 'none') {
                 // @todo We never error on this - just ignore it at the moment...
                 if ($row['mask'] == 'email' && !isValidEmail($value)) {
                     $reg_errors->addError(array('custom_field_invalid_email', array($row['name'])));
                 } elseif ($row['mask'] == 'number' && preg_match('~[^\\d]~', $value)) {
                     $reg_errors->addError(array('custom_field_not_number', array($row['name'])));
                 } elseif (substr($row['mask'], 0, 5) == 'regex' && trim($value) !== '' && preg_match(substr($row['mask'], 5), $value) === 0) {
                     $reg_errors->addError(array('custom_field_inproper_format', array($row['name'])));
                 }
             }
         }
         // Is this required but not there?
         if (trim($value) == '' && $row['show_reg'] > 1) {
             $reg_errors->addError(array('custom_field_empty', array($row['name'])));
         }
     }
     // Lets check for other errors before trying to register the member.
     if ($reg_errors->hasErrors()) {
         $_REQUEST['step'] = 2;
         // If they've filled in some details but made an error then they need less time to finish
         $_SESSION['register']['limit'] = 4;
         return $this->action_register();
     }
     // If they're wanting to use OpenID we need to validate them first.
     if (empty($_SESSION['openid']['verified']) && !empty($_POST['authenticate']) && $_POST['authenticate'] == 'openid') {
         // What do we need to save?
         $save_variables = array();
         foreach ($_POST as $k => $v) {
             if (!in_array($k, array('sc', 'sesc', $context['session_var'], 'passwrd1', 'passwrd2', 'regSubmit'))) {
                 $save_variables[$k] = $v;
             }
         }
         require_once SUBSDIR . '/OpenID.subs.php';
         $openID = new OpenID();
         $openID->validate($_POST['openid_identifier'], false, $save_variables);
     } elseif ($verifiedOpenID || (!empty($_POST['openid_identifier']) || !empty($_SESSION['openid']['openid_uri'])) && $_POST['authenticate'] == 'openid') {
         $regOptions['username'] = !empty($_POST['user']) && trim($_POST['user']) != '' ? $_POST['user'] : $_SESSION['openid']['nickname'];
         $regOptions['email'] = !empty($_POST['email']) && trim($_POST['email']) != '' ? $_POST['email'] : $_SESSION['openid']['email'];
         $regOptions['auth_method'] = 'openid';
         $regOptions['openid'] = !empty($_SESSION['openid']['openid_uri']) ? $_SESSION['openid']['openid_uri'] : (!empty($_POST['openid_identifier']) ? $_POST['openid_identifier'] : '');
     }
     // Registration needs to know your IP
     $req = request();
     $regOptions['ip'] = $user_info['ip'];
     $regOptions['ip2'] = $req->ban_ip();
     $memberID = registerMember($regOptions, 'register');
     // If there are "important" errors and you are not an admin: log the first error
     // Otherwise grab all of them and don't log anything
     if ($reg_errors->hasErrors(1) && !$user_info['is_admin']) {
         foreach ($reg_errors->prepareErrors(1) as $error) {
             fatal_error($error, 'general');
         }
     }
     // Was there actually an error of some kind dear boy?
     if ($reg_errors->hasErrors()) {
         $_REQUEST['step'] = 2;
         return $this->action_register();
     }
     // Do our spam protection now.
     spamProtection('register');
     // We'll do custom fields after as then we get to use the helper function!
     if (!empty($_POST['customfield'])) {
         require_once SUBSDIR . '/Profile.subs.php';
         makeCustomFieldChanges($memberID, 'register');
     }
     // If COPPA has been selected then things get complicated, setup the template.
     if (!empty($modSettings['coppaAge']) && empty($_SESSION['skip_coppa'])) {
         redirectexit('action=coppa;member=' . $memberID);
     } elseif (!empty($modSettings['registration_method'])) {
         loadTemplate('Register');
         $context += array('page_title' => $txt['register'], 'title' => $txt['registration_successful'], 'sub_template' => 'after', 'description' => $modSettings['registration_method'] == 2 ? $txt['approval_after_registration'] : $txt['activate_after_registration']);
     } else {
         call_integration_hook('integrate_activate', array($regOptions['username']));
         setLoginCookie(60 * $modSettings['cookieTime'], $memberID, hash('sha256', Util::strtolower($regOptions['username']) . $regOptions['password'] . $regOptions['register_vars']['password_salt']));
         redirectexit('action=auth;sa=check;member=' . $memberID, $context['server']['needs_login_fix']);
     }
 }
 /**
  * List all members, page by page, with sorting.
  * Called from MemberList().
  * Can be passed a sort parameter, to order the display of members.
  * Calls printMemberListRows to retrieve the results of the query.
  */
 public function action_mlall()
 {
     global $txt, $scripturl, $modSettings, $context;
     // The chunk size for the cached index.
     $cache_step_size = 500;
     require_once SUBSDIR . '/Memberlist.subs.php';
     // 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']) {
             $memberlist_cache = ml_memberCache($cache_step_size);
         }
         $context['num_members'] = $memberlist_cache['num_members'];
     } else {
         $context['num_members'] = ml_memberCount();
     }
     // 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', Util::strtolower($_REQUEST['start']), $match) === 0) {
             fatal_error('Hacker?', false);
         }
         $_REQUEST['start'] = ml_alphaStart($match[0]);
     }
     // Build out the letter selection link bar
     $context['letter_links'] = '';
     for ($i = 97; $i < 123; $i++) {
         $context['letter_links'] .= '<a href="' . $scripturl . '?action=memberlist;sa=all;start=' . chr($i) . '#letter' . chr($i) . '">' . chr($i - 32) . '</a> ';
     }
     // Sort out the column information.
     foreach ($context['columns'] as $col => $column_details) {
         $context['columns'][$col]['href'] = $scripturl . '?action=memberlist;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;
         if ($context['columns'][$col]['selected']) {
             $context['columns'][$col]['class'] .= ' selected';
         }
     }
     // Are we sorting the results
     $context['sort_by'] = $_REQUEST['sort'];
     $context['sort_direction'] = !isset($_REQUEST['desc']) ? 'up' : 'down';
     // Construct the page index.
     $context['page_index'] = constructPageIndex($scripturl . '?action=memberlist;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=memberlist;sort=' . $_REQUEST['sort'] . ';start=' . $_REQUEST['start'], 'name' => &$context['page_title'], 'extra_after' => ' (' . sprintf($txt['of_total_members'], $context['num_members']) . ')');
     $limit = $_REQUEST['start'];
     $where = '';
     $query_parameters = array('regular_id_group' => 0, 'is_activated' => 1, 'sort' => $context['columns'][$_REQUEST['sort']]['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);
     }
     // Add custom fields parameters too.
     if (!empty($context['custom_profile_fields']['parameters'])) {
         $query_parameters += $context['custom_profile_fields']['parameters'];
     }
     // Select the members from the database.
     ml_selectMembers($query_parameters, $where, $limit, $_REQUEST['sort']);
     // Add anchors at the start of each letter.
     if ($_REQUEST['sort'] === 'real_name') {
         $last_letter = '';
         foreach ($context['members'] as $i => $dummy) {
             $this_letter = Util::strtolower(Util::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, ENT_COMPAT, 'UTF-8');
                 $last_letter = $this_letter;
             }
         }
     }
 }
 /**
  * Checks if an the answers to anti-spam questions are correct
  *
  * @return boolean
  */
 private function _verifyAnswers()
 {
     // Get the answers and see if they are all right!
     $questions = $this->_loadAntispamQuestions(array('type' => 'id_question', 'value' => $_SESSION[$this->_options['id'] . '_vv']['q']));
     $this->_incorrectQuestions = array();
     foreach ($questions as $row) {
         // Everything lowercase
         $answers = array();
         foreach ($row['answer'] as $answer) {
             $answers[] = Util::strtolower($answer);
         }
         if (!isset($_REQUEST[$this->_options['id'] . '_vv']['q'][$row['id_question']]) || trim($_REQUEST[$this->_options['id'] . '_vv']['q'][$row['id_question']]) == '' || !in_array(trim(Util::htmlspecialchars(Util::strtolower($_REQUEST[$this->_options['id'] . '_vv']['q'][$row['id_question']]))), $answers)) {
             $this->_incorrectQuestions[] = $row['id_question'];
         }
     }
     return empty($this->_incorrectQuestions);
 }
 /**
  * Setup spellchecking suggestions and load them into $context
  *
  * @param string[] $search_params the search parameters
  * @param string[] $searchArray an array of terms
  */
 private function _load_suggestions($search_params, $searchArray = array())
 {
     global $txt, $context;
     // Windows fix.
     ob_start();
     $old = error_reporting(0);
     pspell_new('en');
     $pspell_link = pspell_new($txt['lang_dictionary'], $txt['lang_spelling'], '', 'utf-8', PSPELL_FAST | PSPELL_RUN_TOGETHER);
     if (!$pspell_link) {
         $pspell_link = pspell_new('en', '', '', '', PSPELL_FAST | PSPELL_RUN_TOGETHER);
     }
     error_reporting($old);
     @ob_end_clean();
     $did_you_mean = array('search' => array(), 'display' => array());
     $found_misspelling = false;
     foreach ($searchArray as $word) {
         if (empty($pspell_link)) {
             continue;
         }
         // Don't check phrases.
         if (preg_match('~^\\w+$~', $word) === 0) {
             $did_you_mean['search'][] = '"' . $word . '"';
             $did_you_mean['display'][] = '&quot;' . Util::htmlspecialchars($word) . '&quot;';
             continue;
         } elseif (preg_match('~\\d~', $word) === 1) {
             $did_you_mean['search'][] = $word;
             $did_you_mean['display'][] = Util::htmlspecialchars($word);
             continue;
         } elseif (pspell_check($pspell_link, $word)) {
             $did_you_mean['search'][] = $word;
             $did_you_mean['display'][] = Util::htmlspecialchars($word);
             continue;
         }
         $suggestions = pspell_suggest($pspell_link, $word);
         foreach ($suggestions as $i => $s) {
             // Search is case insensitive.
             if (Util::strtolower($s) == Util::strtolower($word)) {
                 unset($suggestions[$i]);
             } elseif ($suggestions[$i] != censorText($s)) {
                 unset($suggestions[$i]);
             }
         }
         // Anything found?  If so, correct it!
         if (!empty($suggestions)) {
             $suggestions = array_values($suggestions);
             $did_you_mean['search'][] = $suggestions[0];
             $did_you_mean['display'][] = '<em><strong>' . Util::htmlspecialchars($suggestions[0]) . '</strong></em>';
             $found_misspelling = true;
         } else {
             $did_you_mean['search'][] = $word;
             $did_you_mean['display'][] = Util::htmlspecialchars($word);
         }
     }
     if ($found_misspelling) {
         // Don't spell check excluded words, but add them still...
         $temp_excluded = array('search' => array(), 'display' => array());
         if (!empty($excludedWords)) {
             foreach ($excludedWords as $word) {
                 if (preg_match('~^\\w+$~', $word) == 0) {
                     $temp_excluded['search'][] = '-"' . $word . '"';
                     $temp_excluded['display'][] = '-&quot;' . Util::htmlspecialchars($word) . '&quot;';
                 } else {
                     $temp_excluded['search'][] = '-' . $word;
                     $temp_excluded['display'][] = '-' . Util::htmlspecialchars($word);
                 }
             }
         }
         $did_you_mean['search'] = array_merge($did_you_mean['search'], $temp_excluded['search']);
         $did_you_mean['display'] = array_merge($did_you_mean['display'], $temp_excluded['display']);
         $search_params['search'] = implode(' ', $did_you_mean['search']);
         if (isset($search_params['brd'])) {
             $search_params['brd'] = implode(',', $search_params['brd']);
         }
         $context['params'] = array();
         foreach ($search_params as $k => $v) {
             $context['did_you_mean_params'][] = $k . '|\'|' . $v;
         }
         $context['did_you_mean_params'] = base64_encode(implode('|"|', $context['did_you_mean_params']));
         $context['did_you_mean'] = implode(' ', $did_you_mean['display']);
     }
 }
 /**
  * Cleans a string of everything but alphanumeric characters
  *
  * @param string $string A string to clean
  * @return string A cleaned up string
  */
 private function _cleanString($string)
 {
     // Decode the entities first
     $string = html_entity_decode($string, ENT_QUOTES, 'UTF-8');
     // Lowercase string
     $string = Util::strtolower($string);
     // Fix numbers so they search easier (phone numbers, SSN, dates, etc)
     $string = preg_replace('~([[:digit:]]+)\\pP+(?=[[:digit:]])~u', '', $string);
     // Last but not least, strip everything out that's not alphanumeric
     $string = preg_replace('~[^\\pL\\pN]+~u', ' ', $string);
     return $string;
 }
Exemple #22
0
/**
 * Gets a list of available languages from the mother ship
 *
 * - Will return a subset if searching, otherwise all available
 *
 * @package Languages
 * @return string
 */
function list_getLanguagesList()
{
    global $forum_version, $context, $txt, $scripturl;
    // We're going to use this URL.
    // @todo no we are not, this needs to be changed - again
    $url = 'http://download.elkarte.net/fetch_language.php?version=' . urlencode(strtr($forum_version, array('ElkArte ' => '')));
    // Load the class file and stick it into an array.
    require_once SUBSDIR . '/XmlArray.class.php';
    $language_list = new Xml_Array(fetch_web_data($url), true);
    // Check that the site responded and that the language exists.
    if (!$language_list->exists('languages')) {
        $context['langfile_error'] = 'no_response';
    } elseif (!$language_list->exists('languages/language')) {
        $context['langfile_error'] = 'no_files';
    } else {
        $language_list = $language_list->path('languages[0]');
        $lang_files = $language_list->set('language');
        $languages = array();
        foreach ($lang_files as $file) {
            // Were we searching?
            if (!empty($context['elk_search_term']) && strpos($file->fetch('name'), Util::strtolower($context['elk_search_term'])) === false) {
                continue;
            }
            $languages[] = array('id' => $file->fetch('id'), 'name' => Util::ucwords($file->fetch('name')), 'version' => $file->fetch('version'), 'utf8' => $txt['yes'], 'description' => $file->fetch('description'), 'install_link' => '<a href="' . $scripturl . '?action=admin;area=languages;sa=downloadlang;did=' . $file->fetch('id') . ';' . $context['session_var'] . '=' . $context['session_id'] . '">' . $txt['add_language_elk_install'] . '</a>');
        }
        if (empty($languages)) {
            $context['langfile_error'] = 'no_files';
        } else {
            return $languages;
        }
    }
}