Ejemplo n.º 1
0
/**
 * A very simple function to determine if an email address is "valid" for Elkarte.
 * A valid email for ElkArte is something that resebles an email (filter_var) and
 * is less than 255 characters (for database limits)
 *
 * @param string $value - The string to evaluate as valid email
 * @return bool|string - The email if valid, false if not a valid email
 */
function isValidEmail($value)
{
    $value = trim($value);
    if (filter_var($value, FILTER_VALIDATE_EMAIL) && Util::strlen($value) < 255) {
        return $value;
    } else {
        return false;
    }
}
Ejemplo n.º 2
0
/**
 * Recent topic list:
 *  [board] Subject by Poster Date
 *
 * @param int $num_recent
 * @param int[]|null $exclude_boards
 * @param bool|null $include_boards
 * @param string $output_method = 'echo'
 */
function ssi_recentTopics($num_recent = 8, $exclude_boards = null, $include_boards = null, $output_method = 'echo')
{
    global $settings, $scripturl, $txt, $user_info, $modSettings;
    $db = database();
    if ($exclude_boards === null && !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0) {
        $exclude_boards = array($modSettings['recycle_board']);
    } else {
        $exclude_boards = empty($exclude_boards) ? array() : (is_array($exclude_boards) ? $exclude_boards : array($exclude_boards));
    }
    // Only some boards?.
    if (is_array($include_boards) || (int) $include_boards === $include_boards) {
        $include_boards = is_array($include_boards) ? $include_boards : array($include_boards);
    } elseif ($include_boards != null) {
        $output_method = $include_boards;
        $include_boards = array();
    }
    require_once SUBSDIR . '/MessageIndex.subs.php';
    $icon_sources = MessageTopicIcons();
    // Find all the posts in distinct topics. Newer ones will have higher IDs.
    $request = $db->query('', '
		SELECT
			t.id_topic, b.id_board, b.name AS board_name
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
			LEFT JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
		WHERE t.id_last_msg >= {int:min_message_id}' . (empty($exclude_boards) ? '' : '
			AND b.id_board NOT IN ({array_int:exclude_boards})') . '' . (empty($include_boards) ? '' : '
			AND b.id_board IN ({array_int:include_boards})') . '
			AND {query_wanna_see_board}' . ($modSettings['postmod_active'] ? '
			AND t.approved = {int:is_approved}
			AND ml.approved = {int:is_approved}' : '') . '
		ORDER BY t.id_last_msg DESC
		LIMIT ' . $num_recent, array('include_boards' => empty($include_boards) ? '' : $include_boards, 'exclude_boards' => empty($exclude_boards) ? '' : $exclude_boards, 'min_message_id' => $modSettings['maxMsgID'] - 35 * min($num_recent, 5), 'is_approved' => 1));
    $topics = array();
    while ($row = $db->fetch_assoc($request)) {
        $topics[$row['id_topic']] = $row;
    }
    $db->free_result($request);
    // Did we find anything? If not, bail.
    if (empty($topics)) {
        return array();
    }
    // Find all the posts in distinct topics. Newer ones will have higher IDs.
    $request = $db->query('substring', '
		SELECT
			mf.poster_time, mf.subject, ml.id_topic, mf.id_member, ml.id_msg, t.num_replies, t.num_views, mg.online_color,
			IFNULL(mem.real_name, mf.poster_name) AS poster_name, ' . ($user_info['is_guest'] ? '1 AS is_read, 0 AS new_from' : '
			IFNULL(lt.id_msg, IFNULL(lmr.id_msg, 0)) >= ml.id_msg_modified AS is_read,
			IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from') . ', SUBSTRING(mf.body, 1, 384) AS body, mf.smileys_enabled, mf.icon
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}messages AS ml ON (ml.id_msg = t.id_last_msg)
			INNER JOIN {db_prefix}messages AS mf ON (mf.id_msg = t.id_last_msg)
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = mf.id_member)' . (!$user_info['is_guest'] ? '
			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
			LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board AND lmr.id_member = {int:current_member})' : '') . '
			LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = mem.id_group)
		WHERE t.id_topic IN ({array_int:topic_list})', array('current_member' => $user_info['id'], 'topic_list' => array_keys($topics)));
    $posts = array();
    while ($row = $db->fetch_assoc($request)) {
        $row['body'] = strip_tags(strtr(parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']), array('<br />' => '&#10;')));
        if (Util::strlen($row['body']) > 128) {
            $row['body'] = Util::substr($row['body'], 0, 128) . '...';
        }
        // Censor the subject.
        censorText($row['subject']);
        censorText($row['body']);
        if (!empty($modSettings['messageIconChecks_enable']) && !isset($icon_sources[$row['icon']])) {
            $icon_sources[$row['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $row['icon'] . '.png') ? 'images_url' : 'default_images_url';
        }
        // Build the array.
        $posts[] = array('board' => array('id' => $topics[$row['id_topic']]['id_board'], 'name' => $topics[$row['id_topic']]['board_name'], 'href' => $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $topics[$row['id_topic']]['id_board'] . '.0">' . $topics[$row['id_topic']]['board_name'] . '</a>'), 'topic' => $row['id_topic'], 'poster' => array('id' => $row['id_member'], 'name' => $row['poster_name'], 'href' => empty($row['id_member']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => empty($row['id_member']) ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>'), 'subject' => $row['subject'], 'replies' => $row['num_replies'], 'views' => $row['num_views'], 'short_subject' => Util::shorten_text($row['subject'], 25), 'preview' => $row['body'], 'time' => standardTime($row['poster_time']), 'html_time' => htmlTime($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . ';topicseen#new', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#new" rel="nofollow">' . $row['subject'] . '</a>', 'new' => !empty($row['is_read']), 'is_new' => empty($row['is_read']), 'new_from' => $row['new_from'], 'icon' => '<img src="' . $settings[$icon_sources[$row['icon']]] . '/post/' . $row['icon'] . '.png" style="vertical-align: middle;" alt="' . $row['icon'] . '" />');
    }
    $db->free_result($request);
    // Just return it.
    if ($output_method != 'echo' || empty($posts)) {
        return $posts;
    }
    echo '
		<table class="ssi_table">';
    foreach ($posts as $post) {
        echo '
			<tr>
				<td class="righttext top">
					[', $post['board']['link'], ']
				</td>
				<td class="top">
					<a href="', $post['href'], '">', $post['subject'], '</a>
					', $txt['by'], ' ', $post['poster']['link'], '
					', !$post['is_new'] ? '' : '<a href="' . $scripturl . '?topic=' . $post['topic'] . '.msg' . $post['new_from'] . ';topicseen#new" rel="nofollow"><span class="new_posts">' . $txt['new'] . '</span></a>', '
				</td>
				<td class="righttext">
					', $post['time'], '
				</td>
			</tr>';
    }
    echo '
		</table>';
}
Ejemplo n.º 3
0
/**
 * Makes sure the calendar post is valid.
 *
 * @package Calendar
 */
function validateEventPost()
{
    global $modSettings;
    if (!isset($_POST['deleteevent'])) {
        // No month?  No year?
        if (!isset($_POST['month'])) {
            fatal_lang_error('event_month_missing', false);
        }
        if (!isset($_POST['year'])) {
            fatal_lang_error('event_year_missing', false);
        }
        // Check the month and year...
        if ($_POST['month'] < 1 || $_POST['month'] > 12) {
            fatal_lang_error('invalid_month', false);
        }
        if ($_POST['year'] < $modSettings['cal_minyear'] || $_POST['year'] > $modSettings['cal_maxyear']) {
            fatal_lang_error('invalid_year', false);
        }
    }
    // Make sure they're allowed to post...
    isAllowedTo('calendar_post');
    if (isset($_POST['span'])) {
        // Make sure it's turned on and not some fool trying to trick it.
        if (empty($modSettings['cal_allowspan'])) {
            fatal_lang_error('no_span', false);
        }
        if ($_POST['span'] < 1 || $_POST['span'] > $modSettings['cal_maxspan']) {
            fatal_lang_error('invalid_days_numb', false);
        }
    }
    // There is no need to validate the following values if we are just deleting the event.
    if (!isset($_POST['deleteevent'])) {
        // No day?
        if (!isset($_POST['day'])) {
            fatal_lang_error('event_day_missing', false);
        }
        if (!isset($_POST['evtitle']) && !isset($_POST['subject'])) {
            fatal_lang_error('event_title_missing', false);
        } elseif (!isset($_POST['evtitle'])) {
            $_POST['evtitle'] = $_POST['subject'];
        }
        // Bad day?
        if (!checkdate($_POST['month'], $_POST['day'], $_POST['year'])) {
            fatal_lang_error('invalid_date', false);
        }
        // No title?
        if (Util::htmltrim($_POST['evtitle']) === '') {
            fatal_lang_error('no_event_title', false);
        }
        if (Util::strlen($_POST['evtitle']) > 100) {
            $_POST['evtitle'] = Util::substr($_POST['evtitle'], 0, 100);
        }
        $_POST['evtitle'] = str_replace(';', '', $_POST['evtitle']);
    }
}
Ejemplo n.º 4
0
/**
 * General function to split off a topic.
 * creates a new topic and moves the messages with the IDs in
 * array messagesToBeSplit to the new topic.
 * the subject of the newly created topic is set to 'newSubject'.
 * marks the newly created message as read for the user splitting it.
 * updates the statistics to reflect a newly created topic.
 * logs the action in the moderation log.
 * a notification is sent to all users monitoring this topic.
 *
 * @param int $split1_ID_TOPIC
 * @param int[] $splitMessages
 * @param string $new_subject
 * @return int the topic ID of the new split topic.
 */
function splitTopic($split1_ID_TOPIC, $splitMessages, $new_subject)
{
    global $txt;
    $db = database();
    // Nothing to split?
    if (empty($splitMessages)) {
        fatal_lang_error('no_posts_selected', false);
    }
    // Get some board info.
    $request = $db->query('', '
		SELECT id_board, approved
		FROM {db_prefix}topics
		WHERE id_topic = {int:id_topic}
		LIMIT 1', array('id_topic' => $split1_ID_TOPIC));
    list($id_board, $split1_approved) = $db->fetch_row($request);
    $db->free_result($request);
    // Find the new first and last not in the list. (old topic)
    $request = $db->query('', '
		SELECT
			MIN(m.id_msg) AS myid_first_msg, MAX(m.id_msg) AS myid_last_msg, COUNT(*) AS message_count, m.approved
		FROM {db_prefix}messages AS m
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:id_topic})
		WHERE m.id_msg NOT IN ({array_int:no_msg_list})
			AND m.id_topic = {int:id_topic}
		GROUP BY m.approved
		ORDER BY m.approved DESC
		LIMIT 2', array('id_topic' => $split1_ID_TOPIC, 'no_msg_list' => $splitMessages));
    // You can't select ALL the messages!
    if ($db->num_rows($request) == 0) {
        fatal_lang_error('selected_all_posts', false);
    }
    $split1_first_msg = null;
    $split1_last_msg = null;
    while ($row = $db->fetch_assoc($request)) {
        // Get the right first and last message dependant on approved state...
        if (empty($split1_first_msg) || $row['myid_first_msg'] < $split1_first_msg) {
            $split1_first_msg = $row['myid_first_msg'];
        }
        if (empty($split1_last_msg) || $row['approved']) {
            $split1_last_msg = $row['myid_last_msg'];
        }
        // Get the counts correct...
        if ($row['approved']) {
            $split1_replies = $row['message_count'] - 1;
            $split1_unapprovedposts = 0;
        } else {
            if (!isset($split1_replies)) {
                $split1_replies = 0;
            } elseif (!$split1_approved) {
                $split1_replies++;
            }
            $split1_unapprovedposts = $row['message_count'];
        }
    }
    $db->free_result($request);
    $split1_firstMem = getMsgMemberID($split1_first_msg);
    $split1_lastMem = getMsgMemberID($split1_last_msg);
    // Find the first and last in the list. (new topic)
    $request = $db->query('', '
		SELECT MIN(id_msg) AS myid_first_msg, MAX(id_msg) AS myid_last_msg, COUNT(*) AS message_count, approved
		FROM {db_prefix}messages
		WHERE id_msg IN ({array_int:msg_list})
			AND id_topic = {int:id_topic}
		GROUP BY id_topic, approved
		ORDER BY approved DESC
		LIMIT 2', array('msg_list' => $splitMessages, 'id_topic' => $split1_ID_TOPIC));
    while ($row = $db->fetch_assoc($request)) {
        // As before get the right first and last message dependant on approved state...
        if (empty($split2_first_msg) || $row['myid_first_msg'] < $split2_first_msg) {
            $split2_first_msg = $row['myid_first_msg'];
        }
        if (empty($split2_last_msg) || $row['approved']) {
            $split2_last_msg = $row['myid_last_msg'];
        }
        // Then do the counts again...
        if ($row['approved']) {
            $split2_approved = true;
            $split2_replies = $row['message_count'] - 1;
            $split2_unapprovedposts = 0;
        } else {
            // Should this one be approved??
            if ($split2_first_msg == $row['myid_first_msg']) {
                $split2_approved = false;
            }
            if (!isset($split2_replies)) {
                $split2_replies = 0;
            } elseif (!$split2_approved) {
                $split2_replies++;
            }
            $split2_unapprovedposts = $row['message_count'];
        }
    }
    $db->free_result($request);
    $split2_firstMem = getMsgMemberID($split2_first_msg);
    $split2_lastMem = getMsgMemberID($split2_last_msg);
    // No database changes yet, so let's double check to see if everything makes at least a little sense.
    if ($split1_first_msg <= 0 || $split1_last_msg <= 0 || $split2_first_msg <= 0 || $split2_last_msg <= 0 || $split1_replies < 0 || $split2_replies < 0 || $split1_unapprovedposts < 0 || $split2_unapprovedposts < 0 || !isset($split1_approved) || !isset($split2_approved)) {
        fatal_lang_error('cant_find_messages');
    }
    // You cannot split off the first message of a topic.
    if ($split1_first_msg > $split2_first_msg) {
        fatal_lang_error('split_first_post', false);
    }
    // We're off to insert the new topic!  Use 0 for now to avoid UNIQUE errors.
    $db->insert('', '{db_prefix}topics', array('id_board' => 'int', 'id_member_started' => 'int', 'id_member_updated' => 'int', 'id_first_msg' => 'int', 'id_last_msg' => 'int', 'num_replies' => 'int', 'unapproved_posts' => 'int', 'approved' => 'int', 'is_sticky' => 'int'), array((int) $id_board, $split2_firstMem, $split2_lastMem, 0, 0, $split2_replies, $split2_unapprovedposts, (int) $split2_approved, 0), array('id_topic'));
    $split2_ID_TOPIC = $db->insert_id('{db_prefix}topics', 'id_topic');
    if ($split2_ID_TOPIC <= 0) {
        fatal_lang_error('cant_insert_topic');
    }
    // Move the messages over to the other topic.
    $new_subject = strtr(Util::htmltrim(Util::htmlspecialchars($new_subject)), array("\r" => '', "\n" => '', "\t" => ''));
    // Check the subject length.
    if (Util::strlen($new_subject) > 100) {
        $new_subject = Util::substr($new_subject, 0, 100);
    }
    // Valid subject?
    if ($new_subject != '') {
        $db->query('', '
			UPDATE {db_prefix}messages
			SET
				id_topic = {int:id_topic},
				subject = CASE WHEN id_msg = {int:split_first_msg} THEN {string:new_subject} ELSE {string:new_subject_replies} END
			WHERE id_msg IN ({array_int:split_msgs})', array('split_msgs' => $splitMessages, 'id_topic' => $split2_ID_TOPIC, 'new_subject' => $new_subject, 'split_first_msg' => $split2_first_msg, 'new_subject_replies' => $txt['response_prefix'] . $new_subject));
        // Cache the new topics subject... we can do it now as all the subjects are the same!
        updateStats('subject', $split2_ID_TOPIC, $new_subject);
    }
    // Any associated reported posts better follow...
    require_once SUBSDIR . '/Topic.subs.php';
    updateSplitTopics(array('splitMessages' => $splitMessages, 'split2_ID_TOPIC' => $split2_ID_TOPIC, 'split1_replies' => $split1_replies, 'split1_first_msg' => $split1_first_msg, 'split1_last_msg' => $split1_last_msg, 'split1_firstMem' => $split1_firstMem, 'split1_lastMem' => $split1_lastMem, 'split1_unapprovedposts' => $split1_unapprovedposts, 'split1_ID_TOPIC' => $split1_ID_TOPIC, 'split2_first_msg' => $split2_first_msg, 'split2_last_msg' => $split2_last_msg, 'split2_ID_TOPIC' => $split2_ID_TOPIC, 'split2_approved' => $split2_approved), $id_board);
    require_once SUBSDIR . '/FollowUps.subs.php';
    // Let's see if we can create a stronger bridge between the two topics
    // @todo not sure what message from the oldest topic I should link to the new one, so I'll go with the first
    linkMessages($split1_first_msg, $split2_ID_TOPIC);
    // Copy log topic entries.
    // @todo This should really be chunked.
    $request = $db->query('', '
		SELECT id_member, id_msg, unwatched
		FROM {db_prefix}log_topics
		WHERE id_topic = {int:id_topic}', array('id_topic' => (int) $split1_ID_TOPIC));
    if ($db->num_rows($request) > 0) {
        $replaceEntries = array();
        while ($row = $db->fetch_assoc($request)) {
            $replaceEntries[] = array($row['id_member'], $split2_ID_TOPIC, $row['id_msg'], $row['unwatched']);
        }
        require_once SUBSDIR . '/Topic.subs.php';
        markTopicsRead($replaceEntries, false);
        unset($replaceEntries);
    }
    $db->free_result($request);
    // Housekeeping.
    updateTopicStats();
    updateLastMessages($id_board);
    logAction('split', array('topic' => $split1_ID_TOPIC, 'new_topic' => $split2_ID_TOPIC, 'board' => $id_board));
    // Notify people that this topic has been split?
    require_once SUBSDIR . '/Notification.subs.php';
    sendNotifications($split1_ID_TOPIC, 'split');
    // If there's a search index that needs updating, update it...
    require_once SUBSDIR . '/Search.subs.php';
    $searchAPI = findSearchAPI();
    if (is_callable(array($searchAPI, 'topicSplit'))) {
        $searchAPI->topicSplit($split2_ID_TOPIC, $splitMessages);
    }
    // Return the ID of the newly created topic.
    return $split2_ID_TOPIC;
}
Ejemplo n.º 5
0
/**
 * Dumps the database.
 *
 * What it does:
 * - It writes all of the database to standard output.
 * - It uses gzip compression if compress is set in the URL/post data.
 * - It may possibly time out, and mess up badly if you were relying on it. :P
 * - The data dumped depends on whether "struct" and "data" are passed.
 * - It is called from ManageMaintenance.controller.php.
 */
function DumpDatabase2()
{
    global $db_name, $scripturl, $modSettings, $db_prefix, $db_show_debug;
    // We'll need a db to dump :P
    $database = database();
    // We don't need debug when dumping the database
    $modSettings['disableQueryCheck'] = true;
    $db_show_debug = false;
    // You can't dump nothing!
    if (!isset($_REQUEST['struct']) && !isset($_REQUEST['data'])) {
        $_REQUEST['data'] = true;
    }
    // Attempt to stop from dying...
    @set_time_limit(600);
    $time_limit = ini_get('max_execution_time');
    $start_time = time();
    // @todo ... fail on not getting the requested memory?
    setMemoryLimit('256M');
    $memory_limit = memoryReturnBytes(ini_get('memory_limit')) / 4;
    $current_used_memory = 0;
    $db_backup = '';
    $output_function = 'un_compressed';
    @ob_end_clean();
    // Start saving the output... (don't do it otherwise for memory reasons.)
    if (isset($_REQUEST['compress']) && function_exists('gzencode')) {
        $output_function = 'gzencode';
        // Send faked headers so it will just save the compressed output as a gzip.
        header('Content-Type: application/x-gzip');
        header('Accept-Ranges: bytes');
        header('Content-Encoding: none');
        // Gecko browsers... don't like this. (Mozilla, Firefox, etc.)
        if (!isBrowser('gecko')) {
            header('Content-Transfer-Encoding: binary');
        }
        // The file extension will include .gz...
        $extension = '.sql.gz';
    } else {
        // Get rid of the gzipping alreading being done.
        if (!empty($modSettings['enableCompressedOutput'])) {
            @ob_end_clean();
        } elseif (ob_get_length() != 0) {
            ob_clean();
        }
        // Tell the client to save this file, even though it's text.
        header('Content-Type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream'));
        header('Content-Encoding: none');
        // This time the extension should just be .sql.
        $extension = '.sql';
    }
    // This should turn off the session URL parser.
    $scripturl = '';
    // Send the proper headers to let them download this file.
    header('Content-Disposition: attachment; filename="' . $db_name . '-' . (empty($_REQUEST['struct']) ? 'data' : (empty($_REQUEST['data']) ? 'structure' : 'complete')) . '_' . strftime('%Y-%m-%d') . $extension . '"');
    header('Cache-Control: private');
    header('Connection: close');
    // This makes things simpler when using it so very very often.
    $crlf = "\r\n";
    // SQL Dump Header.
    $db_chunks = '-- ==========================================================' . $crlf . '--' . $crlf . '-- Database dump of tables in `' . $db_name . '`' . $crlf . '-- ' . standardTime(time(), false) . $crlf . '--' . $crlf . '-- ==========================================================' . $crlf . $crlf;
    // Get all tables in the database....for our installation
    $real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
    $tables = $database->db_list_tables(false, $real_prefix . '%');
    // Dump each table.
    foreach ($tables as $tableName) {
        // Are we dumping the structures?
        if (isset($_REQUEST['struct'])) {
            $db_chunks .= $crlf . '--' . $crlf . '-- Table structure for table `' . $tableName . '`' . $crlf . '--' . $crlf . $crlf . $database->db_table_sql($tableName) . ';' . $crlf;
        } else {
            // This is needed to speedup things later
            $database->db_table_sql($tableName);
        }
        // How about the data?
        if (!isset($_REQUEST['data']) || substr($tableName, -10) == 'log_errors') {
            continue;
        }
        $first_round = true;
        $close_table = false;
        // Are there any rows in this table?
        while ($get_rows = $database->insert_sql($tableName, $first_round)) {
            if (empty($get_rows)) {
                break;
            }
            // Time is what we need here!
            if (function_exists('apache_reset_timeout')) {
                @apache_reset_timeout();
            } elseif (!empty($time_limit) && $start_time + $time_limit - 20 > time()) {
                $start_time = time();
                @set_time_limit(150);
            }
            // for the first pass, start the output with a custom line...
            if ($first_round) {
                $db_chunks .= $crlf . '--' . $crlf . '-- Dumping data in `' . $tableName . '`' . $crlf . '--' . $crlf . $crlf;
                $first_round = false;
            }
            $db_chunks .= $get_rows;
            $current_used_memory += Util::strlen($db_chunks);
            $db_backup .= $db_chunks;
            unset($db_chunks);
            $db_chunks = '';
            if ($current_used_memory > $memory_limit) {
                echo $output_function($db_backup);
                $current_used_memory = 0;
                // This is probably redundant
                unset($db_backup);
                $db_backup = '';
            }
            $close_table = true;
        }
        // No rows to get - skip it.
        if ($close_table) {
            $db_backup .= '-- --------------------------------------------------------' . $crlf;
        }
    }
    // write the last line
    $db_backup .= $crlf . '-- Done' . $crlf;
    echo $output_function($db_backup);
    exit;
}
Ejemplo n.º 6
0
 /**
  * Fulltext_Search::prepareIndexes()
  *
  * Do we have to do some work with the words we are searching for to prepare them?
  *
  * @param string $word
  * @param mixed[] $wordsSearch
  * @param string[] $wordsExclude
  * @param boolean $isExcluded
  */
 public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
 {
     global $modSettings;
     $subwords = text2words($word, null, false);
     if (empty($modSettings['search_force_index'])) {
         // A boolean capable search engine and not forced to only use an index, we may use a non indexed search
         // this is harder on the server so we are restrictive here
         if (count($subwords) > 1 && preg_match('~[.:@$]~', $word)) {
             // Using special characters that a full index would ignore and the remaining words are
             // short which would also be ignored
             if (Util::strlen(current($subwords)) < $this->min_word_length && Util::strlen(next($subwords)) < $this->min_word_length) {
                 $wordsSearch['words'][] = trim($word, '/*- ');
                 $wordsSearch['complex_words'][] = count($subwords) === 1 ? $word : '"' . $word . '"';
             }
         } elseif (Util::strlen(trim($word, '/*- ')) < $this->min_word_length) {
             // Short words have feelings too
             $wordsSearch['words'][] = trim($word, '/*- ');
             $wordsSearch['complex_words'][] = count($subwords) === 1 ? $word : '"' . $word . '"';
         }
     }
     $fulltextWord = count($subwords) === 1 ? $word : '"' . $word . '"';
     $wordsSearch['indexed_words'][] = $fulltextWord;
     if ($isExcluded) {
         $wordsExclude[] = $fulltextWord;
     }
 }
Ejemplo n.º 7
0
/**
 * Validate the signature
 *
 * @param string $value
 */
function profileValidateSignature(&$value)
{
    global $modSettings, $txt;
    require_once SUBSDIR . '/Post.subs.php';
    // Admins can do whatever they hell they want!
    if (!allowedTo('admin_forum')) {
        // Load all the signature limits.
        list($sig_limits, $sig_bbc) = explode(':', $modSettings['signature_settings']);
        $sig_limits = explode(',', $sig_limits);
        $disabledTags = !empty($sig_bbc) ? explode(',', $sig_bbc) : array();
        $unparsed_signature = strtr(un_htmlspecialchars($value), array("\r" => '', '&#039' => '\''));
        // Too many lines?
        if (!empty($sig_limits[2]) && substr_count($unparsed_signature, "\n") >= $sig_limits[2]) {
            $txt['profile_error_signature_max_lines'] = sprintf($txt['profile_error_signature_max_lines'], $sig_limits[2]);
            return 'signature_max_lines';
        }
        // Too many images?!
        if (!empty($sig_limits[3]) && substr_count(strtolower($unparsed_signature), '[img') + substr_count(strtolower($unparsed_signature), '<img') > $sig_limits[3]) {
            $txt['profile_error_signature_max_image_count'] = sprintf($txt['profile_error_signature_max_image_count'], $sig_limits[3]);
            return 'signature_max_image_count';
        }
        // What about too many smileys!
        $smiley_parsed = $unparsed_signature;
        parsesmileys($smiley_parsed);
        $smiley_count = substr_count(strtolower($smiley_parsed), '<img') - substr_count(strtolower($unparsed_signature), '<img');
        if (!empty($sig_limits[4]) && $sig_limits[4] == -1 && $smiley_count > 0) {
            return 'signature_allow_smileys';
        } elseif (!empty($sig_limits[4]) && $sig_limits[4] > 0 && $smiley_count > $sig_limits[4]) {
            $txt['profile_error_signature_max_smileys'] = sprintf($txt['profile_error_signature_max_smileys'], $sig_limits[4]);
            return 'signature_max_smileys';
        }
        // Maybe we are abusing font sizes?
        if (!empty($sig_limits[7]) && preg_match_all('~\\[size=([\\d\\.]+)?(px|pt|em|x-large|larger)~i', $unparsed_signature, $matches) !== false && isset($matches[2])) {
            foreach ($matches[1] as $ind => $size) {
                $limit_broke = 0;
                // Attempt to allow all sizes of abuse, so to speak.
                if ($matches[2][$ind] == 'px' && $size > $sig_limits[7]) {
                    $limit_broke = $sig_limits[7] . 'px';
                } elseif ($matches[2][$ind] == 'pt' && $size > $sig_limits[7] * 0.75) {
                    $limit_broke = (int) $sig_limits[7] * 0.75 . 'pt';
                } elseif ($matches[2][$ind] == 'em' && $size > (double) $sig_limits[7] / 16) {
                    $limit_broke = (double) $sig_limits[7] / 16 . 'em';
                } elseif ($matches[2][$ind] != 'px' && $matches[2][$ind] != 'pt' && $matches[2][$ind] != 'em' && $sig_limits[7] < 18) {
                    $limit_broke = 'large';
                }
                if ($limit_broke) {
                    $txt['profile_error_signature_max_font_size'] = sprintf($txt['profile_error_signature_max_font_size'], $limit_broke);
                    return 'signature_max_font_size';
                }
            }
        }
        // The difficult one - image sizes! Don't error on this - just fix it.
        if (!empty($sig_limits[5]) || !empty($sig_limits[6])) {
            // Get all BBC tags...
            preg_match_all('~\\[img(\\s+width=([\\d]+))?(\\s+height=([\\d]+))?(\\s+width=([\\d]+))?\\s*\\](?:<br />)*([^<">]+?)(?:<br />)*\\[/img\\]~i', $unparsed_signature, $matches);
            // ... and all HTML ones.
            preg_match_all('~<img\\s+src=(?:")?((?:http://|ftp://|https://|ftps://).+?)(?:")?(?:\\s+alt=(?:")?(.*?)(?:")?)?(?:\\s?/)?>~i', $unparsed_signature, $matches2, PREG_PATTERN_ORDER);
            // And stick the HTML in the BBC.
            if (!empty($matches2)) {
                foreach ($matches2[0] as $ind => $dummy) {
                    $matches[0][] = $matches2[0][$ind];
                    $matches[1][] = '';
                    $matches[2][] = '';
                    $matches[3][] = '';
                    $matches[4][] = '';
                    $matches[5][] = '';
                    $matches[6][] = '';
                    $matches[7][] = $matches2[1][$ind];
                }
            }
            $replaces = array();
            // Try to find all the images!
            if (!empty($matches)) {
                foreach ($matches[0] as $key => $image) {
                    $width = -1;
                    $height = -1;
                    // Does it have predefined restraints? Width first.
                    if ($matches[6][$key]) {
                        $matches[2][$key] = $matches[6][$key];
                    }
                    if ($matches[2][$key] && $sig_limits[5] && $matches[2][$key] > $sig_limits[5]) {
                        $width = $sig_limits[5];
                        $matches[4][$key] = $matches[4][$key] * ($width / $matches[2][$key]);
                    } elseif ($matches[2][$key]) {
                        $width = $matches[2][$key];
                    }
                    // ... and height.
                    if ($matches[4][$key] && $sig_limits[6] && $matches[4][$key] > $sig_limits[6]) {
                        $height = $sig_limits[6];
                        if ($width != -1) {
                            $width = $width * ($height / $matches[4][$key]);
                        }
                    } elseif ($matches[4][$key]) {
                        $height = $matches[4][$key];
                    }
                    // If the dimensions are still not fixed - we need to check the actual image.
                    if ($width == -1 && $sig_limits[5] || $height == -1 && $sig_limits[6]) {
                        require_once SUBSDIR . '/Attachments.subs.php';
                        $sizes = url_image_size($matches[7][$key]);
                        if (is_array($sizes)) {
                            // Too wide?
                            if ($sizes[0] > $sig_limits[5] && $sig_limits[5]) {
                                $width = $sig_limits[5];
                                $sizes[1] = $sizes[1] * ($width / $sizes[0]);
                            }
                            // Too high?
                            if ($sizes[1] > $sig_limits[6] && $sig_limits[6]) {
                                $height = $sig_limits[6];
                                if ($width == -1) {
                                    $width = $sizes[0];
                                }
                                $width = $width * ($height / $sizes[1]);
                            } elseif ($width != -1) {
                                $height = $sizes[1];
                            }
                        }
                    }
                    // Did we come up with some changes? If so remake the string.
                    if ($width != -1 || $height != -1) {
                        $replaces[$image] = '[img' . ($width != -1 ? ' width=' . round($width) : '') . ($height != -1 ? ' height=' . round($height) : '') . ']' . $matches[7][$key] . '[/img]';
                    }
                }
                if (!empty($replaces)) {
                    $value = str_replace(array_keys($replaces), array_values($replaces), $value);
                }
            }
        }
        // Any disabled BBC?
        $disabledSigBBC = implode('|', $disabledTags);
        if (!empty($disabledSigBBC)) {
            if (preg_match('~\\[(' . $disabledSigBBC . '[ =\\]/])~i', $unparsed_signature, $matches) !== false && isset($matches[1])) {
                $disabledTags = array_unique($disabledTags);
                $txt['profile_error_signature_disabled_bbc'] = sprintf($txt['profile_error_signature_disabled_bbc'], implode(', ', $disabledTags));
                return 'signature_disabled_bbc';
            }
        }
    }
    preparsecode($value);
    // Too long?
    if (!allowedTo('admin_forum') && !empty($sig_limits[1]) && Util::strlen(str_replace('<br />', "\n", $value)) > $sig_limits[1]) {
        $_POST['signature'] = trim(htmlspecialchars(str_replace('<br />', "\n", $value), ENT_QUOTES, 'UTF-8'));
        $txt['profile_error_signature_max_length'] = sprintf($txt['profile_error_signature_max_length'], $sig_limits[1]);
        return 'signature_max_length';
    }
    return true;
}
Ejemplo n.º 8
0
    /**
     * Used to edit the body or subject of a message inline
     * called from action=jsmodify from script and topic js
     */
    public function action_jsmodify()
    {
        global $modSettings, $board, $topic;
        global $user_info, $context;
        $db = database();
        // We have to have a topic!
        if (empty($topic)) {
            obExit(false);
        }
        checkSession('get');
        require_once SUBSDIR . '/Post.subs.php';
        // Assume the first message if no message ID was given.
        $request = $db->query('', '
			SELECT
				t.locked, t.num_replies, t.id_member_started, t.id_first_msg,
				m.id_msg, m.id_member, m.poster_time, m.subject, m.smileys_enabled, m.body, m.icon,
				m.modified_time, m.modified_name, m.approved
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
			WHERE m.id_msg = {raw:id_msg}
				AND m.id_topic = {int:current_topic}' . (allowedTo('modify_any') || allowedTo('approve_posts') ? '' : (!$modSettings['postmod_active'] ? '
				AND (m.id_member != {int:guest_id} AND m.id_member = {int:current_member})' : '
				AND (m.approved = {int:is_approved} OR (m.id_member != {int:guest_id} AND m.id_member = {int:current_member}))')), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'id_msg' => empty($_REQUEST['msg']) ? 't.id_first_msg' : (int) $_REQUEST['msg'], 'is_approved' => 1, 'guest_id' => 0));
        if ($db->num_rows($request) == 0) {
            fatal_lang_error('no_board', false);
        }
        $row = $db->fetch_assoc($request);
        $db->free_result($request);
        // Change either body or subject requires permissions to modify messages.
        if (isset($_POST['message']) || isset($_POST['subject']) || isset($_REQUEST['icon'])) {
            if (!empty($row['locked'])) {
                isAllowedTo('moderate_board');
            }
            if ($row['id_member'] == $user_info['id'] && !allowedTo('modify_any')) {
                if ((!$modSettings['postmod_active'] || $row['approved']) && !empty($modSettings['edit_disable_time']) && $row['poster_time'] + ($modSettings['edit_disable_time'] + 5) * 60 < time()) {
                    fatal_lang_error('modify_post_time_passed', false);
                } elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_own')) {
                    isAllowedTo('modify_replies');
                } else {
                    isAllowedTo('modify_own');
                }
            } elseif ($row['id_member_started'] == $user_info['id'] && !allowedTo('modify_any')) {
                isAllowedTo('modify_replies');
            } else {
                isAllowedTo('modify_any');
            }
            // Only log this action if it wasn't your message.
            $moderationAction = $row['id_member'] != $user_info['id'];
        }
        $post_errors = Error_Context::context('post', 1);
        if (isset($_POST['subject']) && Util::htmltrim(Util::htmlspecialchars($_POST['subject'])) !== '') {
            $_POST['subject'] = strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
            // Maximum number of characters.
            if (Util::strlen($_POST['subject']) > 100) {
                $_POST['subject'] = Util::substr($_POST['subject'], 0, 100);
            }
        } elseif (isset($_POST['subject'])) {
            $post_errors->addError('no_subject');
            unset($_POST['subject']);
        }
        if (isset($_POST['message'])) {
            if (Util::htmltrim(Util::htmlspecialchars($_POST['message'])) === '') {
                $post_errors->addError('no_message');
                unset($_POST['message']);
            } elseif (!empty($modSettings['max_messageLength']) && Util::strlen($_POST['message']) > $modSettings['max_messageLength']) {
                $post_errors->addError(array('long_message', array($modSettings['max_messageLength'])));
                unset($_POST['message']);
            } else {
                $_POST['message'] = Util::htmlspecialchars($_POST['message'], ENT_QUOTES);
                preparsecode($_POST['message']);
                if (Util::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '') {
                    $post_errors->addError('no_message');
                    unset($_POST['message']);
                }
            }
        }
        if (isset($_POST['lock'])) {
            if (!allowedTo(array('lock_any', 'lock_own')) || !allowedTo('lock_any') && $user_info['id'] != $row['id_member']) {
                unset($_POST['lock']);
            } elseif (!allowedTo('lock_any')) {
                if ($row['locked'] == 1) {
                    unset($_POST['lock']);
                } else {
                    $_POST['lock'] = empty($_POST['lock']) ? 0 : 2;
                }
            } elseif (!empty($row['locked']) && !empty($_POST['lock']) || $_POST['lock'] == $row['locked']) {
                unset($_POST['lock']);
            } else {
                $_POST['lock'] = empty($_POST['lock']) ? 0 : 1;
            }
        }
        if (isset($_POST['sticky']) && !allowedTo('make_sticky')) {
            unset($_POST['sticky']);
        }
        if (!$post_errors->hasErrors()) {
            $msgOptions = array('id' => $row['id_msg'], 'subject' => isset($_POST['subject']) ? $_POST['subject'] : null, 'body' => isset($_POST['message']) ? $_POST['message'] : null, 'icon' => isset($_REQUEST['icon']) ? preg_replace('~[\\./\\\\*\':"<>]~', '', $_REQUEST['icon']) : null);
            $topicOptions = array('id' => $topic, 'board' => $board, 'lock_mode' => isset($_POST['lock']) ? (int) $_POST['lock'] : null, 'sticky_mode' => isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : null, 'mark_as_read' => false);
            $posterOptions = array();
            // Only consider marking as editing if they have edited the subject, message or icon.
            if (isset($_POST['subject']) && $_POST['subject'] != $row['subject'] || isset($_POST['message']) && $_POST['message'] != $row['body'] || isset($_REQUEST['icon']) && $_REQUEST['icon'] != $row['icon']) {
                // And even then only if the time has passed...
                if (time() - $row['poster_time'] > $modSettings['edit_wait_time'] || $user_info['id'] != $row['id_member']) {
                    $msgOptions['modify_time'] = time();
                    $msgOptions['modify_name'] = $user_info['name'];
                }
            } else {
                $moderationAction = false;
            }
            modifyPost($msgOptions, $topicOptions, $posterOptions);
            // If we didn't change anything this time but had before put back the old info.
            if (!isset($msgOptions['modify_time']) && !empty($row['modified_time'])) {
                $msgOptions['modify_time'] = $row['modified_time'];
                $msgOptions['modify_name'] = $row['modified_name'];
            }
            // Changing the first subject updates other subjects to 'Re: new_subject'.
            if (isset($_POST['subject']) && isset($_REQUEST['change_all_subjects']) && $row['id_first_msg'] == $row['id_msg'] && !empty($row['num_replies']) && (allowedTo('modify_any') || $row['id_member_started'] == $user_info['id'] && allowedTo('modify_replies'))) {
                // Get the proper (default language) response prefix first.
                $context['response_prefix'] = response_prefix();
                $db->query('', '
					UPDATE {db_prefix}messages
					SET subject = {string:subject}
					WHERE id_topic = {int:current_topic}
						AND id_msg != {int:id_first_msg}', array('current_topic' => $topic, 'id_first_msg' => $row['id_first_msg'], 'subject' => $context['response_prefix'] . $_POST['subject']));
            }
            if (!empty($moderationAction)) {
                logAction('modify', array('topic' => $topic, 'message' => $row['id_msg'], 'member' => $row['id_member'], 'board' => $board));
            }
        }
        if (isset($_REQUEST['xml'])) {
            $context['sub_template'] = 'modifydone';
            if (!$post_errors->hasErrors() && isset($msgOptions['subject']) && isset($msgOptions['body'])) {
                $context['message'] = array('id' => $row['id_msg'], 'modified' => array('time' => isset($msgOptions['modify_time']) ? standardTime($msgOptions['modify_time']) : '', 'html_time' => isset($msgOptions['modify_time']) ? htmlTime($msgOptions['modify_time']) : '', 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0, 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : ''), 'subject' => $msgOptions['subject'], 'first_in_topic' => $row['id_msg'] == $row['id_first_msg'], 'body' => strtr($msgOptions['body'], array(']]>' => ']]]]><![CDATA[>')));
                censorText($context['message']['subject']);
                censorText($context['message']['body']);
                $context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $row['id_msg']);
            } elseif (!$post_errors->hasErrors()) {
                $context['sub_template'] = 'modifytopicdone';
                $context['message'] = array('id' => $row['id_msg'], 'modified' => array('time' => isset($msgOptions['modify_time']) ? standardTime($msgOptions['modify_time']) : '', 'html_time' => isset($msgOptions['modify_time']) ? htmlTime($msgOptions['modify_time']) : '', 'timestamp' => isset($msgOptions['modify_time']) ? forum_time(true, $msgOptions['modify_time']) : 0, 'name' => isset($msgOptions['modify_time']) ? $msgOptions['modify_name'] : ''), 'subject' => isset($msgOptions['subject']) ? $msgOptions['subject'] : '');
                censorText($context['message']['subject']);
            } else {
                $context['message'] = array('id' => $row['id_msg'], 'errors' => array(), 'error_in_subject' => $post_errors->hasError('no_subject'), 'error_in_body' => $post_errors->hasError('no_message') || $post_errors->hasError('long_message'));
                $context['message']['errors'] = $post_errors->prepareErrors();
            }
        } else {
            obExit(false);
        }
    }
Ejemplo n.º 9
0
 /**
  * This function offers up a download of an event in iCal 2.0 format.
  *
  * follows the conventions in RFC5546 http://tools.ietf.org/html/rfc5546
  * sets events as all day events since we don't have hourly events
  * will honor and set multi day events
  * sets a sequence number if the event has been modified.
  * Accessed by action=calendar;sa=ical
  *
  * @todo .... allow for week or month export files as well?
  */
 public function action_ical()
 {
     global $forum_version, $modSettings, $webmaster_email, $mbname;
     // What do you think you export?
     isAllowedTo('calendar_view');
     // You can't export if the calendar export feature is off.
     if (empty($modSettings['cal_export'])) {
         fatal_lang_error('calendar_export_off', false);
     }
     // Goes without saying that this is required.
     if (!isset($_REQUEST['eventid'])) {
         fatal_lang_error('no_access', false);
     }
     // This is kinda wanted.
     require_once SUBSDIR . '/Calendar.subs.php';
     // Load up the event in question and check it exists.
     $event = getEventProperties($_REQUEST['eventid']);
     if ($event === false) {
         fatal_lang_error('no_access', false);
     }
     // Check the title isn't too long - iCal requires some formatting if so.
     $title = str_split($event['title'], 30);
     foreach ($title as $id => $line) {
         if ($id != 0) {
             $title[$id] = ' ' . $title[$id];
         }
         $title[$id] .= "\n";
     }
     // Format the dates.
     $datestamp = date('Ymd\\THis\\Z', time());
     $datestart = $event['year'] . ($event['month'] < 10 ? '0' . $event['month'] : $event['month']) . ($event['day'] < 10 ? '0' . $event['day'] : $event['day']);
     // Do we have a event that spans several days?
     if ($event['span'] > 1) {
         $dateend = strtotime($event['year'] . '-' . ($event['month'] < 10 ? '0' . $event['month'] : $event['month']) . '-' . ($event['day'] < 10 ? '0' . $event['day'] : $event['day']));
         $dateend += ($event['span'] - 1) * 86400;
         $dateend = date('Ymd', $dateend);
     }
     // This is what we will be sending later
     $filecontents = '';
     $filecontents .= 'BEGIN:VCALENDAR' . "\n";
     $filecontents .= 'METHOD:PUBLISH' . "\n";
     $filecontents .= 'PRODID:-//ElkArteCommunity//ElkArte ' . (empty($forum_version) ? 2.0 : strtr($forum_version, array('ElkArte ' => ''))) . '//EN' . "\n";
     $filecontents .= 'VERSION:2.0' . "\n";
     $filecontents .= 'BEGIN:VEVENT' . "\n";
     $filecontents .= 'ORGANIZER;CN="' . $event['realname'] . '":MAILTO:' . $webmaster_email . "\n";
     $filecontents .= 'DTSTAMP:' . $datestamp . "\n";
     $filecontents .= 'DTSTART;VALUE=DATE:' . $datestart . "\n";
     // more than one day
     if ($event['span'] > 1) {
         $filecontents .= 'DTEND;VALUE=DATE:' . $dateend . "\n";
     }
     // event has changed? advance the sequence for this UID
     if ($event['sequence'] > 0) {
         $filecontents .= 'SEQUENCE:' . $event['sequence'] . "\n";
     }
     $filecontents .= 'SUMMARY:' . implode('', $title);
     $filecontents .= 'UID:' . $event['eventid'] . '@' . str_replace(' ', '-', $mbname) . "\n";
     $filecontents .= 'END:VEVENT' . "\n";
     $filecontents .= 'END:VCALENDAR';
     // Send some standard headers.
     @ob_end_clean();
     if (!empty($modSettings['enableCompressedOutput'])) {
         ob_start('ob_gzhandler');
     } else {
         ob_start();
     }
     // Send the file headers
     header('Pragma: ');
     header('Cache-Control: no-cache');
     if (!isBrowser('gecko')) {
         header('Content-Transfer-Encoding: binary');
     }
     header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
     header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT');
     header('Accept-Ranges: bytes');
     header('Connection: close');
     header('Content-Disposition: attachment; filename="' . $event['title'] . '.ics"');
     if (empty($modSettings['enableCompressedOutput'])) {
         header('Content-Length: ' . Util::strlen($filecontents));
     }
     // This is a calendar item!
     header('Content-Type: text/calendar');
     // Chuck out the card.
     echo $filecontents;
     // Off we pop - lovely!
     obExit(false);
 }
Ejemplo n.º 10
0
/**
 * Saves a PM draft in the user_drafts table
 *
 * - The core draft feature must be enabled, as well as the pm draft option
 * - Determines if this is a new or and update to an existing pm draft
 *
 * @package Drafts
 * @param mixed[] $recipientList
 */
function savePMDraft($recipientList)
{
    global $context, $user_info, $modSettings;
    // Ajax calling
    if (!isset($context['drafts_pm_save'])) {
        $context['drafts_pm_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_pm_enabled']) && allowedTo('pm_draft');
    }
    // PM survey says ... can you stay or must you go
    if (empty($context['drafts_pm_save']) || !isset($_POST['save_draft']) || !isset($_POST['id_pm_draft'])) {
        return false;
    }
    // Read in what was sent
    $id_pm_draft = empty($_POST['id_pm_draft']) ? 0 : (int) $_POST['id_pm_draft'];
    $draft_info = loadDraft($id_pm_draft, 1);
    $post_errors = Error_Context::context('pm', 1);
    // 5 seconds is the same limit we have for posting
    if (isset($_REQUEST['xml']) && !empty($draft_info['poster_time']) && time() < $draft_info['poster_time'] + 5) {
        // Send something back to the javascript caller
        if (!empty($id_pm_draft)) {
            loadTemplate('Xml');
            $context['sub_template'] = 'xml_draft';
            $context['id_draft'] = $id_pm_draft;
            $context['draft_saved_on'] = $draft_info['poster_time'];
            obExit();
        }
        return true;
    }
    // Determine who this is being sent to
    if (isset($_REQUEST['xml'])) {
        $recipientList['to'] = isset($_POST['recipient_to']) ? explode(',', $_POST['recipient_to']) : array();
        $recipientList['bcc'] = isset($_POST['recipient_bcc']) ? explode(',', $_POST['recipient_bcc']) : array();
    } elseif (!empty($draft_info['to_list']) && empty($recipientList)) {
        $recipientList = unserialize($draft_info['to_list']);
    }
    // Prepare the data
    $draft = array('id_pm_draft' => $id_pm_draft, 'reply_id' => empty($_POST['replied_to']) ? 0 : (int) $_POST['replied_to'], 'body' => Util::htmlspecialchars($_POST['message'], ENT_QUOTES), 'subject' => strtr(Util::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => '')), 'id_member' => $user_info['id']);
    // message and subject always need a bit more work
    preparsecode($draft['body']);
    if (Util::strlen($draft['subject']) > 100) {
        $draft['subject'] = Util::substr($draft['subject'], 0, 100);
    }
    // Modifying an existing PM draft?
    if (!empty($id_pm_draft) && !empty($draft_info)) {
        modify_pm_draft($draft, $recipientList);
        // some items to return to the form
        $context['draft_saved'] = true;
        $context['id_pm_draft'] = $id_pm_draft;
    } else {
        $id_pm_draft = create_pm_draft($draft, $recipientList);
        // Everything go as expected, if not toss back an error
        if (!empty($id_pm_draft)) {
            $context['draft_saved'] = true;
            $context['id_pm_draft'] = $id_pm_draft;
        } else {
            $post_errors->addError('draft_not_saved');
        }
    }
    // if we were called from the autosave function, send something back
    if (!empty($id_pm_draft) && isset($_REQUEST['xml']) && !$post_errors->hasError('session_timeout')) {
        loadTemplate('Xml');
        $context['sub_template'] = 'xml_draft';
        $context['id_draft'] = $id_pm_draft;
        $context['draft_saved_on'] = time();
        obExit();
    }
    return;
}
Ejemplo n.º 11
0
 /**
  * This function handles adding, deleting and editing labels on messages.
  */
 public function action_manlabels()
 {
     global $txt, $context, $user_info, $scripturl;
     require_once SUBSDIR . '/PersonalMessage.subs.php';
     // Build the link tree elements...
     $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manlabels', 'name' => $txt['pm_manage_labels']);
     // Some things for the template
     $context['page_title'] = $txt['pm_manage_labels'];
     $context['sub_template'] = 'labels';
     // Add all existing labels to the array to save, slashing them as necessary...
     $the_labels = array();
     foreach ($context['labels'] as $label) {
         if ($label['id'] != -1) {
             $the_labels[$label['id']] = $label['name'];
         }
     }
     // Submitting changes?
     if (isset($_POST['add']) || isset($_POST['delete']) || isset($_POST['save'])) {
         checkSession('post');
         // This will be for updating messages.
         $message_changes = array();
         $new_labels = array();
         $rule_changes = array();
         // Will most likely need this.
         loadRules();
         // Adding a new label?
         if (isset($_POST['add'])) {
             $_POST['label'] = strtr(Util::htmlspecialchars(trim($_POST['label'])), array(',' => '&#044;'));
             if (Util::strlen($_POST['label']) > 30) {
                 $_POST['label'] = Util::substr($_POST['label'], 0, 30);
             }
             if ($_POST['label'] != '') {
                 $the_labels[] = $_POST['label'];
             }
         } elseif (isset($_POST['delete'], $_POST['delete_label'])) {
             $i = 0;
             foreach ($the_labels as $id => $name) {
                 if (isset($_POST['delete_label'][$id])) {
                     unset($the_labels[$id]);
                     $message_changes[$id] = true;
                 } else {
                     $new_labels[$id] = $i++;
                 }
             }
         } elseif (isset($_POST['save']) && !empty($_POST['label_name'])) {
             $i = 0;
             foreach ($the_labels as $id => $name) {
                 if ($id == -1) {
                     continue;
                 } elseif (isset($_POST['label_name'][$id])) {
                     // Prepare the label name
                     $_POST['label_name'][$id] = trim(strtr(Util::htmlspecialchars($_POST['label_name'][$id]), array(',' => '&#044;')));
                     // Has to fit in the database as well
                     if (Util::strlen($_POST['label_name'][$id]) > 30) {
                         $_POST['label_name'][$id] = Util::substr($_POST['label_name'][$id], 0, 30);
                     }
                     if ($_POST['label_name'][$id] != '') {
                         $the_labels[(int) $id] = $_POST['label_name'][$id];
                         $new_labels[$id] = $i++;
                     } else {
                         unset($the_labels[(int) $id]);
                         $message_changes[(int) $id] = true;
                     }
                 } else {
                     $new_labels[$id] = $i++;
                 }
             }
         }
         // Save the label status.
         updateMemberData($user_info['id'], array('message_labels' => implode(',', $the_labels)));
         // Update all the messages currently with any label changes in them!
         if (!empty($message_changes)) {
             $searchArray = array_keys($message_changes);
             if (!empty($new_labels)) {
                 for ($i = max($searchArray) + 1, $n = max(array_keys($new_labels)); $i <= $n; $i++) {
                     $searchArray[] = $i;
                 }
             }
             updateLabelsToPM($searchArray, $new_labels, $user_info['id']);
             // Now do the same the rules - check through each rule.
             foreach ($context['rules'] as $k => $rule) {
                 // Each action...
                 foreach ($rule['actions'] as $k2 => $action) {
                     if ($action['t'] != 'lab' || !in_array($action['v'], $searchArray)) {
                         continue;
                     }
                     $rule_changes[] = $rule['id'];
                     // If we're here we have a label which is either changed or gone...
                     if (isset($new_labels[$action['v']])) {
                         $context['rules'][$k]['actions'][$k2]['v'] = $new_labels[$action['v']];
                     } else {
                         unset($context['rules'][$k]['actions'][$k2]);
                     }
                 }
             }
         }
         // If we have rules to change do so now.
         if (!empty($rule_changes)) {
             $rule_changes = array_unique($rule_changes);
             // Update/delete as appropriate.
             foreach ($rule_changes as $k => $id) {
                 if (!empty($context['rules'][$id]['actions'])) {
                     updatePMRuleAction($id, $user_info['id'], $context['rules'][$id]['actions']);
                     unset($rule_changes[$k]);
                 }
             }
             // Anything left here means it's lost all actions...
             if (!empty($rule_changes)) {
                 deletePMRules($user_info['id'], $rule_changes);
             }
         }
         // Make sure we're not caching this!
         cache_put_data('labelCounts:' . $user_info['id'], null, 720);
         // To make the changes appear right away, redirect.
         redirectexit('action=pm;sa=manlabels');
     }
 }
Ejemplo n.º 12
0
 /**
  * Breaks a string up so its no more than width characters long
  *
  * - Will break at word boundaries
  * - If no natural space is found will break mid-word
  *
  * @param string $string
  * @param int $width
  * @param string $break
  */
 private function _utf8_wordwrap($string, $width = 75, $break = "\n")
 {
     $lines = array();
     while (!empty($string)) {
         // Get the next #width characters before a break (space, tab etc)
         if (preg_match('~^(.{1,' . $width . '})(?:\\s|$)~', $string, $matches)) {
             // Add the #width to the output and set up for the next pass
             $lines[] = $matches[1];
             $string = Util::substr($string, Util::strlen($matches[0]));
         } else {
             $lines[] = Util::substr($string, 0, $width);
             $string = Util::substr($string, $width);
         }
     }
     // Join it all the shortened sections up on our break characters
     return implode($break, $lines);
 }
Ejemplo n.º 13
0
 /**
  * Combine files in to <200k chunks and make closure compiler requests
  *
  * What it does:
  * - Loads as many files as it can in to a single post request while
  * keeping the post size within the limits accepted by the service
  * - Will do multiple requests until done, combining the results
  * - Returns the compressed string or the original if an error occurs
  */
 private function _closure_js_code_chunks()
 {
     $fetch_data = '';
     $combine_files = array_values($this->_combine_files);
     for ($i = 0, $filecount = count($combine_files); $i < $filecount; $i++) {
         // New post request, start off empty
         $post_len = 0;
         $post_data = '';
         $post_data_raw = '';
         // Combine data in to chunks of < 200k to minimize http posts
         while ($i < $filecount) {
             // Get the details for this file
             $file = $combine_files[$i];
             // Skip over minimized ones
             if ($file['minimized'] === true) {
                 $i++;
                 continue;
             }
             // Prepare the data for posting
             $data = urlencode($file['content']);
             $data_len = Util::strlen($data);
             // While we can add data to the post and not acceed the post size allowed by the service
             if ($data_len + $post_len < 200000) {
                 $post_data .= $data;
                 $post_data_raw .= $file['content'];
                 $post_len = $data_len + $post_len;
                 $i++;
             } else {
                 $i--;
                 break;
             }
         }
         // Send it off and get the results
         $post_data = '&js_code=' . $post_data;
         $data = fetch_web_data($this->_url, $this->_post_header . $post_data);
         // Use the results or the raw data if an error is detected
         $fetch_data .= $data === false || trim($data) == '' || preg_match('/^Error\\(\\d{1,2}\\):\\s/m', $data) ? $post_data_raw : $data;
     }
     return $fetch_data;
 }
Ejemplo n.º 14
0
    /**
     * Set merge options and do the actual merge of two or more topics.
     *
     * the merge options screen:
     * * shows topics to be merged and allows to set some merge options.
     * * is accessed by ?action=mergetopics;sa=options.and can also internally be called by action_quickmod().
     * * uses 'merge_extra_options' sub template of the MergeTopics template.
     *
     * the actual merge:
     * * is accessed with ?action=mergetopics;sa=execute.
     * * updates the statistics to reflect the merge.
     * * logs the action in the moderation log.
     * * sends a notification is sent to all users monitoring this topic.
     * * redirects to ?action=mergetopics;sa=done.
     *
     * @param int[] $topics = array() of topic ids
     */
    public function action_mergeExecute($topics = array())
    {
        global $user_info, $txt, $context, $scripturl, $modSettings;
        $db = database();
        // Check the session.
        checkSession('request');
        require_once SUBSDIR . '/Topic.subs.php';
        require_once SUBSDIR . '/Post.subs.php';
        // Handle URLs from action_mergeIndex.
        if (!empty($_GET['from']) && !empty($_GET['to'])) {
            $topics = array((int) $_GET['from'], (int) $_GET['to']);
        }
        // If we came from a form, the topic IDs came by post.
        if (!empty($_POST['topics']) && is_array($_POST['topics'])) {
            $topics = $_POST['topics'];
        }
        // There's nothing to merge with just one topic...
        if (empty($topics) || !is_array($topics) || count($topics) == 1) {
            fatal_lang_error('merge_need_more_topics');
        }
        // Make sure every topic is numeric, or some nasty things could be done with the DB.
        foreach ($topics as $id => $topic) {
            $topics[$id] = (int) $topic;
        }
        // Joy of all joys, make sure they're not pi**ing about with unapproved topics they can't see :P
        if ($modSettings['postmod_active']) {
            $can_approve_boards = !empty($user_info['mod_cache']['ap']) ? $user_info['mod_cache']['ap'] : boardsAllowedTo('approve_posts');
        }
        // Get info about the topics and polls that will be merged.
        $request = $db->query('', '
			SELECT
				t.id_topic, t.id_board, t.id_poll, t.num_views, t.is_sticky, t.approved, t.num_replies, t.unapproved_posts,
				m1.subject, m1.poster_time AS time_started, IFNULL(mem1.id_member, 0) AS id_member_started, IFNULL(mem1.real_name, m1.poster_name) AS name_started,
				m2.poster_time AS time_updated, IFNULL(mem2.id_member, 0) AS id_member_updated, IFNULL(mem2.real_name, m2.poster_name) AS name_updated
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}messages AS m1 ON (m1.id_msg = t.id_first_msg)
				INNER JOIN {db_prefix}messages AS m2 ON (m2.id_msg = t.id_last_msg)
				LEFT JOIN {db_prefix}members AS mem1 ON (mem1.id_member = m1.id_member)
				LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = m2.id_member)
			WHERE t.id_topic IN ({array_int:topic_list})
			ORDER BY t.id_first_msg
			LIMIT ' . count($topics), array('topic_list' => $topics));
        if ($db->num_rows($request) < 2) {
            fatal_lang_error('no_topic_id');
        }
        $num_views = 0;
        $is_sticky = 0;
        $boardTotals = array();
        $topic_data = array();
        $boards = array();
        $polls = array();
        $firstTopic = 0;
        while ($row = $db->fetch_assoc($request)) {
            // Make a note for the board counts...
            if (!isset($boardTotals[$row['id_board']])) {
                $boardTotals[$row['id_board']] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0);
            }
            // We can't see unapproved topics here?
            if ($modSettings['postmod_active'] && !$row['approved'] && $can_approve_boards != array(0) && in_array($row['id_board'], $can_approve_boards)) {
                continue;
            } elseif (!$row['approved']) {
                $boardTotals[$row['id_board']]['unapproved_topics']++;
            } else {
                $boardTotals[$row['id_board']]['num_topics']++;
            }
            $boardTotals[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts'];
            $boardTotals[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? 1 : 0);
            $topic_data[$row['id_topic']] = array('id' => $row['id_topic'], 'board' => $row['id_board'], 'poll' => $row['id_poll'], 'num_views' => $row['num_views'], 'subject' => $row['subject'], 'started' => array('time' => standardTime($row['time_started']), 'html_time' => htmlTime($row['time_started']), 'timestamp' => forum_time(true, $row['time_started']), 'href' => empty($row['id_member_started']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_started'], 'link' => empty($row['id_member_started']) ? $row['name_started'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_started'] . '">' . $row['name_started'] . '</a>'), 'updated' => array('time' => standardTime($row['time_updated']), 'html_time' => htmlTime($row['time_updated']), 'timestamp' => forum_time(true, $row['time_updated']), 'href' => empty($row['id_member_updated']) ? '' : $scripturl . '?action=profile;u=' . $row['id_member_updated'], 'link' => empty($row['id_member_updated']) ? $row['name_updated'] : '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member_updated'] . '">' . $row['name_updated'] . '</a>'));
            $num_views += $row['num_views'];
            $boards[] = $row['id_board'];
            // If there's no poll, id_poll == 0...
            if ($row['id_poll'] > 0) {
                $polls[] = $row['id_poll'];
            }
            // Store the id_topic with the lowest id_first_msg.
            if (empty($firstTopic)) {
                $firstTopic = $row['id_topic'];
            }
            $is_sticky = max($is_sticky, $row['is_sticky']);
        }
        $db->free_result($request);
        // If we didn't get any topics then they've been messing with unapproved stuff.
        if (empty($topic_data)) {
            fatal_lang_error('no_topic_id');
        }
        $boards = array_values(array_unique($boards));
        // The parameters of action_mergeExecute were set, so this must've been an internal call.
        if (!empty($topics)) {
            isAllowedTo('merge_any', $boards);
            loadTemplate('MergeTopics');
        }
        // Get the boards a user is allowed to merge in.
        $merge_boards = boardsAllowedTo('merge_any');
        if (empty($merge_boards)) {
            fatal_lang_error('cannot_merge_any', 'user');
        }
        require_once SUBSDIR . '/Boards.subs.php';
        // Make sure they can see all boards....
        $query_boards = array('boards' => $boards);
        if (!in_array(0, $merge_boards)) {
            $query_boards['boards'] = array_merge($query_boards['boards'], $merge_boards);
        }
        // Saved in a variable to (potentially) save a query later
        $boards_info = fetchBoardsInfo($query_boards);
        // This happens when a member is moderator of a board he cannot see
        foreach ($boards as $board) {
            if (!isset($boards_info[$board])) {
                fatal_lang_error('no_board');
            }
        }
        if (empty($_REQUEST['sa']) || $_REQUEST['sa'] == 'options') {
            if (count($polls) > 1) {
                $request = $db->query('', '
					SELECT t.id_topic, t.id_poll, m.subject, p.question
					FROM {db_prefix}polls AS p
						INNER JOIN {db_prefix}topics AS t ON (t.id_poll = p.id_poll)
						INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
					WHERE p.id_poll IN ({array_int:polls})
					LIMIT ' . count($polls), array('polls' => $polls));
                while ($row = $db->fetch_assoc($request)) {
                    $context['polls'][] = array('id' => $row['id_poll'], 'topic' => array('id' => $row['id_topic'], 'subject' => $row['subject']), 'question' => $row['question'], 'selected' => $row['id_topic'] == $firstTopic);
                }
                $db->free_result($request);
            }
            if (count($boards) > 1) {
                foreach ($boards_info as $row) {
                    $context['boards'][] = array('id' => $row['id_board'], 'name' => $row['name'], 'selected' => $row['id_board'] == $topic_data[$firstTopic]['board']);
                }
            }
            $context['topics'] = $topic_data;
            foreach ($topic_data as $id => $topic) {
                $context['topics'][$id]['selected'] = $topic['id'] == $firstTopic;
            }
            $context['page_title'] = $txt['merge'];
            $context['sub_template'] = 'merge_extra_options';
            return;
        }
        // Determine target board.
        $target_board = count($boards) > 1 ? (int) $_REQUEST['board'] : $boards[0];
        if (!in_array($target_board, $boards)) {
            fatal_lang_error('no_board');
        }
        // Determine which poll will survive and which polls won't.
        $target_poll = count($polls) > 1 ? (int) $_POST['poll'] : (count($polls) == 1 ? $polls[0] : 0);
        if ($target_poll > 0 && !in_array($target_poll, $polls)) {
            fatal_lang_error('no_access', false);
        }
        $deleted_polls = empty($target_poll) ? $polls : array_diff($polls, array($target_poll));
        // Determine the subject of the newly merged topic - was a custom subject specified?
        if (empty($_POST['subject']) && isset($_POST['custom_subject']) && $_POST['custom_subject'] != '') {
            $target_subject = strtr(Util::htmltrim(Util::htmlspecialchars($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => ''));
            // Keep checking the length.
            if (Util::strlen($target_subject) > 100) {
                $target_subject = Util::substr($target_subject, 0, 100);
            }
            // Nothing left - odd but pick the first topics subject.
            if ($target_subject == '') {
                $target_subject = $topic_data[$firstTopic]['subject'];
            }
        } elseif (!empty($topic_data[(int) $_POST['subject']]['subject'])) {
            $target_subject = $topic_data[(int) $_POST['subject']]['subject'];
        } else {
            $target_subject = $topic_data[$firstTopic]['subject'];
        }
        // Get the first and last message and the number of messages....
        $request = $db->query('', '
			SELECT approved, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg, COUNT(*) AS message_count
			FROM {db_prefix}messages
			WHERE id_topic IN ({array_int:topics})
			GROUP BY approved
			ORDER BY approved DESC', array('topics' => $topics));
        $topic_approved = 1;
        $first_msg = 0;
        while ($row = $db->fetch_assoc($request)) {
            // If this is approved, or is fully unapproved.
            if ($row['approved'] || !isset($first_msg)) {
                $first_msg = $row['first_msg'];
                $last_msg = $row['last_msg'];
                if ($row['approved']) {
                    $num_replies = $row['message_count'] - 1;
                    $num_unapproved = 0;
                } else {
                    $topic_approved = 0;
                    $num_replies = 0;
                    $num_unapproved = $row['message_count'];
                }
            } else {
                // If this has a lower first_msg then the first post is not approved and hence the number of replies was wrong!
                if ($first_msg > $row['first_msg']) {
                    $first_msg = $row['first_msg'];
                    $num_replies++;
                    $topic_approved = 0;
                }
                $num_unapproved = $row['message_count'];
            }
        }
        $db->free_result($request);
        // Ensure we have a board stat for the target board.
        if (!isset($boardTotals[$target_board])) {
            $boardTotals[$target_board] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0);
        }
        // Fix the topic count stuff depending on what the new one counts as.
        if ($topic_approved) {
            $boardTotals[$target_board]['num_topics']--;
        } else {
            $boardTotals[$target_board]['unapproved_topics']--;
        }
        $boardTotals[$target_board]['unapproved_posts'] -= $num_unapproved;
        $boardTotals[$target_board]['num_posts'] -= $topic_approved ? $num_replies + 1 : $num_replies;
        // Get the member ID of the first and last message.
        $request = $db->query('', '
			SELECT id_member
			FROM {db_prefix}messages
			WHERE id_msg IN ({int:first_msg}, {int:last_msg})
			ORDER BY id_msg
			LIMIT 2', array('first_msg' => $first_msg, 'last_msg' => $last_msg));
        list($member_started) = $db->fetch_row($request);
        list($member_updated) = $db->fetch_row($request);
        // First and last message are the same, so only row was returned.
        if ($member_updated === null) {
            $member_updated = $member_started;
        }
        $db->free_result($request);
        // Obtain all the message ids we are going to affect.
        $affected_msgs = messagesInTopics($topics);
        // Assign the first topic ID to be the merged topic.
        $id_topic = min($topics);
        // Grab the response prefix (like 'Re: ') in the default forum language.
        $context['response_prefix'] = response_prefix();
        $enforce_subject = isset($_POST['enforce_subject']) ? Util::htmlspecialchars(trim($_POST['enforce_subject'])) : '';
        // Merge topic notifications.
        $notifications = isset($_POST['notifications']) && is_array($_POST['notifications']) ? array_intersect($topics, $_POST['notifications']) : array();
        fixMergedTopics($first_msg, $topics, $id_topic, $target_board, $target_subject, $enforce_subject, $notifications);
        // Asssign the properties of the newly merged topic.
        $db->query('', '
			UPDATE {db_prefix}topics
			SET
				id_board = {int:id_board},
				id_member_started = {int:id_member_started},
				id_member_updated = {int:id_member_updated},
				id_first_msg = {int:id_first_msg},
				id_last_msg = {int:id_last_msg},
				id_poll = {int:id_poll},
				num_replies = {int:num_replies},
				unapproved_posts = {int:unapproved_posts},
				num_views = {int:num_views},
				is_sticky = {int:is_sticky},
				approved = {int:approved}
			WHERE id_topic = {int:id_topic}', array('id_board' => $target_board, 'is_sticky' => $is_sticky, 'approved' => $topic_approved, 'id_topic' => $id_topic, 'id_member_started' => $member_started, 'id_member_updated' => $member_updated, 'id_first_msg' => $first_msg, 'id_last_msg' => $last_msg, 'id_poll' => $target_poll, 'num_replies' => $num_replies, 'unapproved_posts' => $num_unapproved, 'num_views' => $num_views));
        // Get rid of the redundant polls.
        if (!empty($deleted_polls)) {
            require_once SUBSDIR . '/Poll.subs.php';
            removePoll($deleted_polls);
        }
        // Cycle through each board...
        foreach ($boardTotals as $id_board => $stats) {
            decrementBoard($id_board, $stats);
        }
        // Determine the board the final topic resides in
        $topic_info = getTopicInfo($id_topic);
        $id_board = $topic_info['id_board'];
        // Update all the statistics.
        updateStats('topic');
        updateStats('subject', $id_topic, $target_subject);
        updateLastMessages($boards);
        logAction('merge', array('topic' => $id_topic, 'board' => $id_board));
        // Notify people that these topics have been merged?
        require_once SUBSDIR . '/Notification.subs.php';
        sendNotifications($id_topic, 'merge');
        // If there's a search index that needs updating, update it...
        require_once SUBSDIR . '/Search.subs.php';
        $searchAPI = findSearchAPI();
        if (is_callable(array($searchAPI, 'topicMerge'))) {
            $searchAPI->topicMerge($id_topic, $topics, $affected_msgs, empty($enforce_subject) ? null : array($context['response_prefix'], $target_subject));
        }
        // Send them to the all done page.
        redirectexit('action=mergetopics;sa=done;to=' . $id_topic . ';targetboard=' . $target_board);
    }
Ejemplo n.º 15
0
 /**
  * Truncate a string up to a number of characters while preserving whole words and HTML tags
  *
  * This function is an adaption of the cake php function truncate in utility string.php (MIT)
  *
  * @param string $string text to truncate.
  * @param integer $length length of returned string
  * @param string $ellipsis characters to add at the end of cut string, like ...
  * @param boolean $exact If to account for the $ellipsis length in returned string length
  *
  * @return string Trimmed string.
  */
 public static function shorten_html($string, $length = 384, $ellipsis = '...', $exact = true)
 {
     // If its shorter than the maximum length, while accounting for html tags, simply return
     if (Util::strlen(preg_replace('~<.*?>~', '', $string)) <= $length) {
         return $string;
     }
     // Start off empty
     $total_length = $exact ? Util::strlen($ellipsis) : 0;
     $open_tags = array();
     $truncate = '';
     // Group all html open and closing tags, [1] full tag with <> [2] basic tag name [3] tag content
     preg_match_all('~(<\\/?([\\w+]+)[^>]*>)?([^<>]*)~', $string, $tags, PREG_SET_ORDER);
     // Walk down the stack of tags
     foreach ($tags as $tag) {
         // If this tag has content
         if (!preg_match('/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s', $tag[2])) {
             // Opening tag add the closing tag to the top of the stack
             if (preg_match('~<[\\w]+[^>]*>~s', $tag[0])) {
                 array_unshift($open_tags, $tag[2]);
             } elseif (preg_match('~<\\/([\\w]+)[^>]*>~s', $tag[0], $close_tag)) {
                 // Remove its starting tag
                 $pos = array_search($close_tag[1], $open_tags);
                 if ($pos !== false) {
                     array_splice($open_tags, $pos, 1);
                 }
             }
         }
         // Add this (opening or closing) tag to $truncate
         $truncate .= $tag[1];
         // Calculate the length of the actual tag content, accounts for html entities as a single characters
         $content_length = Util::strlen($tag[3]);
         // Have we exceeded the allowed length limit, only add in what we are allowed
         if ($content_length + $total_length > $length) {
             // The number of characters which we can still return
             $remaining = $length - $total_length;
             $truncate .= Util::substr($tag[3], 0, $remaining);
             break;
         } else {
             $truncate .= $tag[3];
             $total_length += $content_length;
         }
         // Are we there yet?
         if ($total_length >= $length) {
             break;
         }
     }
     // Our truncated string up to the last space
     $space_pos = Util::strpos($truncate, ' ', 0, true);
     $space_pos = empty($space_pos) ? $length : $space_pos;
     $truncate_check = Util::substr($truncate, 0, $space_pos);
     // Make sure this would not cause a cut in the middle of a tag
     $lastOpenTag = (int) Util::strpos($truncate_check, '<', 0, true);
     $lastCloseTag = (int) Util::strpos($truncate_check, '>', 0, true);
     if ($lastOpenTag > $lastCloseTag) {
         // Find the last full open tag in our truncated string, its what was being cut
         preg_match_all('~<[\\w]+[^>]*>~s', $truncate, $lastTagMatches);
         $last_tag = array_pop($lastTagMatches[0]);
         // Set the space to just after the last tag
         $space_pos = Util::strpos($truncate, $last_tag, 0, true) + strlen($last_tag);
         $space_pos = empty($space_pos) ? $length : $space_pos;
     }
     // Look at what we are going to cut off the end of our truncated string
     $bits = Util::substr($truncate, $space_pos);
     // Does it cut a tag off, if so we need to know so it can be added back at the cut point
     preg_match_all('~<\\/([a-z]+)>~', $bits, $dropped_tags, PREG_SET_ORDER);
     if (!empty($dropped_tags)) {
         if (!empty($open_tags)) {
             foreach ($dropped_tags as $closing_tag) {
                 if (!in_array($closing_tag[1], $open_tags)) {
                     array_unshift($open_tags, $closing_tag[1]);
                 }
             }
         } else {
             foreach ($dropped_tags as $closing_tag) {
                 $open_tags[] = $closing_tag[1];
             }
         }
     }
     // Cut it
     $truncate = Util::substr($truncate, 0, $space_pos);
     // Dot dot dot
     $truncate .= $ellipsis;
     // Finally close any html tags that were left open
     foreach ($open_tags as $tag) {
         $truncate .= '</' . $tag . '>';
     }
     return $truncate;
 }
Ejemplo n.º 16
0
 /**
  * Do we have to do some work with the words we are searching for to prepare them?
  *
  * @param string $word
  * @param mixed[] $wordsSearch
  * @param string[] $wordsExclude
  * @param boolean $isExcluded
  */
 public function prepareIndexes($word, &$wordsSearch, &$wordsExclude, $isExcluded)
 {
     global $modSettings;
     $subwords = text2words($word, $this->min_word_length, true);
     if (empty($modSettings['search_force_index'])) {
         $wordsSearch['words'][] = $word;
     }
     // Excluded phrases don't benefit from being split into subwords.
     if (count($subwords) > 1 && $isExcluded) {
         return;
     } else {
         foreach ($subwords as $subword) {
             if (Util::strlen($subword) >= $this->min_word_length && !in_array($subword, $this->bannedWords)) {
                 $wordsSearch['indexed_words'][] = $subword;
                 if ($isExcluded) {
                     $wordsExclude[] = $subword;
                 }
             }
         }
     }
 }
Ejemplo n.º 17
0
 /**
  * Callback to return messages - saves memory.
  *
  * @todo Fix this, update it, whatever... from Display.controller.php mainly.
  * Note that the call to loadAttachmentContext() doesn't work:
  * this function doesn't fulfill the pre-condition to fill $attachments global...
  * So all it does is to fallback and return.
  *
  * What it does:
  * - callback function for the results sub template.
  * - loads the necessary contextual data to show a search result.
  *
  * @param boolean $reset = false
  * @return array of messages that match the search
  */
 public function prepareSearchContext_callback($reset = false)
 {
     global $txt, $modSettings, $scripturl, $user_info;
     global $memberContext, $context, $settings, $options, $messages_request;
     global $boards_can, $participants;
     // Remember which message this is.  (ie. reply #83)
     static $counter = null;
     if ($counter == null || $reset) {
         $counter = $_REQUEST['start'] + 1;
     }
     // Start from the beginning...
     if ($reset) {
         return currentContext($messages_request, $reset);
     }
     // Attempt to get the next in line
     $message = currentContext($messages_request);
     if (!$message) {
         return false;
     }
     // Can't have an empty subject can we?
     $message['subject'] = $message['subject'] != '' ? $message['subject'] : $txt['no_subject'];
     $message['first_subject'] = $message['first_subject'] != '' ? $message['first_subject'] : $txt['no_subject'];
     $message['last_subject'] = $message['last_subject'] != '' ? $message['last_subject'] : $txt['no_subject'];
     // If it couldn't load, or the user was a guest.... someday may be done with a guest table.
     if (!loadMemberContext($message['id_member'])) {
         // Notice this information isn't used anywhere else.... *cough guest table cough*.
         $memberContext[$message['id_member']]['name'] = $message['poster_name'];
         $memberContext[$message['id_member']]['id'] = 0;
         $memberContext[$message['id_member']]['group'] = $txt['guest_title'];
         $memberContext[$message['id_member']]['link'] = $message['poster_name'];
         $memberContext[$message['id_member']]['email'] = $message['poster_email'];
     }
     $memberContext[$message['id_member']]['ip'] = $message['poster_ip'];
     // Do the censor thang...
     censorText($message['body']);
     censorText($message['subject']);
     censorText($message['first_subject']);
     censorText($message['last_subject']);
     // Shorten this message if necessary.
     if ($context['compact']) {
         // Set the number of characters before and after the searched keyword.
         $charLimit = 50;
         $message['body'] = strtr($message['body'], array("\n" => ' ', '<br />' => "\n"));
         $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']);
         $message['body'] = strip_tags(strtr($message['body'], array('</div>' => '<br />', '</li>' => '<br />')), '<br>');
         if (Util::strlen($message['body']) > $charLimit) {
             if (empty($context['key_words'])) {
                 $message['body'] = Util::substr($message['body'], 0, $charLimit) . '<strong>...</strong>';
             } else {
                 $matchString = '';
                 $force_partial_word = false;
                 foreach ($context['key_words'] as $keyword) {
                     $keyword = un_htmlspecialchars($keyword);
                     $keyword = preg_replace_callback('~(&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', strtr($keyword, array('\\\'' => '\'', '&' => '&amp;')));
                     if (preg_match('~[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]$~', $keyword) != 0 || preg_match('~^[\'\\.,/@%&;:(){}\\[\\]_\\-+\\\\]~', $keyword) != 0) {
                         $force_partial_word = true;
                     }
                     $matchString .= strtr(preg_quote($keyword, '/'), array('\\*' => '.+?')) . '|';
                 }
                 $matchString = un_htmlspecialchars(substr($matchString, 0, -1));
                 $message['body'] = un_htmlspecialchars(strtr($message['body'], array('&nbsp;' => ' ', '<br />' => "\n", '&#91;' => '[', '&#93;' => ']', '&#58;' => ':', '&#64;' => '@')));
                 if (empty($modSettings['search_method']) || $force_partial_word) {
                     preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?|^)(' . $matchString . ')(.{0,' . $charLimit . '}[\\s\\W]|[^\\s\\W]{0,' . $charLimit . '})/isu', $message['body'], $matches);
                 } else {
                     preg_match_all('/([^\\s\\W]{' . $charLimit . '}[\\s\\W]|[\\s\\W].{0,' . $charLimit . '}?[\\s\\W]|^)(' . $matchString . ')([\\s\\W].{0,' . $charLimit . '}[\\s\\W]|[\\s\\W][^\\s\\W]{0,' . $charLimit . '})/isu', $message['body'], $matches);
                 }
                 $message['body'] = '';
                 foreach ($matches[0] as $index => $match) {
                     $match = strtr(htmlspecialchars($match, ENT_QUOTES, 'UTF-8'), array("\n" => '&nbsp;'));
                     $message['body'] .= '<strong>......</strong>&nbsp;' . $match . '&nbsp;<strong>......</strong>';
                 }
             }
             // Re-fix the international characters.
             $message['body'] = preg_replace_callback('~(&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', 'entity_fix__callback', $message['body']);
         }
     } else {
         // Run BBC interpreter on the message.
         $message['body'] = parse_bbc($message['body'], $message['smileys_enabled'], $message['id_msg']);
     }
     // Make sure we don't end up with a practically empty message body.
     $message['body'] = preg_replace('~^(?:&nbsp;)+$~', '', $message['body']);
     // Sadly, we need to check that the icon is not broken.
     if (!empty($modSettings['messageIconChecks_enable'])) {
         if (!isset($context['icon_sources'][$message['first_icon']])) {
             $context['icon_sources'][$message['first_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['first_icon'] . '.png') ? 'images_url' : 'default_images_url';
         }
         if (!isset($context['icon_sources'][$message['last_icon']])) {
             $context['icon_sources'][$message['last_icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['last_icon'] . '.png') ? 'images_url' : 'default_images_url';
         }
         if (!isset($context['icon_sources'][$message['icon']])) {
             $context['icon_sources'][$message['icon']] = file_exists($settings['theme_dir'] . '/images/post/' . $message['icon'] . '.png') ? 'images_url' : 'default_images_url';
         }
     } else {
         if (!isset($context['icon_sources'][$message['first_icon']])) {
             $context['icon_sources'][$message['first_icon']] = 'images_url';
         }
         if (!isset($context['icon_sources'][$message['last_icon']])) {
             $context['icon_sources'][$message['last_icon']] = 'images_url';
         }
         if (!isset($context['icon_sources'][$message['icon']])) {
             $context['icon_sources'][$message['icon']] = 'images_url';
         }
     }
     // Do we have quote tag enabled?
     $quote_enabled = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
     $output = array_merge($context['topics'][$message['id_msg']], array('id' => $message['id_topic'], 'is_sticky' => !empty($modSettings['enableStickyTopics']) && !empty($message['is_sticky']), 'is_locked' => !empty($message['locked']), 'is_poll' => !empty($modSettings['pollMode']) && $message['id_poll'] > 0, 'is_hot' => !empty($modSettings['useLikesNotViews']) ? $message['num_likes'] >= $modSettings['hotTopicPosts'] : $message['num_replies'] >= $modSettings['hotTopicPosts'], 'is_very_hot' => !empty($modSettings['useLikesNotViews']) ? $message['num_likes'] >= $modSettings['hotTopicVeryPosts'] : $message['num_replies'] >= $modSettings['hotTopicVeryPosts'], 'posted_in' => !empty($participants[$message['id_topic']]), 'views' => $message['num_views'], 'replies' => $message['num_replies'], 'tests' => array('can_reply' => in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any']), 'can_quote' => (in_array($message['id_board'], $boards_can['post_reply_any']) || in_array(0, $boards_can['post_reply_any'])) && $quote_enabled, 'can_mark_notify' => in_array($message['id_board'], $boards_can['mark_any_notify']) || in_array(0, $boards_can['mark_any_notify']) && !$context['user']['is_guest']), 'first_post' => array('id' => $message['first_msg'], 'time' => standardTime($message['first_poster_time']), 'html_time' => htmlTime($message['first_poster_time']), 'timestamp' => forum_time(true, $message['first_poster_time']), 'subject' => $message['first_subject'], 'href' => $scripturl . '?topic=' . $message['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . '.0">' . $message['first_subject'] . '</a>', 'icon' => $message['first_icon'], 'icon_url' => $settings[$context['icon_sources'][$message['first_icon']]] . '/post/' . $message['first_icon'] . '.png', 'member' => array('id' => $message['first_member_id'], 'name' => $message['first_member_name'], 'href' => !empty($message['first_member_id']) ? $scripturl . '?action=profile;u=' . $message['first_member_id'] : '', 'link' => !empty($message['first_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['first_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['first_member_name'] . '">' . $message['first_member_name'] . '</a>' : $message['first_member_name'])), 'last_post' => array('id' => $message['last_msg'], 'time' => standardTime($message['last_poster_time']), 'html_time' => htmlTime($message['last_poster_time']), 'timestamp' => forum_time(true, $message['last_poster_time']), 'subject' => $message['last_subject'], 'href' => $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'], 'link' => '<a href="' . $scripturl . '?topic=' . $message['id_topic'] . ($message['num_replies'] == 0 ? '.0' : '.msg' . $message['last_msg']) . '#msg' . $message['last_msg'] . '">' . $message['last_subject'] . '</a>', 'icon' => $message['last_icon'], 'icon_url' => $settings[$context['icon_sources'][$message['last_icon']]] . '/post/' . $message['last_icon'] . '.png', 'member' => array('id' => $message['last_member_id'], 'name' => $message['last_member_name'], 'href' => !empty($message['last_member_id']) ? $scripturl . '?action=profile;u=' . $message['last_member_id'] : '', 'link' => !empty($message['last_member_id']) ? '<a href="' . $scripturl . '?action=profile;u=' . $message['last_member_id'] . '" title="' . $txt['profile_of'] . ' ' . $message['last_member_name'] . '">' . $message['last_member_name'] . '</a>' : $message['last_member_name'])), 'board' => array('id' => $message['id_board'], 'name' => $message['board_name'], 'href' => $scripturl . '?board=' . $message['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $message['id_board'] . '.0">' . $message['board_name'] . '</a>'), 'category' => array('id' => $message['id_cat'], 'name' => $message['cat_name'], 'href' => $scripturl . '#c' . $message['id_cat'], 'link' => '<a href="' . $scripturl . '#c' . $message['id_cat'] . '">' . $message['cat_name'] . '</a>')));
     determineTopicClass($output);
     if ($output['posted_in']) {
         $output['class'] = 'my_' . $output['class'];
     }
     $body_highlighted = $message['body'];
     $subject_highlighted = $message['subject'];
     if (!empty($options['display_quick_mod'])) {
         $started = $output['first_post']['member']['id'] == $user_info['id'];
         $output['quick_mod'] = array('lock' => in_array(0, $boards_can['lock_any']) || in_array($output['board']['id'], $boards_can['lock_any']) || $started && (in_array(0, $boards_can['lock_own']) || in_array($output['board']['id'], $boards_can['lock_own'])), 'sticky' => (in_array(0, $boards_can['make_sticky']) || in_array($output['board']['id'], $boards_can['make_sticky'])) && !empty($modSettings['enableStickyTopics']), 'move' => in_array(0, $boards_can['move_any']) || in_array($output['board']['id'], $boards_can['move_any']) || $started && (in_array(0, $boards_can['move_own']) || in_array($output['board']['id'], $boards_can['move_own'])), 'remove' => in_array(0, $boards_can['remove_any']) || in_array($output['board']['id'], $boards_can['remove_any']) || $started && (in_array(0, $boards_can['remove_own']) || in_array($output['board']['id'], $boards_can['remove_own'])));
         $context['can_lock'] |= $output['quick_mod']['lock'];
         $context['can_sticky'] |= $output['quick_mod']['sticky'];
         $context['can_move'] |= $output['quick_mod']['move'];
         $context['can_remove'] |= $output['quick_mod']['remove'];
         $context['can_merge'] |= in_array($output['board']['id'], $boards_can['merge_any']);
         $context['can_markread'] = $context['user']['is_logged'];
         $context['qmod_actions'] = array('remove', 'lock', 'sticky', 'move', 'markread');
         call_integration_hook('integrate_quick_mod_actions_search');
     }
     foreach ($context['key_words'] 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'), $body_highlighted);
         $subject_highlighted = preg_replace('/(' . preg_quote($query, '/') . ')/iu', '<strong class="highlight">$1</strong>', $subject_highlighted);
     }
     require_once SUBSDIR . '/Attachments.subs.php';
     $output['matches'][] = array('id' => $message['id_msg'], 'attachment' => loadAttachmentContext($message['id_msg']), 'alternate' => $counter % 2, 'member' => &$memberContext[$message['id_member']], 'icon' => $message['icon'], 'icon_url' => $settings[$context['icon_sources'][$message['icon']]] . '/post/' . $message['icon'] . '.png', 'subject' => $message['subject'], 'subject_highlighted' => $subject_highlighted, 'time' => standardTime($message['poster_time']), 'html_time' => htmlTime($message['poster_time']), 'timestamp' => forum_time(true, $message['poster_time']), 'counter' => $counter, 'modified' => array('time' => standardTime($message['modified_time']), 'html_time' => htmlTime($message['modified_time']), 'timestamp' => forum_time(true, $message['modified_time']), 'name' => $message['modified_name']), 'body' => $message['body'], 'body_highlighted' => $body_highlighted, 'start' => 'msg' . $message['id_msg']);
     $counter++;
     if (!$context['compact']) {
         $output['buttons'] = array('notify' => array('href' => $scripturl . '?action=notify;topic=' . $output['id'] . '.msg' . $message['id_msg'], 'text' => $txt['notify'], 'test' => 'can_mark_notify'), 'reply' => array('href' => $scripturl . '?action=post;topic=' . $output['id'] . '.msg' . $message['id_msg'], 'text' => $txt['reply'], 'test' => 'can_reply'), 'quote' => array('href' => $scripturl . '?action=post;topic=' . $output['id'] . '.msg' . $message['id_msg'] . ';quote=' . $message['id_msg'], 'text' => $txt['quote'], 'test' => 'can_quote'));
     }
     call_integration_hook('integrate_search_message_context', array($counter, &$output));
     return $output;
 }
Ejemplo n.º 18
0
/**
 * Create a new topic by email
 *
 * What it does:
 * - Called by pbe_topic to create a new topic or by pbe_main to create a new topic via a subject change
 * - checks posting permissions, but requires all email validation checks are complete
 * - Calls pbe_load_text to prepare text for the post
 * - Uses createPost to do the actual "posting"
 * - Calls sendNotifications to announce the new post
 * - Calls query_update_member_stats to show they did something
 * - Requires the pbe, email_message and board_info arrays to be populated.
 *
 * @package Maillist
 * @param mixed[] $pbe array of pbe 'user_info' values
 * @param Email_Parse $email_message
 * @param mixed[] $board_info
 */
function pbe_create_topic($pbe, $email_message, $board_info)
{
    global $txt, $modSettings;
    // It does not work like that
    if (empty($pbe) || empty($email_message)) {
        return false;
    }
    // We have the board info, and their permissions - do they have a right to start a new topic?
    $becomesApproved = true;
    if (!$pbe['user_info']['is_admin']) {
        if (!in_array('postby_email', $pbe['user_info']['permissions'])) {
            return pbe_emailError('error_permission', $email_message);
        } elseif ($modSettings['postmod_active'] && in_array('post_unapproved_topics', $pbe['user_info']['permissions']) && !in_array('post_new', $pbe['user_info']['permissions'])) {
            $becomesApproved = false;
        } elseif (!in_array('post_new', $pbe['user_info']['permissions'])) {
            return pbe_emailError('error_cant_start', $email_message);
        }
    }
    // Approving all new topics by email anyway, smart admin this one is ;)
    if (!empty($modSettings['maillist_newtopic_needsapproval'])) {
        $becomesApproved = false;
    }
    // First on the agenda the subject
    $subject = pbe_clean_email_subject($email_message->subject);
    $subject = strtr(Util::htmlspecialchars($subject), array("\r" => '', "\n" => '', "\t" => ''));
    // Not to long not to short
    if (Util::strlen($subject) > 100) {
        $subject = Util::substr($subject, 0, 100);
    } elseif ($subject == '') {
        return pbe_emailError('error_no_subject', $email_message);
    }
    // The message itself will need a bit of work
    $html = $email_message->html_found;
    $text = pbe_load_text($html, $email_message, $pbe);
    if (empty($text)) {
        return pbe_emailError('error_no_message', $email_message);
    }
    // Build the attachment array if needed
    if (!empty($email_message->attachments) && !empty($modSettings['maillist_allow_attachments']) && !empty($modSettings['attachmentEnable']) && $modSettings['attachmentEnable'] == 1) {
        if ($modSettings['postmod_active'] && in_array('post_unapproved_attachments', $pbe['user_info']['permissions']) || in_array('post_attachment', $pbe['user_info']['permissions'])) {
            $attachIDs = pbe_email_attachments($pbe, $email_message);
        } else {
            $text .= "\n\n" . $txt['error_no_attach'] . "\n";
        }
    }
    // If we get to this point ... then its time to play, lets start a topic !
    require_once SUBSDIR . '/Post.subs.php';
    // Setup the topic variables.
    $msgOptions = array('id' => 0, 'subject' => $subject, 'smileys_enabled' => true, 'body' => $text, 'attachments' => empty($attachIDs) ? array() : $attachIDs, 'approved' => $becomesApproved);
    $topicOptions = array('id' => 0, 'board' => $board_info['id_board'], 'mark_as_read' => false);
    $posterOptions = array('id' => $pbe['profile']['id_member'], 'name' => $pbe['profile']['real_name'], 'email' => $pbe['profile']['email_address'], 'update_post_count' => empty($board_info['count_posts']), 'ip' => isset($email_message->ip) ? $email_message->ip : $pbe['profile']['member_ip']);
    // Attempt to make the new topic.
    createPost($msgOptions, $topicOptions, $posterOptions);
    // The auto_notify setting
    $theme_settings = query_get_theme($pbe['profile']['id_member'], $pbe['profile']['id_theme'], $board_info);
    $auto_notify = isset($theme_settings['auto_notify']) ? $theme_settings['auto_notify'] : 0;
    // Notifications on or off
    query_notifications($pbe['profile']['id_member'], $board_info['id_board'], $topicOptions['id'], $auto_notify, $pbe['user_info']['permissions']);
    // Notify members who have notification turned on for this, (if it's approved)
    if ($becomesApproved) {
        require_once SUBSDIR . '/Notification.subs.php';
        sendNotifications($topicOptions['id'], 'reply', array(), array(), $pbe);
    }
    // Update this users info so the log shows them as active
    query_update_member_stats($pbe, $email_message, $topicOptions);
    return true;
}
Ejemplo n.º 19
0
 /**
  * Send the emails.
  *
  * - Sends off emails to all the moderators.
  * - Sends to administrators and global moderators. (1 and 2)
  * - Called by action_reporttm(), and thus has the same permission and setting requirements as it does.
  * - Accessed through ?action=reporttm when posting.
  */
 public function action_reporttm2()
 {
     global $txt, $scripturl, $topic, $board, $user_info, $modSettings, $language, $context;
     // You must have the proper permissions!
     isAllowedTo('report_any');
     // Make sure they aren't spamming.
     spamProtection('reporttm');
     require_once SUBSDIR . '/Mail.subs.php';
     // No errors, yet.
     $report_errors = Error_Context::context('report', 1);
     // Check their session.
     if (checkSession('post', '', false) != '') {
         $report_errors->addError('session_timeout');
     }
     // Make sure we have a comment and it's clean.
     if (!isset($_POST['comment']) || Util::htmltrim($_POST['comment']) === '') {
         $report_errors->addError('no_comment');
     }
     $poster_comment = strtr(Util::htmlspecialchars($_POST['comment']), array("\r" => '', "\t" => ''));
     if (Util::strlen($poster_comment) > 254) {
         $report_errors->addError('post_too_long');
     }
     // Guests need to provide their address!
     if ($user_info['is_guest']) {
         require_once SUBSDIR . '/DataValidator.class.php';
         if (!Data_Validator::is_valid($_POST, array('email' => 'valid_email'), array('email' => 'trim'))) {
             empty($_POST['email']) ? $report_errors->addError('no_email') : $report_errors->addError('bad_email');
         }
         isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title']));
         $user_info['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8');
     }
     // Could they get the right verification code?
     if ($user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha'])) {
         require_once SUBSDIR . '/VerificationControls.class.php';
         $verificationOptions = array('id' => 'report');
         $context['require_verification'] = create_control_verification($verificationOptions, true);
         if (is_array($context['require_verification'])) {
             foreach ($context['require_verification'] as $error) {
                 $report_errors->addError($error, 0);
             }
         }
     }
     // Any errors?
     if ($report_errors->hasErrors()) {
         return $this->action_reporttm();
     }
     // Get the basic topic information, and make sure they can see it.
     $msg_id = (int) $_POST['msg'];
     $message = posterDetails($msg_id, $topic);
     if (empty($message)) {
         fatal_lang_error('no_board', false);
     }
     $poster_name = un_htmlspecialchars($message['real_name']) . ($message['real_name'] != $message['poster_name'] ? ' (' . $message['poster_name'] . ')' : '');
     $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : '');
     $subject = un_htmlspecialchars($message['subject']);
     // Get a list of members with the moderate_board permission.
     require_once SUBSDIR . '/Members.subs.php';
     $moderators = membersAllowedTo('moderate_board', $board);
     $result = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile'));
     $mod_to_notify = array();
     foreach ($result as $row) {
         if ($row['notify_types'] != 4) {
             $mod_to_notify[] = $row;
         }
     }
     // Check that moderators do exist!
     if (empty($mod_to_notify)) {
         fatal_lang_error('no_mods', false);
     }
     // If we get here, I believe we should make a record of this, for historical significance, yabber.
     if (empty($modSettings['disable_log_report'])) {
         require_once SUBSDIR . '/Messages.subs.php';
         $id_report = recordReport($message, $poster_comment);
         // If we're just going to ignore these, then who gives a monkeys...
         if ($id_report === false) {
             redirectexit('topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
         }
     }
     // Find out who the real moderators are - for mod preferences.
     require_once SUBSDIR . '/Boards.subs.php';
     $real_mods = getBoardModerators($board, true);
     // Send every moderator an email.
     foreach ($mod_to_notify as $row) {
         // Maybe they don't want to know?!
         if (!empty($row['mod_prefs'])) {
             list(, , $pref_binary) = explode('|', $row['mod_prefs']);
             if (!($pref_binary & 1) && (!($pref_binary & 2) || !in_array($row['id_member'], $real_mods))) {
                 continue;
             }
         }
         $replacements = array('TOPICSUBJECT' => $subject, 'POSTERNAME' => $poster_name, 'REPORTERNAME' => $reporterName, 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id, 'REPORTLINK' => !empty($id_report) ? $scripturl . '?action=moderate;area=reports;report=' . $id_report : '', 'COMMENT' => $_POST['comment']);
         $emaildata = loadEmailTemplate('report_to_moderator', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']);
         // Send it to the moderator.
         sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], $user_info['email'], null, false, 2);
     }
     // Keep track of when the mod reports get updated, that way we know when we need to look again.
     updateSettings(array('last_mod_report_action' => time()));
     // Back to the post we reported!
     redirectexit('reportsent;topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id);
 }
Ejemplo n.º 20
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;
}
/**
 * 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;
}
Ejemplo n.º 22
0
 /**
  * Get the recent topics to display.
  * The returned array will be generated to match the xml_format.
  *
  * @param string $xml_format one of rss, rss2, rdf, atom
  * @return mixed[] of recent posts
  */
 public function action_xmlrecent($xml_format)
 {
     global $scripturl, $modSettings, $board;
     // Get the latest news
     require_once SUBSDIR . '/News.subs.php';
     $results = getXMLRecent($this->_query_this_board, $board, $this->_limit);
     // Loop on the results and prepare them in the format requested
     $data = array();
     foreach ($results as $row) {
         // Limit the length of the message, if the option is set.
         if (!empty($modSettings['xmlnews_maxlen']) && Util::strlen(str_replace('<br />', "\n", $row['body'])) > $modSettings['xmlnews_maxlen']) {
             $row['body'] = strtr(Util::shorten_text(str_replace('<br />', "\n", $row['body']), $modSettings['xmlnews_maxlen'], true), array("\n" => '<br />'));
         }
         $row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], $row['id_msg']);
         // You can't say that
         censorText($row['body']);
         censorText($row['subject']);
         // Doesn't work as well as news, but it kinda does..
         if ($xml_format == 'rss' || $xml_format == 'rss2') {
             $data[] = array('title' => $row['subject'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'description' => cdata_parse(strtr(un_htmlspecialchars($row['body']), '&', '&#x26;')), 'author' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] . ' (' . un_htmlspecialchars($row['poster_name']) . ')' : '<![CDATA[none@noreply.net (' . un_htmlspecialchars($row['poster_name']) . ')]]>', 'category' => cdata_parse($row['bname']), 'comments' => $scripturl . '?action=post;topic=' . $row['id_topic'] . '.0', 'pubDate' => gmdate('D, d M Y H:i:s \\G\\M\\T', $row['poster_time']), 'guid' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']);
             // Add the poster name on if we are rss2
             if ($xml_format == 'rss2') {
                 $data[count($data) - 1]['dc:creator'] = $row['poster_name'];
                 unset($data[count($data) - 1]['author']);
             }
         } elseif ($xml_format == 'rdf') {
             $data[] = array('title' => $row['subject'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'description' => cdata_parse($row['body']));
         } elseif ($xml_format == 'atom') {
             $data[] = array('title' => $row['subject'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'summary' => cdata_parse($row['body']), 'category' => $row['bname'], 'author' => array('name' => $row['poster_name'], 'email' => in_array(showEmailAddress(!empty($row['hide_email']), $row['id_member']), array('yes', 'yes_permission_override')) ? $row['poster_email'] : null, 'uri' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : ''), 'published' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', $row['poster_time']), 'updated' => gmstrftime('%Y-%m-%dT%H:%M:%SZ', empty($row['modified_time']) ? $row['poster_time'] : $row['modified_time']), 'id' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']);
         } else {
             $data[] = array('time' => htmlspecialchars(strip_tags(standardTime($row['poster_time'])), ENT_COMPAT, 'UTF-8'), 'id' => $row['id_msg'], 'subject' => cdata_parse($row['subject']), 'body' => cdata_parse($row['body']), 'starter' => array('name' => cdata_parse($row['first_poster_name']), 'id' => $row['id_first_member'], 'link' => !empty($row['id_first_member']) ? $scripturl . '?action=profile;u=' . $row['id_first_member'] : ''), 'poster' => array('name' => cdata_parse($row['poster_name']), 'id' => $row['id_member'], 'link' => !empty($row['id_member']) ? $scripturl . '?action=profile;u=' . $row['id_member'] : ''), 'topic' => array('subject' => cdata_parse($row['first_subject']), 'id' => $row['id_topic'], 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.new#new'), 'board' => array('name' => cdata_parse($row['bname']), 'id' => $row['id_board'], 'link' => $scripturl . '?board=' . $row['id_board'] . '.0'), 'link' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']);
         }
     }
     return $data;
 }
Ejemplo n.º 23
0
 /**
  * Actually logs you in.
  *
  * What it does:
  * - checks credentials and checks that login was successful.
  * - it employs protection against a specific IP or user trying to brute force
  *   a login to an account.
  * - upgrades password encryption on login, if necessary.
  * - after successful login, redirects you to $_SESSION['login_url'].
  * - accessed from ?action=login2, by forms.
  *
  * On error, uses the same templates action_login() uses.
  */
 public function action_login2()
 {
     global $txt, $scripturl, $user_info, $user_settings, $modSettings, $context, $sc;
     // Load cookie authentication and all stuff.
     require_once SUBSDIR . '/Auth.subs.php';
     // Beyond this point you are assumed to be a guest trying to login.
     if (!$user_info['is_guest']) {
         redirectexit();
     }
     // Are you guessing with a script?
     checkSession('post');
     validateToken('login');
     spamProtection('login');
     // Set the login_url if it's not already set (but careful not to send us to an attachment).
     if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0 || isset($_GET['quicklogin']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'login') === false) {
         $_SESSION['login_url'] = $_SESSION['old_url'];
     }
     // Been guessing a lot, haven't we?
     if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) {
         fatal_lang_error('login_threshold_fail', 'critical');
     }
     // Set up the cookie length.  (if it's invalid, just fall through and use the default.)
     if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) {
         $modSettings['cookieTime'] = 3153600;
     } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) {
         $modSettings['cookieTime'] = (int) $_POST['cookielength'];
     }
     loadLanguage('Login');
     // Load the template stuff
     loadTemplate('Login');
     loadJavascriptFile('sha256.js', array('defer' => true));
     $context['sub_template'] = 'login';
     // Set up the default/fallback stuff.
     $context['default_username'] = isset($_POST['user']) ? preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_POST['user'], ENT_COMPAT, 'UTF-8')) : '';
     $context['default_password'] = '';
     $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600;
     $context['login_errors'] = array($txt['error_occurred']);
     $context['page_title'] = $txt['login'];
     // Add the login chain to the link tree.
     $context['linktree'][] = array('url' => $scripturl . '?action=login', 'name' => $txt['login']);
     // This is an OpenID login. Let's validate...
     if (!empty($_POST['openid_identifier']) && !empty($modSettings['enableOpenID'])) {
         require_once SUBSDIR . '/OpenID.subs.php';
         $open_id = new OpenID();
         if ($open_id->validate($_POST['openid_identifier']) !== 'no_data') {
             return $open_id;
         } else {
             $context['login_errors'] = array($txt['openid_not_found']);
             return;
         }
     }
     // You forgot to type your username, dummy!
     if (!isset($_POST['user']) || $_POST['user'] == '') {
         $context['login_errors'] = array($txt['need_username']);
         return;
     }
     // No one needs a username that long, plus we only support 80 chars in the db
     if (Util::strlen($_POST['user']) > 80) {
         $_POST['user'] = Util::substr($_POST['user'], 0, 80);
     }
     // Can't use a password > 64 characters sorry, to long and only good for a DoS attack
     // Plus we expect a 64 character one from SHA-256
     if (isset($_POST['passwrd']) && strlen($_POST['passwrd']) > 64 || isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) > 64) {
         $context['login_errors'] = array($txt['improper_password']);
         return;
     }
     // Hmm... maybe 'admin' will login with no password. Uhh... NO!
     if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_POST['hash_passwrd']) || strlen($_POST['hash_passwrd']) != 64)) {
         $context['login_errors'] = array($txt['no_password']);
         return;
     }
     // No funky symbols either.
     if (preg_match('~[<>&"\'=\\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_POST['user'])) != 0) {
         $context['login_errors'] = array($txt['error_invalid_characters_username']);
         return;
     }
     // Are we using any sort of integration to validate the login?
     if (in_array('retry', call_integration_hook('integrate_validate_login', array($_POST['user'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime'])), true)) {
         $context['login_errors'] = array($txt['login_hash_error']);
         $context['disable_login_hashing'] = true;
         return;
     }
     // Find them... if we can
     $user_settings = loadExistingMember($_POST['user']);
     // Let them try again, it didn't match anything...
     if (empty($user_settings)) {
         $context['login_errors'] = array($txt['username_no_exist']);
         return;
     }
     // Figure out if the password is using Elk's encryption - if what they typed is right.
     if (isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) === 64) {
         // Challenge what was passed
         $valid_password = validateLoginPassword($_POST['hash_passwrd'], $user_settings['passwd']);
         // Let them in
         if ($valid_password) {
             $sha_passwd = $_POST['hash_passwrd'];
             $valid_password = true;
         } elseif (preg_match('/^[0-9a-f]{40}$/i', $user_settings['passwd']) && isset($_POST['old_hash_passwrd']) && $_POST['old_hash_passwrd'] === hash('sha1', $user_settings['passwd'] . $sc)) {
             // Old password passed, turn off hashing and ask for it again so we can update the db to something more secure.
             $context['login_errors'] = array($txt['login_hash_error']);
             $context['disable_login_hashing'] = true;
             unset($user_settings);
             return;
         } else {
             // Don't allow this!
             validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
             $_SESSION['failed_login'] = isset($_SESSION['failed_login']) ? $_SESSION['failed_login'] + 1 : 1;
             // To many tries, maybe they need a reminder
             if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                 redirectexit('action=reminder');
             } else {
                 log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
                 // Wrong password, lets enable plain text responses in case form hashing is causing problems
                 $context['disable_login_hashing'] = true;
                 $context['login_errors'] = array($txt['incorrect_password']);
                 unset($user_settings);
                 return;
             }
         }
     } else {
         // validateLoginPassword will hash this like the form normally would and check its valid
         $sha_passwd = $_POST['passwrd'];
         $valid_password = validateLoginPassword($sha_passwd, $user_settings['passwd'], $user_settings['member_name']);
     }
     // Bad password!  Thought you could fool the database?!
     if ($valid_password === false) {
         // Let's be cautious, no hacking please. thanx.
         validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
         // Maybe we were too hasty... let's try some other authentication methods.
         $other_passwords = $this->_other_passwords($user_settings);
         // Whichever encryption it was using, let's make it use ElkArte's now ;).
         if (in_array($user_settings['passwd'], $other_passwords)) {
             $user_settings['passwd'] = validateLoginPassword($sha_passwd, '', '', true);
             $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
             // Update the password hash and set up the salt.
             updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'], 'passwd_flood' => ''));
         } else {
             // They've messed up again - keep a count to see if they need a hand.
             $_SESSION['failed_login'] = isset($_SESSION['failed_login']) ? $_SESSION['failed_login'] + 1 : 1;
             // Hmm... don't remember it, do you?  Here, try the password reminder ;).
             if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) {
                 redirectexit('action=reminder');
             } else {
                 // Log an error so we know that it didn't go well in the error log.
                 log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
                 $context['login_errors'] = array($txt['incorrect_password']);
                 return;
             }
         }
     } elseif (!empty($user_settings['passwd_flood'])) {
         // Let's be sure they weren't a little hacker.
         validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true);
         // If we got here then we can reset the flood counter.
         updateMemberData($user_settings['id_member'], array('passwd_flood' => ''));
     }
     // Correct password, but they've got no salt; fix it!
     if ($user_settings['password_salt'] == '') {
         $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
         updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt']));
     }
     // Check their activation status.
     if (!checkActivation()) {
         return;
     }
     doLogin();
 }
Ejemplo n.º 24
0
/**
 * Checks whether a password meets the current forum rules
 *
 * What it does:
 * - called when registering/choosing a password.
 * - checks the password obeys the current forum settings for password strength.
 * - if password checking is enabled, will check that none of the words in restrict_in appear in the password.
 * - returns an error identifier if the password is invalid, or null.
 *
 * @package Authorization
 * @param string $password
 * @param string $username
 * @param string[] $restrict_in = array()
 * @return string an error identifier if the password is invalid
 */
function validatePassword($password, $username, $restrict_in = array())
{
    global $modSettings, $txt;
    // Perform basic requirements first.
    if (Util::strlen($password) < (empty($modSettings['password_strength']) ? 4 : 8)) {
        loadLanguage('Errors');
        $txt['profile_error_password_short'] = sprintf($txt['profile_error_password_short'], empty($modSettings['password_strength']) ? 4 : 8);
        return 'short';
    }
    // Is this enough?
    if (empty($modSettings['password_strength'])) {
        return null;
    }
    // Otherwise, perform the medium strength test - checking if password appears in the restricted string.
    if (preg_match('~\\b' . preg_quote($password, '~') . '\\b~', implode(' ', $restrict_in)) != 0) {
        return 'restricted_words';
    } elseif (Util::strpos($password, $username) !== false) {
        return 'restricted_words';
    }
    // If just medium, we're done.
    if ($modSettings['password_strength'] == 1) {
        return null;
    }
    // Otherwise, hard test next, check for numbers and letters, uppercase too.
    $good = preg_match('~(\\D\\d|\\d\\D)~', $password) != 0;
    $good &= Util::strtolower($password) != $password;
    return $good ? null : 'chars';
}
Ejemplo n.º 25
0
 /**
  * length ... Determine if the provided value length matches a specific value
  *
  * Usage: '[key]' => 'exact_length[x]'
  *
  * @param string $field
  * @param mixed[] $input
  * @param mixed[]|null $validation_parameters array or null
  */
 protected function _validate_length($field, $input, $validation_parameters = null)
 {
     if (!isset($input[$field])) {
         return;
     }
     if (Util::strlen($input[$field]) == (int) $validation_parameters) {
         return;
     }
     return array('field' => $field, 'input' => $input[$field], 'function' => __FUNCTION__, 'param' => $validation_parameters);
 }
Ejemplo n.º 26
0
 /**
  * Execute the move of a topic.
  * It is called on the submit of action_movetopic.
  * This function logs that topics have been moved in the moderation log.
  * If the member is the topic starter requires the move_own permission,
  * otherwise requires the move_any permission.
  * Upon successful completion redirects to message index.
  * Accessed via ?action=movetopic2.
  *
  * @uses subs/Post.subs.php.
  */
 public function action_movetopic2()
 {
     global $txt, $board, $topic, $scripturl, $context, $language, $user_info;
     if (empty($topic)) {
         fatal_lang_error('no_access', false);
     }
     // You can't choose to have a redirection topic and use an empty reason.
     if (isset($_POST['postRedirect']) && (!isset($_POST['reason']) || trim($_POST['reason']) == '')) {
         fatal_lang_error('movetopic_no_reason', false);
     }
     // You have to tell us were you are moving to
     if (!isset($_POST['toboard'])) {
         fatal_lang_error('movetopic_no_board', false);
     }
     // We will need this
     require_once SUBSDIR . '/Topic.subs.php';
     moveTopicConcurrence();
     // Make sure this form hasn't been submitted before.
     checkSubmitOnce('check');
     // Get the basic details on this topic
     $topic_info = getTopicInfo($topic);
     $context['is_approved'] = $topic_info['approved'];
     // Can they see it?
     if (!$context['is_approved']) {
         isAllowedTo('approve_posts');
     }
     // Can they move topics on this board?
     if (!allowedTo('move_any')) {
         if ($topic_info['id_member_started'] == $user_info['id']) {
             isAllowedTo('move_own');
         } else {
             isAllowedTo('move_any');
         }
     }
     checkSession();
     require_once SUBSDIR . '/Post.subs.php';
     require_once SUBSDIR . '/Boards.subs.php';
     // The destination board must be numeric.
     $toboard = (int) $_POST['toboard'];
     // Make sure they can see the board they are trying to move to (and get whether posts count in the target board).
     $board_info = boardInfo($toboard, $topic);
     if (empty($board_info)) {
         fatal_lang_error('no_board');
     }
     // Remember this for later.
     $_SESSION['move_to_topic'] = array('move_to' => $toboard);
     // Rename the topic...
     if (isset($_POST['reset_subject'], $_POST['custom_subject']) && $_POST['custom_subject'] != '') {
         $custom_subject = strtr(Util::htmltrim(Util::htmlspecialchars($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => ''));
         // Keep checking the length.
         if (Util::strlen($custom_subject) > 100) {
             $custom_subject = Util::substr($custom_subject, 0, 100);
         }
         // If it's still valid move onwards and upwards.
         if ($custom_subject != '') {
             $all_messages = isset($_POST['enforce_subject']);
             if ($all_messages) {
                 // Get a response prefix, but in the forum's default language.
                 $context['response_prefix'] = response_prefix();
                 topicSubject($topic_info, $custom_subject, $context['response_prefix'], $all_messages);
             } else {
                 topicSubject($topic_info, $custom_subject);
             }
             // Fix the subject cache.
             updateStats('subject', $topic, $custom_subject);
         }
     }
     // Create a link to this in the old board.
     // @todo Does this make sense if the topic was unapproved before? I'd just about say so.
     if (isset($_POST['postRedirect'])) {
         // Should be in the boardwide language.
         if ($user_info['language'] != $language) {
             loadLanguage('index', $language);
         }
         $reason = Util::htmlspecialchars($_POST['reason'], ENT_QUOTES);
         preparsecode($reason);
         // Add a URL onto the message.
         $reason = strtr($reason, array($txt['movetopic_auto_board'] => '[url=' . $scripturl . '?board=' . $toboard . '.0]' . $board_info['name'] . '[/url]', $txt['movetopic_auto_topic'] => '[iurl]' . $scripturl . '?topic=' . $topic . '.0[/iurl]'));
         // Auto remove this MOVED redirection topic in the future?
         $redirect_expires = !empty($_POST['redirect_expires']) ? (int) $_POST['redirect_expires'] : 0;
         // Redirect to the MOVED topic from topic list?
         $redirect_topic = isset($_POST['redirect_topic']) ? $topic : 0;
         // And remember the last expiry period too.
         $_SESSION['move_to_topic']['redirect_topic'] = $redirect_topic;
         $_SESSION['move_to_topic']['redirect_expires'] = $redirect_expires;
         $msgOptions = array('subject' => $txt['moved'] . ': ' . $board_info['subject'], 'body' => $reason, 'icon' => 'moved', 'smileys_enabled' => 1);
         $topicOptions = array('board' => $board, 'lock_mode' => 1, 'mark_as_read' => true, 'redirect_expires' => empty($redirect_expires) ? 0 : $redirect_expires * 60 + time(), 'redirect_topic' => $redirect_topic);
         $posterOptions = array('id' => $user_info['id'], 'update_post_count' => empty($board_info['count_posts']));
         createPost($msgOptions, $topicOptions, $posterOptions);
     }
     $board_from = boardInfo($board);
     if ($board_from['count_posts'] != $board_info['count_posts']) {
         $posters = postersCount($topic);
         foreach ($posters as $id_member => $posts) {
             // The board we're moving from counted posts, but not to.
             if (empty($board_from['count_posts'])) {
                 updateMemberData($id_member, array('posts' => 'posts - ' . $posts));
             } else {
                 updateMemberData($id_member, array('posts' => 'posts + ' . $posts));
             }
         }
     }
     // Do the move (includes statistics update needed for the redirect topic).
     moveTopics($topic, $toboard);
     // Log that they moved this topic.
     if (!allowedTo('move_own') || $topic_info['id_member_started'] != $user_info['id']) {
         logAction('move', array('topic' => $topic, 'board_from' => $board, 'board_to' => $toboard));
     }
     // Notify people that this topic has been moved?
     require_once SUBSDIR . '/Notification.subs.php';
     sendNotifications($topic, 'move');
     // Why not go back to the original board in case they want to keep moving?
     if (!isset($_REQUEST['goback'])) {
         redirectexit('board=' . $board . '.0');
     } else {
         redirectexit('topic=' . $topic . '.0');
     }
 }
Ejemplo n.º 27
0
 /**
  * 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']);
     }
 }
/**
 * Theme Selection Block, Displays themes available for user selection
 *
 * @param mixed[] $parameters not used in this block
 * @param int $id - not used in this block
 * @param boolean $return_parameters if true returns the configuration options for the block
 */
function sp_theme_select($parameters, $id, $return_parameters = false)
{
    global $modSettings, $user_info, $settings, $language, $txt;
    $block_parameters = array();
    if ($return_parameters) {
        return $block_parameters;
    }
    loadLanguage('Profile');
    loadLanguage('ManageThemes');
    require_once SUBSDIR . '/Themes.subs.php';
    if (!empty($_SESSION['id_theme']) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) {
        $current_theme = (int) $_SESSION['id_theme'];
    } else {
        $current_theme = $user_info['theme'];
    }
    // Load in all the themes in the system
    $current_theme = empty($current_theme) ? -1 : $current_theme;
    $available_themes = installedThemes();
    // Set the guest theme
    if (!isset($available_themes[$modSettings['theme_guests']])) {
        $available_themes[0] = array('num_users' => 0);
        $guest_theme = 0;
    } else {
        $guest_theme = $modSettings['theme_guests'];
    }
    $current_images_url = $settings['images_url'];
    foreach ($available_themes as $id_theme => $theme_data) {
        if ($id_theme == 0) {
            continue;
        }
        $settings['images_url'] =& $theme_data['images_url'];
        // Set the description in their language if available
        if (file_exists($theme_data['theme_dir'] . '/languages/Settings.' . $user_info['language'] . '.php')) {
            include $theme_data['theme_dir'] . '/languages/Settings.' . $user_info['language'] . '.php';
        } elseif (file_exists($theme_data['theme_dir'] . '/languages/Settings.' . $language . '.php')) {
            include $theme_data['theme_dir'] . '/languages/Settings.' . $language . '.php';
        } else {
            $txt['theme_thumbnail_href'] = $theme_data['images_url'] . '/thumbnail.png';
            $txt['theme_description'] = '';
        }
        $available_themes[$id_theme]['thumbnail_href'] = $txt['theme_thumbnail_href'];
        $available_themes[$id_theme]['description'] = $txt['theme_description'];
        // Set the name, keep it short so it does not break our list
        $available_themes[$id_theme]['name'] = preg_replace('~\\stheme$~i', '', $theme_data['name']);
        if (Util::strlen($available_themes[$id_theme]['name']) > 18) {
            $available_themes[$id_theme]['name'] = Util::substr($available_themes[$id_theme]['name'], 0, 18) . '&hellip;';
        }
    }
    $settings['images_url'] = $current_images_url;
    if ($guest_theme != 0) {
        $available_themes[-1] = $available_themes[$guest_theme];
    }
    $available_themes[-1]['id'] = -1;
    $available_themes[-1]['name'] = $txt['theme_forum_default'];
    $available_themes[-1]['selected'] = $current_theme == 0;
    $available_themes[-1]['description'] = $txt['theme_global_description'];
    ksort($available_themes);
    // Validate the selected theme id.
    if (!array_key_exists($current_theme, $available_themes)) {
        $current_theme = -1;
        $available_themes[-1]['selected'] = true;
    }
    if (!empty($_POST['sp_ts_submit']) && !empty($_POST['sp_ts_permanent']) && !empty($_POST['theme']) && isset($available_themes[$_POST['theme']]) && (!empty($modSettings['theme_allow']) || allowedTo('admin_forum'))) {
        updateMemberData($user_info['id'], array('id_theme' => $_POST['theme'] == -1 ? 0 : (int) $_POST['theme']));
    }
    echo '
								<form method="post" action="?" accept-charset="UTF-8">
									<div class="centertext">
										<select name="theme" onchange="sp_theme_select(this)">';
    foreach ($available_themes as $theme) {
        echo '
											<option value="', $theme['id'], '"', $theme['id'] == $current_theme ? ' selected="selected"' : '', '>', $theme['name'], '</option>';
    }
    echo '
										</select>
										<br /><br />
										<img src="', $available_themes[$current_theme]['thumbnail_href'], '" alt="', $available_themes[$current_theme]['name'], '" id="sp_ts_thumb" />
										<br /><br />
										<input type="checkbox" class="input_check" name="sp_ts_permanent" value="1" /> ', $txt['sp-theme_permanent'], '
										<br />
										<input type="submit" name="sp_ts_submit" value="', $txt['sp-theme_change'], '" class="button_submit" />
									</div>
								</form>';
    $javascript = '
		var sp_ts_thumbs = [];';
    foreach ($available_themes as $id => $theme_data) {
        $javascript .= '
		sp_ts_thumbs[' . $id . '] = "' . $theme_data['thumbnail_href'] . '";';
    }
    addInlineJavascript($javascript, true);
}
Ejemplo n.º 29
0
/**
 * Create the query for inserting a record in to the database.
 * This is the main logging function for logging and verbose levels.
 *
 * @param array $settings
 * @param array $package
 * @param string $key
 * @return string
 */
function bb2_insert($settings, $package, $key)
{
    global $user_info, $sc;
    // Logging not enabled
    if (!$settings['logging']) {
        return '';
    }
    // Clean the data that bb sent us
    $ip = bb2_db_escape($package['ip']);
    $date = (int) bb2_db_date();
    $request_method = bb2_db_escape($package['request_method']);
    $request_uri = bb2_db_escape($package['request_uri']);
    $server_protocol = bb2_db_escape($package['server_protocol']);
    $user_agent = bb2_db_escape($package['user_agent']);
    $member_id = (int) (!empty($user_info['id'])) ? $user_info['id'] : 0;
    $session = !empty($sc) ? (string) $sc : '';
    // Prepare the headers etc for db insertion
    // We are passed at least
    //	Host, User-Agent, Accept, Accept-Language, Accept-Encoding, DNT, Connection, Referer, Cookie, Authorization
    $headers = '';
    $length = 0;
    $skip = array('User-Agent', 'Accept-Encoding', 'DNT', 'X-Wap-Profile');
    foreach ($package['headers'] as $h => $v) {
        if (!in_array($h, $skip)) {
            // Make sure this header it will fit in the db, if not move on to the next
            // @todo increase the db space to 512 or convert to text?
            $check = $length + Util::strlen($h) + Util::strlen($v) + 2;
            if ($check < 255) {
                $headers .= bb2_db_escape($h . ': ' . $v . "\n");
                $length = $check;
            }
        }
    }
    $request_entity = '';
    if (!strcasecmp($request_method, "POST")) {
        foreach ($package['request_entity'] as $h => $v) {
            if (is_array($v)) {
                $v = bb2_multi_implode($v, ' | ');
            }
            $request_entity .= bb2_db_escape("{$h}: {$v}\n");
        }
        // Only such much space in this column, so brutally cut it
        // @todo in 1.1 improve logging or drop this?
        $request_entity = substr($request_entity, 0, 254);
    }
    // Add it
    return "INSERT INTO {db_prefix}log_badbehavior\n\t\t(`ip`, `date`, `request_method`, `request_uri`, `server_protocol`, `http_headers`, `user_agent`, `request_entity`, `valid`, `id_member`, `session`) VALUES\n\t\t('{$ip}', '{$date}', '{$request_method}', '{$request_uri}', '{$server_protocol}', '{$headers}', '{$user_agent}', '{$request_entity}', '{$key}', '{$member_id}' , '{$session}')";
}
Ejemplo n.º 30
0
/**
 * Dumps the database.
 * It writes all of the database to standard output.
 * It uses gzip compression if compress is set in the URL/post data.
 * It may possibly time out, and mess up badly if you were relying on it. :P
 * The data dumped depends on whether "struct" and "data" are passed.
 * It requires an administrator and the session hash by post.
 * It is called from ManageMaintenance.php.
 */
function DumpDatabase2()
{
    global $db_name, $scripturl, $context, $modSettings, $crlf, $smcFunc, $db_prefix, $db_show_debug;
    $db = database();
    // Administrators only!
    if (!allowedTo('admin_forum')) {
        fatal_lang_error('no_dump_database', 'critical');
    }
    // We don't need debug when dumping the database
    $modSettings['disableQueryCheck'] = true;
    $db_show_debug = false;
    // You can't dump nothing!
    // 	if (!isset($_REQUEST['struct']) && !isset($_REQUEST['data']))
    $_REQUEST['data'] = true;
    //$_REQUEST['struct'] = false;
    // checkSession('post');
    $smcFunc['db_table_sql'] = 'exp_db_table_sql';
    $smcFunc['db_insert_sql'] = 'exp_db_insert_sql';
    $smcFunc['db_escape_string'] = 'addslashes';
    // Attempt to stop from dying...
    @set_time_limit(600);
    $time_limit = ini_get('max_execution_time');
    $start_time = time();
    // @todo ... fail on not getting the requested memory?
    @set_time_limit(600);
    if (@ini_get('memory_limit') < 256) {
        @ini_set('memory_limit', '256M');
    }
    $memory_limit = @ini_get('memory_limit');
    $memory_limit = (empty($memory_limit) ? 4 : $memory_limit) * 1024 * 1024 / 4;
    $current_used_memory = 0;
    $db_backup = '';
    $output_function = 'un_compressed';
    @ob_end_clean();
    // Get rid of the gzipping alreading being done.
    if (!empty($modSettings['enableCompressedOutput'])) {
        @ob_end_clean();
    } elseif (ob_get_length() != 0) {
        ob_clean();
    }
    // Tell the client to save this file, even though it's text.
    header('Content-Type: ' . ($context['browser']['is_ie'] || $context['browser']['is_opera'] ? 'application/octetstream' : 'application/octet-stream'));
    header('Content-Encoding: none');
    // This time the extension should just be .sql.
    $extension = '.sql';
    // This should turn off the session URL parser.
    $scripturl = '';
    // Send the proper headers to let them download this file.
    header('Content-Disposition: filename="' . $db_name . '-' . (empty($_REQUEST['struct']) ? 'data' : (empty($_REQUEST['data']) ? 'structure' : 'complete')) . '_' . strftime('%Y-%m-%d') . $extension . '"');
    header('Cache-Control: private');
    header('Connection: close');
    // This makes things simpler when using it so very very often.
    $crlf = "\r\n";
    // SQL Dump Header.
    $db_chunks = '-- ==========================================================' . $crlf . '--' . $crlf . '-- Database dump of tables in `' . $db_name . '`' . $crlf . '-- ' . timeformat(time(), false) . $crlf . '--' . $crlf . '-- ==========================================================' . $crlf . $crlf;
    // Get all tables in the database....
    if (preg_match('~^`(.+?)`\\.(.+?)$~', $db_prefix, $match) != 0) {
        $db = strtr($match[1], array('`' => ''));
        $dbp = str_replace('_', '\\_', $match[2]);
    } else {
        $db = false;
        $dbp = $db_prefix;
    }
    // Dump each table.
    $tables = $db->list_tables(false, $db_prefix . '%');
    foreach ($tables as $tableName) {
        // Are we dumping the structures?
        if (isset($_REQUEST['struct'])) {
            $db_chunks .= $crlf . '--' . $crlf . '-- Table structure for table `' . $tableName . '`' . $crlf . '--' . $crlf . $crlf . $smcFunc['db_table_sql']($tableName) . ';' . $crlf;
        } else {
            // This is needed to speedup things later
            $smcFunc['db_table_sql']($tableName);
        }
        // How about the data?
        if (substr($tableName, -10) == 'log_errors') {
            continue;
        }
        $first_round = true;
        $close_table = false;
        // Are there any rows in this table?
        while ($get_rows = $smcFunc['db_insert_sql']($tableName, $first_round)) {
            if (empty($get_rows)) {
                break;
            }
            // Time is what we need here!
            if (function_exists('apache_reset_timeout')) {
                @apache_reset_timeout();
            } elseif (!empty($time_limit) && $start_time + $time_limit - 20 > time()) {
                $start_time = time();
                @set_time_limit(150);
            }
            if ($first_round) {
                $db_chunks .= $crlf . '--' . $crlf . '-- Dumping data in `' . $tableName . '`' . $crlf . '--' . $crlf . $crlf;
                $first_round = false;
            }
            $db_chunks .= $get_rows;
            $current_used_memory += Util::strlen($db_chunks);
            $db_backup .= $db_chunks;
            unset($db_chunks);
            $db_chunks = '';
            if ($current_used_memory > $memory_limit) {
                echo $output_function($db_backup);
                $current_used_memory = 0;
                // This is probably redundant
                unset($db_backup);
                $db_backup = '';
            }
            $close_table = true;
        }
        // No rows to get - skip it.
        if ($close_table) {
            $db_backup .= '-- --------------------------------------------------------' . $crlf;
        }
    }
    $db_backup .= $crlf . '-- Done' . $crlf;
    echo $output_function($db_backup);
    exit;
}