Ejemplo n.º 1
0
 public static function boardindex()
 {
     global $context, $txt, $sourcedir, $user_info;
     $data = array();
     if (($data = CacheAPI::getCache('github-feed-index', 1800)) === null) {
         $f = curl_init();
         if ($f) {
             curl_setopt_array($f, array(CURLOPT_URL => self::$my_git_api_url, CURLOPT_HEADER => false, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false));
             $json_response = curl_exec($f);
             $data = json_decode($json_response, true);
             CacheAPI::putCache('github-feed-index', $data, 1800);
             curl_close($f);
         }
     }
     $n = 0;
     foreach ($data as $commit) {
         if (is_array($commit) && isset($commit['commit'])) {
             $context['gitfeed'][] = array('message_short' => shorten_subject($commit['commit']['message'], 60), 'message' => nl2br($commit['commit']['message']), 'dateline' => timeformat(strtotime($commit['commit']['committer']['date'])), 'sha' => $commit['sha'], 'href' => self::$my_git_url . 'commit/' . $commit['sha']);
         }
         if (++$n > 5) {
             break;
         }
     }
     if (!empty($data)) {
         /* 
          * add our plugin directory to the list of directories to search for templates
          * and register the template hook.
          * only do this if we actually have something to display
          */
         EoS_Smarty::addTemplateDir(dirname(__FILE__));
         EoS_Smarty::getConfigInstance()->registerHookTemplate('sidebar_below_userblock', 'gitfeed_sidebar_top');
         $context['gitfeed_global']['see_all']['href'] = self::$my_git_url . 'commits/master';
         $context['gitfeed_global']['see_all']['txt'] = 'Browse all commits';
     }
 }
Ejemplo n.º 2
0
function MaintainMassMoveTopics()
{
    global $sourcedir, $context, $txt;
    // Only admins.
    isAllowedTo('admin_forum');
    checkSession('request');
    // Set up to the context.
    $context['page_title'] = $txt['not_done_title'];
    $context['continue_countdown'] = '3';
    $context['continue_post_data'] = '';
    $context['continue_get_data'] = '';
    $context['sub_template'] = 'not_done';
    $context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'];
    $context['start_time'] = time();
    // First time we do this?
    $id_board_from = isset($_POST['id_board_from']) ? (int) $_POST['id_board_from'] : (int) $_REQUEST['id_board_from'];
    $id_board_to = isset($_POST['id_board_to']) ? (int) $_POST['id_board_to'] : (int) $_REQUEST['id_board_to'];
    // No boards then this is your stop.
    if (empty($id_board_from) || empty($id_board_to)) {
        return;
    }
    // How many topics are we converting?
    if (!isset($_REQUEST['totaltopics'])) {
        $request = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}topics
			WHERE id_board = {int:id_board_from}', array('id_board_from' => $id_board_from));
        list($total_topics) = mysql_fetch_row($request);
        mysql_free_result($request);
    } else {
        $total_topics = (int) $_REQUEST['totaltopics'];
    }
    // Seems like we need this here.
    $context['continue_get_data'] = '?action=admin;area=maintain;sa=topics;activity=massmove;id_board_from=' . $id_board_from . ';id_board_to=' . $id_board_to . ';totaltopics=' . $total_topics . ';start=' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id'];
    // We have topics to move so start the process.
    if (!empty($total_topics)) {
        while ($context['start'] <= $total_topics) {
            // Lets get the topics.
            $request = smf_db_query('
				SELECT id_topic
				FROM {db_prefix}topics
				WHERE id_board = {int:id_board_from}
				LIMIT 10', array('id_board_from' => $id_board_from));
            // Get the ids.
            $topics = array();
            while ($row = mysql_fetch_assoc($request)) {
                $topics[] = $row['id_topic'];
            }
            // Just return if we don't have any topics left to move.
            if (empty($topics)) {
                CacheAPI::putCache('board-' . $id_board_from, null, 120);
                CacheAPI::putCache('board-' . $id_board_to, null, 120);
                redirectexit('action=admin;area=maintain;sa=topics;done=massmove');
            }
            // Lets move them.
            require_once $sourcedir . '/MoveTopic.php';
            moveTopics($topics, $id_board_to);
            // We've done at least ten more topics.
            $context['start'] += 10;
            // Lets wait a while.
            if (time() - $context['start_time'] > 3) {
                // What's the percent?
                $context['continue_percent'] = round(100 * ($context['start'] / $total_topics), 1);
                $context['continue_get_data'] = '?action=admin;area=maintain;sa=topics;activity=massmove;id_board_from=' . $id_board_from . ';id_board_to=' . $id_board_to . ';totaltopics=' . $total_topics . ';start=' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id'];
                // Let the template system do it's thang.
                return;
            }
        }
    }
    // Don't confuse admins by having an out of date cache.
    CacheAPI::putCache('board-' . $id_board_from, null, 120);
    CacheAPI::putCache('board-' . $id_board_to, null, 120);
    redirectexit('action=admin;area=maintain;sa=topics;done=massmove');
}
Ejemplo n.º 3
0
function cache_get_data($key, $ttl = 120)
{
    return CacheAPI::getCache($key, $ttl);
}
Ejemplo n.º 4
0
function modifyPost(&$msgOptions, &$topicOptions, &$posterOptions)
{
    global $user_info, $modSettings, $context, $sourcedir;
    $topicOptions['poll'] = isset($topicOptions['poll']) ? (int) $topicOptions['poll'] : null;
    $topicOptions['lock_mode'] = isset($topicOptions['lock_mode']) ? $topicOptions['lock_mode'] : null;
    $topicOptions['sticky_mode'] = isset($topicOptions['sticky_mode']) ? $topicOptions['sticky_mode'] : null;
    $tagged_users = array();
    $context['can_tag_users'] = allowedTo('tag_users');
    if (isset($msgOptions['body'])) {
        $tagged_users = handleUserTags($msgOptions['body']);
    }
    // This is longer than it has to be, but makes it so we only set/change what we have to.
    $messages_columns = array();
    if (isset($posterOptions['name'])) {
        $messages_columns['poster_name'] = $posterOptions['name'];
    }
    if (isset($posterOptions['email'])) {
        $messages_columns['poster_email'] = $posterOptions['email'];
    }
    if (isset($msgOptions['icon'])) {
        $messages_columns['icon'] = $msgOptions['icon'];
    }
    if (isset($msgOptions['subject'])) {
        $messages_columns['subject'] = $msgOptions['subject'];
    }
    if (isset($msgOptions['body'])) {
        $messages_columns['body'] = $msgOptions['body'];
        if (!empty($modSettings['search_custom_index_config'])) {
            $request = smf_db_query('
				SELECT body, smileys_enabled
				FROM {db_prefix}messages
				WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id']));
            list($old_body, $old_smileys_enabled) = mysql_fetch_row($request);
            mysql_free_result($request);
        }
    }
    if (isset($msgOptions['locked'])) {
        $messages_columns['locked'] = $msgOptions['locked'];
    }
    if (!empty($msgOptions['modify_time'])) {
        $messages_columns['modified_time'] = $msgOptions['modify_time'];
        $messages_columns['modified_name'] = $msgOptions['modify_name'];
        $messages_columns['id_msg_modified'] = $modSettings['maxMsgID'];
    }
    if (isset($msgOptions['smileys_enabled'])) {
        $messages_columns['smileys_enabled'] = empty($msgOptions['smileys_enabled']) ? 0 : 1;
        $smileys_enabled = $msgOptions['smileys_enabled'];
    } else {
        if (isset($msgOptions['body'])) {
            $smileys_enabled = $old_smileys_enabled;
        }
    }
    // Which columns need to be ints?
    $messageInts = array('modified_time', 'id_msg_modified', 'smileys_enabled');
    $update_parameters = array('id_msg' => $msgOptions['id']);
    foreach ($messages_columns as $var => $val) {
        $messages_columns[$var] = $var . ' = {' . (in_array($var, $messageInts) ? 'int' : 'string') . ':var_' . $var . '}';
        $update_parameters['var_' . $var] = $val;
    }
    // Nothing to do?
    if (empty($messages_columns)) {
        return true;
    }
    // Change the post.
    smf_db_query('
		UPDATE {db_prefix}messages
		SET ' . implode(', ', $messages_columns) . '
		WHERE id_msg = {int:id_msg}', $update_parameters);
    /*
     * delete cached posts (they will update at the next view)
     */
    if (isset($msgOptions['body'])) {
        smf_db_query('DELETE FROM {db_prefix}messages_cache WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id']));
        CacheAPI::clearCacheByPrefix('parse:' . trim($msgOptions['id']) . '-');
    } else {
        $context['no_astream'] = true;
    }
    $context['no_astream'] = isset($context['no_astream']) ? $context['no_astream'] : 0;
    // Lock and or sticky the post.
    if ($topicOptions['sticky_mode'] !== null || $topicOptions['lock_mode'] !== null || $topicOptions['poll'] !== null) {
        smf_db_query('
			UPDATE {db_prefix}topics
			SET
				is_sticky = {raw:is_sticky},
				locked = {raw:locked},
				id_poll = {raw:id_poll}
			WHERE id_topic = {int:id_topic}', array('is_sticky' => $topicOptions['sticky_mode'] === null ? 'is_sticky' : (int) $topicOptions['sticky_mode'], 'locked' => $topicOptions['lock_mode'] === null ? 'locked' : (int) $topicOptions['lock_mode'], 'id_poll' => $topicOptions['poll'] === null ? 'id_poll' : (int) $topicOptions['poll'], 'id_topic' => $topicOptions['id']));
    }
    if (isset($topicOptions['id_first_msg']) && $msgOptions['id'] == $topicOptions['id_first_msg']) {
        if (isset($topicOptions['topic_prefix'])) {
            smf_db_query('
				UPDATE {db_prefix}topics
				SET
					id_prefix = {int:id_prefix}
				WHERE id_topic = {int:id_topic}', array('id_prefix' => $topicOptions['topic_prefix'], 'id_topic' => $topicOptions['id']));
        }
        if (isset($topicOptions['topic_layout'])) {
            smf_db_query('
				UPDATE {db_prefix}topics
				SET
					id_layout = {int:id_layout}
				WHERE id_topic = {int:id_topic}', array('id_layout' => $topicOptions['topic_layout'], 'id_topic' => $topicOptions['id']));
        }
    }
    // Mark the edited post as read.
    if (!empty($topicOptions['mark_as_read']) && !$user_info['is_guest']) {
        // Since it's likely they *read* it before editing, let's try an UPDATE first.
        smf_db_query('
			UPDATE {db_prefix}log_topics
			SET id_msg = {int:id_msg}
			WHERE id_member = {int:current_member}
				AND id_topic = {int:id_topic}', array('current_member' => $user_info['id'], 'id_msg' => $modSettings['maxMsgID'], 'id_topic' => $topicOptions['id']));
        $flag = smf_db_affected_rows() != 0;
        if (empty($flag)) {
            smf_db_insert('ignore', '{db_prefix}log_topics', array('id_topic' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($topicOptions['id'], $user_info['id'], $modSettings['maxMsgID']), array('id_topic', 'id_member'));
        }
    }
    if (count($tagged_users) > 0) {
        notifyTaggedUsers($tagged_users, array('id_topic' => $topicOptions['id'], 'id_message' => $msgOptions['id']));
    }
    // If there's a custom search index, it needs to be modified...
    if (isset($msgOptions['body']) && !empty($modSettings['search_custom_index_config'])) {
        $customIndexSettings = unserialize($modSettings['search_custom_index_config']);
        $stopwords = empty($modSettings['search_stopwords']) ? array() : explode(',', $modSettings['search_stopwords']);
        $old_index = text2words($old_body, $customIndexSettings['bytes_per_word'], true);
        $new_index = text2words($msgOptions['body'], $customIndexSettings['bytes_per_word'], true);
        // Calculate the words to be added and removed from the index.
        $removed_words = array_diff(array_diff($old_index, $new_index), $stopwords);
        $inserted_words = array_diff(array_diff($new_index, $old_index), $stopwords);
        // Delete the removed words AND the added ones to avoid key constraints.
        if (!empty($removed_words)) {
            $removed_words = array_merge($removed_words, $inserted_words);
            smf_db_query('
				DELETE FROM {db_prefix}log_search_words
				WHERE id_msg = {int:id_msg}
					AND id_word IN ({array_int:removed_words})', array('removed_words' => $removed_words, 'id_msg' => $msgOptions['id']));
        }
        // Add the new words to be indexed.
        if (!empty($inserted_words)) {
            $inserts = array();
            foreach ($inserted_words as $word) {
                $inserts[] = array($word, $msgOptions['id']);
            }
            smf_db_insert('insert', '{db_prefix}log_search_words', array('id_word' => 'string', 'id_msg' => 'int'), $inserts, array('id_word', 'id_msg'));
        }
    }
    if (isset($msgOptions['subject'])) {
        // Only update the subject if this was the first message in the topic.
        $request = smf_db_query('
			SELECT id_topic
			FROM {db_prefix}topics
			WHERE id_first_msg = {int:id_first_msg}
			LIMIT 1', array('id_first_msg' => $msgOptions['id']));
        if (mysql_num_rows($request) == 1) {
            updateStats('subject', $topicOptions['id'], $msgOptions['subject']);
            // Added by Related Topics
            if (isset($modSettings['have_related_topics']) && $modSettings['have_related_topics']) {
                require_once $sourcedir . '/lib/Subs-Related.php';
                relatedUpdateTopics($topicOptions['id']);
            }
            // Related Topics END
        }
        mysql_free_result($request);
    }
    // Finally, if we are setting the approved state we need to do much more work :(
    if ($modSettings['postmod_active'] && isset($msgOptions['approved'])) {
        approvePosts($msgOptions['id'], $msgOptions['approved']);
    }
    // record in activity stream
    if ($modSettings['astream_active'] && !$context['no_astream']) {
        require_once $sourcedir . '/lib/Subs-Activities.php';
        aStreamAdd($user_info['id'], ACT_MODIFY_POST, array('member_name' => $user_info['name'], 'topic_title' => $msgOptions['subject']), $topicOptions['board'], $topicOptions['id'], $msgOptions['id'], $msgOptions['id_owner']);
    }
    return true;
}
Ejemplo n.º 5
0
function smf_db_error($db_string, $connection = null)
{
    global $txt, $context, $sourcedir, $webmaster_email, $modSettings;
    global $forum_version, $db_connection, $db_last_error, $db_persist;
    global $db_server, $db_user, $db_passwd, $db_name, $db_show_debug, $ssi_db_user, $ssi_db_passwd;
    // Get the file and line numbers.
    list($file, $line) = smf_db_error_backtrace('', '', 'return', __FILE__, __LINE__);
    // Decide which connection to use
    $connection = $connection == null ? $db_connection : $connection;
    // This is the error message...
    $query_error = mysql_error($connection);
    $query_errno = mysql_errno($connection);
    // Error numbers:
    //    1016: Can't open file '....MYI'
    //    1030: Got error ??? from table handler.
    //    1034: Incorrect key file for table.
    //    1035: Old key file for table.
    //    1205: Lock wait timeout exceeded.
    //    1213: Deadlock found.
    //    2006: Server has gone away.
    //    2013: Lost connection to server during query.
    // Log the error.
    if ($query_errno != 1213 && $query_errno != 1205 && function_exists('log_error')) {
        log_error($txt['database_error'] . ': ' . $query_error . (!empty($modSettings['enableErrorQueryLogging']) ? "\n\n{$db_string}" : ''), 'database', $file, $line);
    }
    // Database error auto fixing ;).
    if (function_exists('cache_get_data') && (!isset($modSettings['autoFixDatabase']) || $modSettings['autoFixDatabase'] == '1')) {
        // Force caching on, just for the error checking.
        $old_cache = @$modSettings['cache_enable'];
        $modSettings['cache_enable'] = '1';
        if (($temp = CacheAPI::getCache('db_last_error', 600)) !== null) {
            $db_last_error = max(@$db_last_error, $temp);
        }
        if (@$db_last_error < time() - 3600 * 24 * 3) {
            // We know there's a problem... but what?  Try to auto detect.
            if ($query_errno == 1030 && strpos($query_error, ' 127 ') !== false) {
                preg_match_all('~(?:[\\n\\r]|^)[^\']+?(?:FROM|JOIN|UPDATE|TABLE) ((?:[^\\n\\r(]+?(?:, )?)*)~s', $db_string, $matches);
                $fix_tables = array();
                foreach ($matches[1] as $tables) {
                    $tables = array_unique(explode(',', $tables));
                    foreach ($tables as $table) {
                        // Now, it's still theoretically possible this could be an injection.  So backtick it!
                        if (trim($table) != '') {
                            $fix_tables[] = '`' . strtr(trim($table), array('`' => '')) . '`';
                        }
                    }
                }
                $fix_tables = array_unique($fix_tables);
            } elseif ($query_errno == 1016) {
                if (preg_match('~\'([^\\.\']+)~', $query_error, $match) != 0) {
                    $fix_tables = array('`' . $match[1] . '`');
                }
            } elseif ($query_errno == 1034 || $query_errno == 1035) {
                preg_match('~\'([^\']+?)\'~', $query_error, $match);
                $fix_tables = array('`' . $match[1] . '`');
            }
        }
        // Check for errors like 145... only fix it once every three days, and send an email. (can't use empty because it might not be set yet...)
        if (!empty($fix_tables)) {
            // Subs-Admin.php for updateSettingsFile(), Subs-Post.php for sendmail().
            require_once $sourcedir . '/lib/Subs-Admin.php';
            require_once $sourcedir . '/lib/Subs-Post.php';
            // Make a note of the REPAIR...
            CacheAPI::putCache('db_last_error', time(), 600);
            if (($temp = CacheAPI::getCache('db_last_error', 600)) === null) {
                updateSettingsFile(array('db_last_error' => time()));
            }
            // Attempt to find and repair the broken table.
            foreach ($fix_tables as $table) {
                smf_db_query("\n\t\t\t\t\tREPAIR TABLE {$table}", false, false);
            }
            // And send off an email!
            sendmail($webmaster_email, $txt['database_error'], $txt['tried_to_repair']);
            $modSettings['cache_enable'] = $old_cache;
            // Try the query again...?
            $ret = smf_db_query($db_string, false, false);
            if ($ret !== false) {
                return $ret;
            }
        } else {
            $modSettings['cache_enable'] = $old_cache;
        }
        // Check for the "lost connection" or "deadlock found" errors - and try it just one more time.
        if (in_array($query_errno, array(1205, 1213, 2006, 2013))) {
            if (in_array($query_errno, array(2006, 2013)) && $db_connection == $connection) {
                // Are we in SSI mode?  If so try that username and password first
                if (SMF == 'SSI' && !empty($ssi_db_user) && !empty($ssi_db_passwd)) {
                    if (empty($db_persist)) {
                        $db_connection = @mysql_connect($db_server, $ssi_db_user, $ssi_db_passwd);
                    } else {
                        $db_connection = @mysql_pconnect($db_server, $ssi_db_user, $ssi_db_passwd);
                    }
                }
                // Fall back to the regular username and password if need be
                if (!$db_connection) {
                    if (empty($db_persist)) {
                        $db_connection = @mysql_connect($db_server, $db_user, $db_passwd);
                    } else {
                        $db_connection = @mysql_pconnect($db_server, $db_user, $db_passwd);
                    }
                }
                if (!$db_connection || !@mysql_select_db($db_name, $db_connection)) {
                    $db_connection = false;
                }
            }
            if ($db_connection) {
                // Try a deadlock more than once more.
                for ($n = 0; $n < 4; $n++) {
                    $ret = smf_db_query($db_string, false, false);
                    $new_errno = mysql_errno($db_connection);
                    if ($ret !== false || in_array($new_errno, array(1205, 1213))) {
                        break;
                    }
                }
                // If it failed again, shucks to be you... we're not trying it over and over.
                if ($ret !== false) {
                    return $ret;
                }
            }
        } elseif ($query_errno == 1030 && (strpos($query_error, ' -1 ') !== false || strpos($query_error, ' 28 ') !== false || strpos($query_error, ' 12 ') !== false)) {
            if (!isset($txt)) {
                $query_error .= ' - check database storage space.';
            } else {
                if (!isset($txt['mysql_error_space'])) {
                    loadLanguage('Errors');
                }
                $query_error .= !isset($txt['mysql_error_space']) ? ' - check database storage space.' : $txt['mysql_error_space'];
            }
        }
    }
    // Nothing's defined yet... just die with it.
    if (empty($context) || empty($txt)) {
        die($query_error);
    }
    // Show an error message, if possible.
    $context['error_title'] = $txt['database_error'];
    if (allowedTo('admin_forum')) {
        $context['error_message'] = nl2br($query_error) . '<br />' . $txt['file'] . ': ' . $file . '<br />' . $txt['line'] . ': ' . $line;
    } else {
        $context['error_message'] = $txt['try_again'];
    }
    // A database error is often the sign of a database in need of upgrade.  Check forum versions, and if not identical suggest an upgrade... (not for Demo/CVS versions!)
    if (allowedTo('admin_forum') && !empty($forum_version) && $forum_version != 'SMF ' . @$modSettings['smfVersion'] && strpos($forum_version, 'Demo') === false && strpos($forum_version, 'CVS') === false) {
        $context['error_message'] .= '<br /><br />' . sprintf($txt['database_error_versions'], $forum_version, $modSettings['smfVersion']);
    }
    if (allowedTo('admin_forum') && isset($db_show_debug) && $db_show_debug === true) {
        $context['error_message'] .= '<br /><br />' . nl2br($db_string);
    }
    // It's already been logged... don't log it again.
    fatal_error($context['error_message'], false);
}
Ejemplo n.º 6
0
function ShowXmlFeed()
{
    global $board, $board_info, $context, $scripturl, $txt, $modSettings, $user_info;
    global $query_this_board, $smcFunc, $forum_version, $cdata_override;
    // If it's not enabled, die.
    if (empty($modSettings['xmlnews_enable'])) {
        obExit(false);
    }
    loadLanguage('Stats');
    // Default to latest 5.  No more than 255, please.
    $_GET['limit'] = empty($_GET['limit']) || (int) $_GET['limit'] < 1 ? 5 : min((int) $_GET['limit'], 255);
    // Handle the cases where a board, boards, or category is asked for.
    $query_this_board = 1;
    $context['optimize_msg'] = array('highest' => 'm.id_msg <= b.id_last_msg');
    if (!empty($_REQUEST['c']) && empty($board)) {
        $_REQUEST['c'] = explode(',', $_REQUEST['c']);
        foreach ($_REQUEST['c'] as $i => $c) {
            $_REQUEST['c'][$i] = (int) $c;
        }
        if (count($_REQUEST['c']) == 1) {
            $request = smf_db_query('
				SELECT name
				FROM {db_prefix}categories
				WHERE id_cat = {int:current_category}', array('current_category' => (int) $_REQUEST['c'][0]));
            list($feed_title) = mysql_fetch_row($request);
            mysql_free_result($request);
            $feed_title = ' - ' . strip_tags($feed_title);
        }
        $request = smf_db_query('
			SELECT b.id_board, b.num_posts
			FROM {db_prefix}boards AS b
			WHERE b.id_cat IN ({array_int:current_category_list})
				AND {query_see_board}', array('current_category_list' => $_REQUEST['c']));
        $total_cat_posts = 0;
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            $boards[] = $row['id_board'];
            $total_cat_posts += $row['num_posts'];
        }
        mysql_free_result($request);
        if (!empty($boards)) {
            $query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')';
        }
        // Try to limit the number of messages we look through.
        if ($total_cat_posts > 100 && $total_cat_posts > $modSettings['totalMessages'] / 15) {
            $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 400 - $_GET['limit'] * 5);
        }
    } elseif (!empty($_REQUEST['boards'])) {
        $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
        foreach ($_REQUEST['boards'] as $i => $b) {
            $_REQUEST['boards'][$i] = (int) $b;
        }
        $request = smf_db_query('
			SELECT b.id_board, b.num_posts, b.name
			FROM {db_prefix}boards AS b
			WHERE b.id_board IN ({array_int:board_list})
				AND {query_see_board}
			LIMIT ' . count($_REQUEST['boards']), array('board_list' => $_REQUEST['boards']));
        // Either the board specified doesn't exist or you have no access.
        $num_boards = mysql_num_rows($request);
        if ($num_boards == 0) {
            fatal_lang_error('no_board');
        }
        $total_posts = 0;
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            if ($num_boards == 1) {
                $feed_title = ' - ' . strip_tags($row['name']);
            }
            $boards[] = $row['id_board'];
            $total_posts += $row['num_posts'];
        }
        mysql_free_result($request);
        if (!empty($boards)) {
            $query_this_board = 'b.id_board IN (' . implode(', ', $boards) . ')';
        }
        // The more boards, the more we're going to look through...
        if ($total_posts > 100 && $total_posts > $modSettings['totalMessages'] / 12) {
            $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 500 - $_GET['limit'] * 5);
        }
    } elseif (!empty($board)) {
        $request = smf_db_query('
			SELECT num_posts
			FROM {db_prefix}boards
			WHERE id_board = {int:current_board}
			LIMIT 1', array('current_board' => $board));
        list($total_posts) = mysql_fetch_row($request);
        mysql_free_result($request);
        $feed_title = ' - ' . strip_tags($board_info['name']);
        $query_this_board = 'b.id_board = ' . $board;
        // Try to look through just a few messages, if at all possible.
        if ($total_posts > 80 && $total_posts > $modSettings['totalMessages'] / 10) {
            $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 600 - $_GET['limit'] * 5);
        }
    } else {
        $query_this_board = '{query_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
			AND b.id_board != ' . $modSettings['recycle_board'] : '');
        $context['optimize_msg']['lowest'] = 'm.id_msg >= ' . max(0, $modSettings['maxMsgID'] - 100 - $_GET['limit'] * 5);
    }
    // Show in rss or proprietary format?
    $xml_format = isset($_GET['type']) && in_array($_GET['type'], array('smf', 'rss', 'rss2', 'atom', 'rdf', 'webslice')) ? $_GET['type'] : 'smf';
    // !!! Birthdays?
    // List all the different types of data they can pull.
    $subActions = array('recent' => array('getXmlRecent', 'recent-post'), 'news' => array('getXmlNews', 'article'), 'members' => array('getXmlMembers', 'member'), 'profile' => array('getXmlProfile', null));
    if (empty($_GET['sa']) || !isset($subActions[$_GET['sa']])) {
        $_GET['sa'] = 'recent';
    }
    //!!! Temp - webslices doesn't do everything yet.
    if ($xml_format == 'webslice' && $_GET['sa'] != 'recent') {
        $xml_format = 'rss2';
    } elseif ($xml_format == 'webslice') {
        $context['user'] += $user_info;
        $cdata_override = true;
        loadTemplate('Xml');
    }
    // We only want some information, not all of it.
    $cachekey = array($xml_format, $_GET['action'], $_GET['limit'], $_GET['sa']);
    foreach (array('board', 'boards', 'c') as $var) {
        if (isset($_REQUEST[$var])) {
            $cachekey[] = $_REQUEST[$var];
        }
    }
    $cachekey = md5(serialize($cachekey) . (!empty($query_this_board) ? $query_this_board : ''));
    $cache_t = microtime();
    // Get the associative array representing the xml.
    if (!empty($modSettings['cache_enable']) && (!$user_info['is_guest'] || $modSettings['cache_enable'] >= 3)) {
        $xml = CacheAPI::getCache('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, 240);
    }
    if (empty($xml)) {
        $xml = $subActions[$_GET['sa']][0]($xml_format);
        if (!empty($modSettings['cache_enable']) && ($user_info['is_guest'] && $modSettings['cache_enable'] >= 3 || !$user_info['is_guest'] && array_sum(explode(' ', microtime())) - array_sum(explode(' ', $cache_t)) > 0.2)) {
            CacheAPI::putCache('xmlfeed-' . $xml_format . ':' . ($user_info['is_guest'] ? '' : $user_info['id'] . '-') . $cachekey, $xml, 240);
        }
    }
    $feed_title = htmlspecialchars(strip_tags($context['forum_name'])) . (isset($feed_title) ? $feed_title : '');
    // This is an xml file....
    ob_end_clean();
    if (!empty($modSettings['enableCompressedOutput'])) {
        @ob_start('ob_gzhandler');
    } else {
        ob_start();
    }
    if ($xml_format == 'smf' || isset($_REQUEST['debug'])) {
        header('Content-Type: text/xml; charset=UTF-8');
    } elseif ($xml_format == 'rss' || $xml_format == 'rss2' || $xml_format == 'webslice') {
        header('Content-Type: application/rss+xml; charset=UTF-8');
    } elseif ($xml_format == 'atom') {
        header('Content-Type: application/atom+xml; charset=UTF-8');
    } elseif ($xml_format == 'rdf') {
        header('Content-Type: ' . ($context['browser']['is_ie'] ? 'text/xml' : 'application/rdf+xml') . '; charset=UTF-8');
    }
    // First, output the xml header.
    echo '<?xml version="1.0" encoding="UTF-8"?' . '>';
    // Are we outputting an rss feed or one with more information?
    if ($xml_format == 'rss' || $xml_format == 'rss2') {
        // Start with an RSS 2.0 header.
        echo '
<rss version=', $xml_format == 'rss2' ? '"2.0"' : '"0.92"', ' xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">
	<channel>
		<title>', $feed_title, '</title>
		<link>', $scripturl, '</link>
		<description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>';
        // Output all of the associative array, start indenting with 2 tabs, and name everything "item".
        dumpTags($xml, 2, 'item', $xml_format);
        // Output the footer of the xml.
        echo '
	</channel>
</rss>';
    } elseif ($xml_format == 'webslice') {
        $context['recent_posts_data'] = $xml;
        // This always has RSS 2
        echo '
<rss version="2.0" xmlns:mon="http://www.microsoft.com/schemas/rss/monitoring/2007" xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">
	<channel>
		<title>', $feed_title, ' - ', $txt['recent_posts'], '</title>
		<link>', $scripturl, '?action=recent</link>
		<description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>
		<item>
			<title>', $feed_title, ' - ', $txt['recent_posts'], '</title>
			<link>', $scripturl, '?action=recent</link>
			<description><![CDATA[
				', template_webslice_header_above(), '
				', template_webslice_recent_posts(), '
				', template_webslice_header_below(), '
			]]></description>
		</item>
	</channel>
</rss>';
    } elseif ($xml_format == 'atom') {
        echo '
<feed xmlns="http://www.w3.org/2005/Atom">
	<title>', $feed_title, '</title>
	<link rel="alternate" type="text/html" href="', $scripturl, '" />

	<modified>', gmstrftime('%Y-%m-%dT%H:%M:%SZ'), '</modified>
	<tagline><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></tagline>
	<generator uri="http://www.simplemachines.org" version="', strtr($forum_version, array('SMF' => '')), '">SMF</generator>
	<author>
		<name>', strip_tags($context['forum_name']), '</name>
	</author>';
        dumpTags($xml, 2, 'entry', $xml_format);
        echo '
</feed>';
    } elseif ($xml_format == 'rdf') {
        echo '
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/">
	<channel rdf:about="', $scripturl, '">
		<title>', $feed_title, '</title>
		<link>', $scripturl, '</link>
		<description><![CDATA[', strip_tags($txt['xml_rss_desc']), ']]></description>
		<items>
			<rdf:Seq>';
        foreach ($xml as $item) {
            echo '
				<rdf:li rdf:resource="', $item['link'], '" />';
        }
        echo '
			</rdf:Seq>
		</items>
	</channel>
';
        dumpTags($xml, 1, 'item', $xml_format);
        echo '
</rdf:RDF>';
    } else {
        echo '
<smf:xml-feed xmlns:smf="http://www.simplemachines.org/" xmlns="http://www.simplemachines.org/xml/', $_GET['sa'], '" xml:lang="', strtr($txt['lang_locale'], '_', '-'), '">';
        // Dump out that associative array.  Indent properly.... and use the right names for the base elements.
        dumpTags($xml, 1, $subActions[$_GET['sa']][1], $xml_format);
        echo '
</smf:xml-feed>';
    }
    obExit(false);
}
Ejemplo n.º 7
0
function JavaScriptModify()
{
    global $sourcedir, $modSettings, $board, $topic, $txt;
    global $user_info, $context, $language;
    // We have to have a topic!
    if (empty($topic)) {
        obExit(false);
    }
    checkSession('get');
    require_once $sourcedir . '/lib/Subs-Post.php';
    // Assume the first message if no message ID was given.
    $request = smf_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, ba.id_topic AS banned_from_topic
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
				LEFT JOIN {db_prefix}topicbans AS ba ON (ba.id_topic = {int:current_topic} AND ba.id_member = {int:current_member})
			WHERE m.id_msg = {raw:id_msg}
				AND m.id_topic = {int:current_topic}' . (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 (mysql_num_rows($request) == 0) {
        fatal_lang_error('no_board', false);
    }
    $row = mysql_fetch_assoc($request);
    mysql_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');
        }
        // check topic bans
        if ($row['banned_from_topic'] != 0 && !$user_info['is_admin'] && !allowedTo('moderate_board') && !allowedTo('moderate_forum')) {
            fatal_lang_error('banned_from_topic');
        }
        // Only log this action if it wasn't your message.
        $moderationAction = $row['id_member'] != $user_info['id'];
    }
    $post_errors = array();
    if (isset($_POST['subject']) && commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['subject'])) !== '') {
        $_POST['subject'] = strtr(commonAPI::htmlspecialchars($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
        // Maximum number of characters.
        if (commonAPI::strlen($_POST['subject']) > 100) {
            $_POST['subject'] = commonAPI::substr($_POST['subject'], 0, 100);
        }
    } elseif (isset($_POST['subject'])) {
        $post_errors[] = 'no_subject';
        unset($_POST['subject']);
    }
    if (isset($_POST['message'])) {
        if (commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['message'])) === '') {
            $post_errors[] = 'no_message';
            unset($_POST['message']);
        } elseif (!empty($modSettings['max_messageLength']) && commonAPI::strlen($_POST['message']) > $modSettings['max_messageLength']) {
            $post_errors[] = 'long_message';
            unset($_POST['message']);
        } else {
            $_POST['message'] = commonAPI::htmlspecialchars($_POST['message'], ENT_QUOTES);
            preparsecode($_POST['message']);
            if (commonAPI::htmltrim(strip_tags(parse_bbc($_POST['message'], false), '<img>')) === '') {
                $post_errors[] = '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 (empty($post_errors)) {
        $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, 'id_owner' => $row['id_member']);
        $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' => true);
        $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.
            if (!isset($context['response_prefix']) && !($context['response_prefix'] = CacheAPI::getCache('response_prefix'))) {
                if ($language === $user_info['language']) {
                    $context['response_prefix'] = $txt['response_prefix'];
                } else {
                    loadLanguage('index', $language, false);
                    $context['response_prefix'] = $txt['response_prefix'];
                    loadLanguage('index');
                }
                CacheAPI::putCache('response_prefix', $context['response_prefix'], 600);
            }
            smf_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 (empty($post_errors) && isset($msgOptions['subject']) && isset($msgOptions['body'])) {
            $context['message'] = array('id' => $row['id_msg'], 'modified' => array('time' => isset($msgOptions['modify_time']) ? timeformat($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']);
            $cache_key = isset($msgOptions['modify_time']) ? $row['id_msg'] . '|' . $msgOptions['modify_time'] : $row['id_msg'];
            $context['message']['body'] = parse_bbc($context['message']['body'], $row['smileys_enabled'], $cache_key);
            parse_bbc_stage2($context['message']['body']);
        } elseif (empty($post_errors)) {
            $context['sub_template'] = 'modifytopicdone';
            $context['message'] = array('id' => $row['id_msg'], 'icon' => isset($_REQUEST['icon']) ? $_REQUEST['icon'] : '', 'modified' => array('time' => isset($msgOptions['modify_time']) ? timeformat($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' => in_array('no_subject', $post_errors), 'error_in_body' => in_array('no_message', $post_errors) || in_array('long_message', $post_errors));
            loadLanguage('Errors');
            foreach ($post_errors as $post_error) {
                if ($post_error == 'long_message') {
                    $context['message']['errors'][] = sprintf($txt['error_' . $post_error], $modSettings['max_messageLength']);
                } else {
                    $context['message']['errors'][] = $txt['error_' . $post_error];
                }
            }
        }
    } else {
        obExit(false);
    }
}
Ejemplo n.º 8
0
function moveTopics($topics, $toBoard)
{
    global $sourcedir, $user_info, $modSettings, $smcFunc;
    // Empty array?
    if (empty($topics)) {
        return;
    } elseif (is_numeric($topics)) {
        $topics = array($topics);
    }
    $num_topics = count($topics);
    $fromBoards = array();
    // Destination board empty or equal to 0?
    if (empty($toBoard)) {
        return;
    }
    // Are we moving to the recycle board?
    $isRecycleDest = !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $toBoard;
    // Determine the source boards...
    $request = smf_db_query('
		SELECT id_board, approved, COUNT(*) AS num_topics, SUM(unapproved_posts) AS unapproved_posts,
			SUM(num_replies) AS num_replies
		FROM {db_prefix}topics
		WHERE id_topic IN ({array_int:topics})
		GROUP BY id_board, approved', array('topics' => $topics));
    // Num of rows = 0 -> no topics found. Num of rows > 1 -> topics are on multiple boards.
    if (mysql_num_rows($request) == 0) {
        return;
    }
    while ($row = mysql_fetch_assoc($request)) {
        if (!isset($fromBoards[$row['id_board']]['num_posts'])) {
            $fromBoards[$row['id_board']] = array('num_posts' => 0, 'num_topics' => 0, 'unapproved_posts' => 0, 'unapproved_topics' => 0, 'id_board' => $row['id_board']);
        }
        // Posts = (num_replies + 1) for each approved topic.
        $fromBoards[$row['id_board']]['num_posts'] += $row['num_replies'] + ($row['approved'] ? $row['num_topics'] : 0);
        $fromBoards[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts'];
        // Add the topics to the right type.
        if ($row['approved']) {
            $fromBoards[$row['id_board']]['num_topics'] += $row['num_topics'];
        } else {
            $fromBoards[$row['id_board']]['unapproved_topics'] += $row['num_topics'];
        }
    }
    mysql_free_result($request);
    // Move over the mark_read data. (because it may be read and now not by some!)
    $SaveAServer = max(0, $modSettings['maxMsgID'] - 50000);
    $request = smf_db_query('
		SELECT lmr.id_member, lmr.id_msg, t.id_topic
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = t.id_board
				AND lmr.id_msg > t.id_first_msg AND lmr.id_msg > {int:protect_lmr_msg})
			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = lmr.id_member)
		WHERE t.id_topic IN ({array_int:topics})
			AND lmr.id_msg > IFNULL(lt.id_msg, 0)', array('protect_lmr_msg' => $SaveAServer, 'topics' => $topics));
    $log_topics = array();
    while ($row = mysql_fetch_assoc($request)) {
        $log_topics[] = array($row['id_topic'], $row['id_member'], $row['id_msg']);
        // Prevent queries from getting too big. Taking some steam off.
        if (count($log_topics) > 500) {
            smf_db_insert('replace', '{db_prefix}log_topics', array('id_topic' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), $log_topics, array('id_topic', 'id_member'));
            $log_topics = array();
        }
    }
    mysql_free_result($request);
    // Now that we have all the topics that *should* be marked read, and by which members...
    if (!empty($log_topics)) {
        // Insert that information into the database!
        smf_db_insert('replace', '{db_prefix}log_topics', array('id_topic' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), $log_topics, array('id_topic', 'id_member'));
    }
    // Update the number of posts on each board.
    $totalTopics = 0;
    $totalPosts = 0;
    $totalUnapprovedTopics = 0;
    $totalUnapprovedPosts = 0;
    foreach ($fromBoards as $stats) {
        smf_db_query('
			UPDATE {db_prefix}boards
			SET
				num_posts = CASE WHEN {int:num_posts} > num_posts THEN 0 ELSE num_posts - {int:num_posts} END,
				num_topics = CASE WHEN {int:num_topics} > num_topics THEN 0 ELSE num_topics - {int:num_topics} END,
				unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END,
				unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END
			WHERE id_board = {int:id_board}', array('id_board' => $stats['id_board'], 'num_posts' => $stats['num_posts'], 'num_topics' => $stats['num_topics'], 'unapproved_posts' => $stats['unapproved_posts'], 'unapproved_topics' => $stats['unapproved_topics']));
        $totalTopics += $stats['num_topics'];
        $totalPosts += $stats['num_posts'];
        $totalUnapprovedTopics += $stats['unapproved_topics'];
        $totalUnapprovedPosts += $stats['unapproved_posts'];
    }
    smf_db_query('
		UPDATE {db_prefix}boards
		SET
			num_topics = num_topics + {int:total_topics},
			num_posts = num_posts + {int:total_posts},' . ($isRecycleDest ? '
			unapproved_posts = {int:no_unapproved}, unapproved_topics = {int:no_unapproved}' : '
			unapproved_posts = unapproved_posts + {int:total_unapproved_posts},
			unapproved_topics = unapproved_topics + {int:total_unapproved_topics}') . '
		WHERE id_board = {int:id_board}', array('id_board' => $toBoard, 'total_topics' => $totalTopics, 'total_posts' => $totalPosts, 'total_unapproved_topics' => $totalUnapprovedTopics, 'total_unapproved_posts' => $totalUnapprovedPosts, 'no_unapproved' => 0));
    // Move the topic.  Done.  :P
    smf_db_query('
		UPDATE {db_prefix}topics
		SET id_board = {int:id_board}' . ($isRecycleDest ? ',
			unapproved_posts = {int:no_unapproved}, approved = {int:is_approved}' : '') . '
		WHERE id_topic IN ({array_int:topics})', array('id_board' => $toBoard, 'topics' => $topics, 'is_approved' => 1, 'no_unapproved' => 0));
    // If this was going to the recycle bin, check what messages are being recycled, and remove them from the queue.
    if ($isRecycleDest && ($totalUnapprovedTopics || $totalUnapprovedPosts)) {
        $request = smf_db_query('
			SELECT id_msg
			FROM {db_prefix}messages
			WHERE id_topic IN ({array_int:topics})
				and approved = {int:not_approved}', array('topics' => $topics, 'not_approved' => 0));
        $approval_msgs = array();
        while ($row = mysql_fetch_assoc($request)) {
            $approval_msgs[] = $row['id_msg'];
        }
        mysql_free_result($request);
        // Empty the approval queue for these, as we're going to approve them next.
        if (!empty($approval_msgs)) {
            smf_db_query('
				DELETE FROM {db_prefix}approval_queue
				WHERE id_msg IN ({array_int:message_list})
					AND id_attach = {int:id_attach}', array('message_list' => $approval_msgs, 'id_attach' => 0));
        }
        // Get all the current max and mins.
        $request = smf_db_query('
			SELECT id_topic, id_first_msg, id_last_msg
			FROM {db_prefix}topics
			WHERE id_topic IN ({array_int:topics})', array('topics' => $topics));
        $topicMaxMin = array();
        while ($row = mysql_fetch_assoc($request)) {
            $topicMaxMin[$row['id_topic']] = array('min' => $row['id_first_msg'], 'max' => $row['id_last_msg']);
        }
        mysql_free_result($request);
        // Check the MAX and MIN are correct.
        $request = smf_db_query('
			SELECT id_topic, MIN(id_msg) AS first_msg, MAX(id_msg) AS last_msg
			FROM {db_prefix}messages
			WHERE id_topic IN ({array_int:topics})
			GROUP BY id_topic', array('topics' => $topics));
        while ($row = mysql_fetch_assoc($request)) {
            // If not, update.
            if ($row['first_msg'] != $topicMaxMin[$row['id_topic']]['min'] || $row['last_msg'] != $topicMaxMin[$row['id_topic']]['max']) {
                smf_db_query('
					UPDATE {db_prefix}topics
					SET id_first_msg = {int:first_msg}, id_last_msg = {int:last_msg}
					WHERE id_topic = {int:selected_topic}', array('first_msg' => $row['first_msg'], 'last_msg' => $row['last_msg'], 'selected_topic' => $row['id_topic']));
            }
        }
        mysql_free_result($request);
    }
    smf_db_query('
		UPDATE {db_prefix}messages
		SET id_board = {int:id_board}' . ($isRecycleDest ? ',approved = {int:is_approved}' : '') . '
		WHERE id_topic IN ({array_int:topics})', array('id_board' => $toBoard, 'topics' => $topics, 'is_approved' => 1));
    smf_db_query('
		UPDATE {db_prefix}log_reported
		SET id_board = {int:id_board}
		WHERE id_topic IN ({array_int:topics})', array('id_board' => $toBoard, 'topics' => $topics));
    smf_db_query('
		UPDATE {db_prefix}calendar
		SET id_board = {int:id_board}
		WHERE id_topic IN ({array_int:topics})', array('id_board' => $toBoard, 'topics' => $topics));
    // Mark target board as seen, if it was already marked as seen before.
    $request = smf_db_query('
		SELECT (IFNULL(lb.id_msg, 0) >= b.id_msg_updated) AS isSeen
		FROM {db_prefix}boards AS b
			LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = b.id_board AND lb.id_member = {int:current_member})
		WHERE b.id_board = {int:id_board}', array('current_member' => $user_info['id'], 'id_board' => $toBoard));
    list($isSeen) = mysql_fetch_row($request);
    mysql_free_result($request);
    if (!empty($isSeen) && !$user_info['is_guest']) {
        smf_db_insert('replace', '{db_prefix}log_boards', array('id_board' => 'int', 'id_member' => 'int', 'id_msg' => 'int'), array($toBoard, $user_info['id'], $modSettings['maxMsgID']), array('id_board', 'id_member'));
    }
    // Update the cache?
    if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 3) {
        foreach ($topics as $topic_id) {
            CacheAPI::putCache('topic_board-' . $topic_id, null, 120);
        }
    }
    require_once $sourcedir . '/lib/Subs-Post.php';
    $updates = array_keys($fromBoards);
    $updates[] = $toBoard;
    updateLastMessages(array_unique($updates));
    // Update 'em pesky stats.
    updateStats('topic');
    updateStats('message');
    updateSettings(array('calendar_updated' => time()));
}
Ejemplo n.º 9
0
function MergeExecute($topics = array())
{
    global $user_info, $txt, $context, $scripturl, $sourcedir;
    global $smcFunc, $language, $modSettings;
    // Check the session.
    checkSession('request');
    // Handle URLs from 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 = boardsAllowedTo('approve_posts');
    }
    // Get info about the topics and polls that will be merged.
    $request = smf_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 (mysql_num_rows($request) < 2) {
        fatal_lang_error('no_topic_id');
    }
    $num_views = 0;
    $is_sticky = 0;
    $boardTotals = array();
    $boards = array();
    $polls = array();
    while ($row = mysql_fetch_assoc($request)) {
        // Make a note for the board counts...
        if (!isset($boardTotals[$row['id_board']])) {
            $boardTotals[$row['id_board']] = array('posts' => 0, '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']]['topics']++;
        }
        $boardTotals[$row['id_board']]['unapproved_posts'] += $row['unapproved_posts'];
        $boardTotals[$row['id_board']]['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' => timeformat($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' => timeformat($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']);
    }
    mysql_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 MergeExecute were set, so this must've been an internal call.
    if (!empty($topics)) {
        isAllowedTo('merge_any', $boards);
        loadTemplate('SplitTopics');
    }
    // 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');
    }
    // Make sure they can see all boards....
    $request = smf_db_query('
		SELECT b.id_board
		FROM {db_prefix}boards AS b
		WHERE b.id_board IN ({array_int:boards})
			AND {query_see_board}' . (!in_array(0, $merge_boards) ? '
			AND b.id_board IN ({array_int:merge_boards})' : '') . '
		LIMIT ' . count($boards), array('boards' => $boards, 'merge_boards' => $merge_boards));
    // If the number of boards that's in the output isn't exactly the same as we've put in there, you're in trouble.
    if (mysql_num_rows($request) != count($boards)) {
        fatal_lang_error('no_board');
    }
    mysql_free_result($request);
    if (empty($_REQUEST['sa']) || $_REQUEST['sa'] == 'options') {
        if (count($polls) > 1) {
            $request = smf_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 = mysql_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);
            }
            mysql_free_result($request);
        }
        if (count($boards) > 1) {
            $request = smf_db_query('
				SELECT id_board, name
				FROM {db_prefix}boards
				WHERE id_board IN ({array_int:boards})
				ORDER BY name
				LIMIT ' . count($boards), array('boards' => $boards));
            while ($row = mysql_fetch_assoc($request)) {
                $context['boards'][] = array('id' => $row['id_board'], 'name' => $row['name'], 'selected' => $row['id_board'] == $topic_data[$firstTopic]['board']);
            }
            mysql_free_result($request);
        }
        $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(commonAPI::htmltrim(commonAPI::htmlspecialchars($_POST['custom_subject'])), array("\r" => '', "\n" => '', "\t" => ''));
        // Keep checking the length.
        if (commonAPI::strlen($target_subject) > 100) {
            $target_subject = commonAPI::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 = smf_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;
    while ($row = mysql_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'];
        }
    }
    mysql_free_result($request);
    // Ensure we have a board stat for the target board.
    if (!isset($boardTotals[$target_board])) {
        $boardTotals[$target_board] = array('posts' => 0, '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]['topics']--;
    } else {
        $boardTotals[$target_board]['unapproved_topics']--;
    }
    $boardTotals[$target_board]['unapproved_posts'] -= $num_unapproved;
    $boardTotals[$target_board]['posts'] -= $topic_approved ? $num_replies + 1 : $num_replies;
    // Get the member ID of the first and last message.
    $request = smf_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) = mysql_fetch_row($request);
    list($member_updated) = mysql_fetch_row($request);
    // First and last message are the same, so only row was returned.
    if ($member_updated === NULL) {
        $member_updated = $member_started;
    }
    mysql_free_result($request);
    // Assign the first topic ID to be the merged topic.
    $id_topic = min($topics);
    // Delete the remaining topics.
    $deleted_topics = array_diff($topics, array($id_topic));
    smf_db_query('
		DELETE FROM {db_prefix}topics
		WHERE id_topic IN ({array_int:deleted_topics})', array('deleted_topics' => $deleted_topics));
    smf_db_query('
		DELETE FROM {db_prefix}log_search_subjects
		WHERE id_topic IN ({array_int:deleted_topics})', array('deleted_topics' => $deleted_topics));
    // Asssign the properties of the newly merged topic.
    smf_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));
    // Grab the response prefix (like 'Re: ') in the default forum language.
    if (!isset($context['response_prefix']) && !($context['response_prefix'] = CacheAPI::getCache('response_prefix'))) {
        if ($language === $user_info['language']) {
            $context['response_prefix'] = $txt['response_prefix'];
        } else {
            loadLanguage('index', $language, false);
            $context['response_prefix'] = $txt['response_prefix'];
            loadLanguage('index');
        }
        CacheAPI::putCache('response_prefix', $context['response_prefix'], 600);
    }
    // Change the topic IDs of all messages that will be merged.  Also adjust subjects if 'enforce subject' was checked.
    smf_db_query('
		UPDATE {db_prefix}messages
		SET
			id_topic = {int:id_topic},
			id_board = {int:target_board}' . (empty($_POST['enforce_subject']) ? '' : ',
			subject = {string:subject}') . '
		WHERE id_topic IN ({array_int:topic_list})', array('topic_list' => $topics, 'id_topic' => $id_topic, 'target_board' => $target_board, 'subject' => $context['response_prefix'] . $target_subject));
    // Any reported posts should reflect the new board.
    smf_db_query('
		UPDATE {db_prefix}log_reported
		SET
			id_topic = {int:id_topic},
			id_board = {int:target_board}
		WHERE id_topic IN ({array_int:topics_list})', array('topics_list' => $topics, 'id_topic' => $id_topic, 'target_board' => $target_board));
    // Change the subject of the first message...
    smf_db_query('
		UPDATE {db_prefix}messages
		SET subject = {string:target_subject}
		WHERE id_msg = {int:first_msg}', array('first_msg' => $first_msg, 'target_subject' => $target_subject));
    // Adjust all calendar events to point to the new topic.
    smf_db_query('
		UPDATE {db_prefix}calendar
		SET
			id_topic = {int:id_topic},
			id_board = {int:target_board}
		WHERE id_topic IN ({array_int:deleted_topics})', array('deleted_topics' => $deleted_topics, 'id_topic' => $id_topic, 'target_board' => $target_board));
    // Merge log topic entries.
    $request = smf_db_query('
		SELECT id_member, MIN(id_msg) AS new_id_msg
		FROM {db_prefix}log_topics
		WHERE id_topic IN ({array_int:topics})
		GROUP BY id_member', array('topics' => $topics));
    if (mysql_num_rows($request) > 0) {
        $replaceEntries = array();
        while ($row = mysql_fetch_assoc($request)) {
            $replaceEntries[] = array($row['id_member'], $id_topic, $row['new_id_msg']);
        }
        smf_db_insert('replace', '{db_prefix}log_topics', array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int'), $replaceEntries, array('id_member', 'id_topic'));
        unset($replaceEntries);
        // Get rid of the old log entries.
        smf_db_query('
			DELETE FROM {db_prefix}log_topics
			WHERE id_topic IN ({array_int:deleted_topics})', array('deleted_topics' => $deleted_topics));
    }
    mysql_free_result($request);
    // Merge topic notifications.
    $notifications = isset($_POST['notifications']) && is_array($_POST['notifications']) ? array_intersect($topics, $_POST['notifications']) : array();
    if (!empty($notifications)) {
        $request = smf_db_query('
			SELECT id_member, MAX(sent) AS sent
			FROM {db_prefix}log_notify
			WHERE id_topic IN ({array_int:topics_list})
			GROUP BY id_member', array('topics_list' => $notifications));
        if (mysql_num_rows($request) > 0) {
            $replaceEntries = array();
            while ($row = mysql_fetch_assoc($request)) {
                $replaceEntries[] = array($row['id_member'], $id_topic, 0, $row['sent']);
            }
            smf_db_insert('replace', '{db_prefix}log_notify', array('id_member' => 'int', 'id_topic' => 'int', 'id_board' => 'int', 'sent' => 'int'), $replaceEntries, array('id_member', 'id_topic', 'id_board'));
            unset($replaceEntries);
            smf_db_query('
				DELETE FROM {db_prefix}log_topics
				WHERE id_topic IN ({array_int:deleted_topics})', array('deleted_topics' => $deleted_topics));
        }
        mysql_free_result($request);
    }
    // Get rid of the redundant polls.
    if (!empty($deleted_polls)) {
        smf_db_query('
			DELETE FROM {db_prefix}polls
			WHERE id_poll IN ({array_int:deleted_polls})', array('deleted_polls' => $deleted_polls));
        smf_db_query('
			DELETE FROM {db_prefix}poll_choices
			WHERE id_poll IN ({array_int:deleted_polls})', array('deleted_polls' => $deleted_polls));
        smf_db_query('
			DELETE FROM {db_prefix}log_polls
			WHERE id_poll IN ({array_int:deleted_polls})', array('deleted_polls' => $deleted_polls));
    }
    // Cycle through each board...
    foreach ($boardTotals as $id_board => $stats) {
        smf_db_query('
			UPDATE {db_prefix}boards
			SET
				num_topics = CASE WHEN {int:topics} > num_topics THEN 0 ELSE num_topics - {int:topics} END,
				unapproved_topics = CASE WHEN {int:unapproved_topics} > unapproved_topics THEN 0 ELSE unapproved_topics - {int:unapproved_topics} END,
				num_posts = CASE WHEN {int:posts} > num_posts THEN 0 ELSE num_posts - {int:posts} END,
				unapproved_posts = CASE WHEN {int:unapproved_posts} > unapproved_posts THEN 0 ELSE unapproved_posts - {int:unapproved_posts} END
			WHERE id_board = {int:id_board}', array('id_board' => $id_board, 'topics' => $stats['topics'], 'unapproved_topics' => $stats['unapproved_topics'], 'posts' => $stats['posts'], 'unapproved_posts' => $stats['unapproved_posts']));
    }
    // Determine the board the final topic resides in
    $request = smf_db_query('
		SELECT id_board
		FROM {db_prefix}topics
		WHERE id_topic = {int:id_topic}
		LIMIT 1', array('id_topic' => $id_topic));
    list($id_board) = mysql_fetch_row($request);
    mysql_free_result($request);
    require_once $sourcedir . '/lib/Subs-Post.php';
    // 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?
    sendNotifications($id_topic, 'merge');
    // Send them to the all done page.
    redirectexit('action=mergetopics;sa=done;to=' . $id_topic . ';targetboard=' . $target_board);
}
Ejemplo n.º 10
0
function ManageLabels()
{
    global $txt, $context, $user_info, $scripturl, $smcFunc;
    EoS_Smarty::loadTemplate('pm/base');
    EoS_Smarty::getConfigInstance()->registerHookTemplate('pm_content_area', 'pm/manage_labels');
    // Build the link tree elements...
    $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manlabels', 'name' => $txt['pm_manage_labels']);
    $context['page_title'] = $txt['pm_manage_labels'];
    $context['sub_template'] = 'labels';
    $the_labels = array();
    // Add all existing labels to the array to save, slashing them as necessary...
    foreach ($context['labels'] as $label) {
        if ($label['id'] != -1) {
            $the_labels[$label['id']] = $label['name'];
        }
    }
    if (isset($_POST[$context['session_var']])) {
        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(commonAPI::htmlspecialchars(trim($_POST['label'])), array(',' => '&#044;'));
            if (commonAPI::strlen($_POST['label']) > 30) {
                $_POST['label'] = commonAPI::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])) {
                    $_POST['label_name'][$id] = trim(strtr(commonAPI::htmlspecialchars($_POST['label_name'][$id]), array(',' => '&#044;')));
                    if (commonAPI::strlen($_POST['label_name'][$id]) > 30) {
                        $_POST['label_name'][$id] = commonAPI::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;
                }
            }
            // Now find the messages to change.
            $request = smf_db_query('
				SELECT id_pm, labels
				FROM {db_prefix}pm_recipients
				WHERE FIND_IN_SET({raw:find_label_implode}, labels) != 0
					AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'find_label_implode' => '\'' . implode('\', labels) != 0 OR FIND_IN_SET(\'', $searchArray) . '\''));
            while ($row = mysql_fetch_assoc($request)) {
                // Do the long task of updating them...
                $toChange = explode(',', $row['labels']);
                foreach ($toChange as $key => $value) {
                    if (in_array($value, $searchArray)) {
                        if (isset($new_labels[$value])) {
                            $toChange[$key] = $new_labels[$value];
                        } else {
                            unset($toChange[$key]);
                        }
                    }
                }
                if (empty($toChange)) {
                    $toChange[] = '-1';
                }
                // Update the message.
                smf_db_query('
					UPDATE {db_prefix}pm_recipients
					SET labels = {string:new_labels}
					WHERE id_pm = {int:id_pm}
						AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'id_pm' => $row['id_pm'], 'new_labels' => implode(',', array_unique($toChange))));
            }
            mysql_free_result($request);
            // 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'])) {
                    smf_db_query('
						UPDATE {db_prefix}pm_rules
						SET actions = {string:actions}
						WHERE id_rule = {int:id_rule}
							AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'id_rule' => $id, 'actions' => serialize($context['rules'][$id]['actions'])));
                    unset($rule_changes[$k]);
                }
            }
            // Anything left here means it's lost all actions...
            if (!empty($rule_changes)) {
                smf_db_query('
					DELETE FROM {db_prefix}pm_rules
					WHERE id_rule IN ({array_int:rule_list})
							AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'rule_list' => $rule_changes));
            }
        }
        // Make sure we're not caching this!
        CacheAPI::putCache('labelCounts:' . $user_info['id'], null, 720);
        // To make the changes appear right away, redirect.
        redirectexit('action=pm;sa=manlabels');
    }
}
Ejemplo n.º 11
0
function ModBlockReportedPosts()
{
    global $context, $user_info, $scripturl, $smcFunc;
    // Got the info already?
    $cachekey = md5(serialize($user_info['mod_cache']['bq']));
    $context['reported_posts'] = array();
    if ($user_info['mod_cache']['bq'] == '0=1') {
        return 'reported_posts_block';
    }
    if (($reported_posts = CacheAPI::getCache('reported_posts_' . $cachekey, 90)) === null) {
        // By George, that means we in a position to get the reports, jolly good.
        $request = smf_db_query('
			SELECT lr.id_report, lr.id_msg, lr.id_topic, lr.id_board, lr.id_member, lr.subject,
				lr.num_reports, IFNULL(mem.real_name, lr.membername) AS author_name,
				IFNULL(mem.id_member, 0) AS id_author
			FROM {db_prefix}log_reported AS lr
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lr.id_member)
			WHERE ' . ($user_info['mod_cache']['bq'] == '1=1' || $user_info['mod_cache']['bq'] == '0=1' ? $user_info['mod_cache']['bq'] : 'lr.' . $user_info['mod_cache']['bq']) . '
				AND lr.closed = {int:not_closed}
				AND lr.ignore_all = {int:not_ignored}
			ORDER BY lr.time_updated DESC
			LIMIT 10', array('not_closed' => 0, 'not_ignored' => 0));
        $reported_posts = array();
        while ($row = mysql_fetch_assoc($request)) {
            $reported_posts[] = $row;
        }
        mysql_free_result($request);
        // Cache it.
        CacheAPI::putCache('reported_posts_' . $cachekey, $reported_posts, 90);
    }
    $context['reported_posts'] = array();
    foreach ($reported_posts as $i => $row) {
        $context['reported_posts'][] = array('id' => $row['id_report'], 'alternate' => $i % 2, 'topic_href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'], 'report_href' => $scripturl . '?action=moderate;area=reports;report=' . $row['id_report'], 'author' => array('id' => $row['id_author'], 'name' => $row['author_name'], 'link' => $row['id_author'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_author'] . '">' . $row['author_name'] . '</a>' : $row['author_name'], 'href' => $scripturl . '?action=profile;u=' . $row['id_author']), 'comments' => array(), 'subject' => $row['subject'], 'num_reports' => $row['num_reports']);
    }
    return 'reported_posts';
}
Ejemplo n.º 12
0
function createWaveFile($word)
{
    global $settings, $user_info, $context;
    // Allow max 2 requests per 20 seconds.
    if (($ip = CacheAPI::getCache('wave_file/' . $user_info['ip'], 20)) > 2 || ($ip2 = CacheAPI::getCache('wave_file/' . $user_info['ip2'], 20)) > 2) {
        die(header('HTTP/1.1 400 Bad Request'));
    }
    CacheAPI::putCache('wave_file/' . $user_info['ip'], $ip ? $ip + 1 : 1, 20);
    CacheAPI::putCache('wave_file/' . $user_info['ip2'], $ip2 ? $ip2 + 1 : 1, 20);
    // Fixate randomization for this word.
    mt_srand(end(unpack('n', md5($word . session_id()))));
    // Try to see if there's a sound font in the user's language.
    if (file_exists($settings['default_theme_dir'] . '/fonts/sound/a.' . $user_info['language'] . '.wav')) {
        $sound_language = $user_info['language'];
    } elseif (file_exists($settings['default_theme_dir'] . '/fonts/sound/a.english.wav')) {
        $sound_language = 'english';
    } else {
        return false;
    }
    // File names are in lower case so lets make sure that we are only using a lower case string
    $word = strtolower($word);
    // Loop through all letters of the word $word.
    $sound_word = '';
    for ($i = 0; $i < strlen($word); $i++) {
        $sound_letter = implode('', file($settings['default_theme_dir'] . '/fonts/sound/' . $word[$i] . '.' . $sound_language . '.wav'));
        if (strpos($sound_letter, 'data') === false) {
            return false;
        }
        $sound_letter = substr($sound_letter, strpos($sound_letter, 'data') + 8);
        switch ($word[$i] === 's' ? 0 : mt_rand(0, 2)) {
            case 0:
                for ($j = 0, $n = strlen($sound_letter); $j < $n; $j++) {
                    for ($k = 0, $m = round(mt_rand(15, 25) / 10); $k < $m; $k++) {
                        $sound_word .= $word[$i] === 's' ? $sound_letter[$j] : chr(mt_rand(max(ord($sound_letter[$j]) - 1, 0x0), min(ord($sound_letter[$j]) + 1, 0xff)));
                    }
                }
                break;
            case 1:
                for ($j = 0, $n = strlen($sound_letter) - 1; $j < $n; $j += 2) {
                    $sound_word .= (mt_rand(0, 3) == 0 ? '' : $sound_letter[$j]) . (mt_rand(0, 3) === 0 ? $sound_letter[$j + 1] : $sound_letter[$j]) . (mt_rand(0, 3) === 0 ? $sound_letter[$j] : $sound_letter[$j + 1]) . $sound_letter[$j + 1] . (mt_rand(0, 3) == 0 ? $sound_letter[$j + 1] : '');
                }
                $sound_word .= str_repeat($sound_letter[$n], 2);
                break;
            case 2:
                $shift = 0;
                for ($j = 0, $n = strlen($sound_letter); $j < $n; $j++) {
                    if (mt_rand(0, 10) === 0) {
                        $shift += mt_rand(-3, 3);
                    }
                    for ($k = 0, $m = round(mt_rand(15, 25) / 10); $k < $m; $k++) {
                        $sound_word .= chr(min(max(ord($sound_letter[$j]) + $shift, 0x0), 0xff));
                    }
                }
                break;
        }
        $sound_word .= str_repeat(chr(0x80), mt_rand(10000, 10500));
    }
    $data_size = strlen($sound_word);
    $file_size = $data_size + 0x24;
    $sample_rate = 16000;
    // Disable compression.
    ob_end_clean();
    header('Content-Encoding: none');
    // Output the wav.
    header('Content-type: audio/x-wav');
    header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
    header('Content-Length: ' . ($file_size + 0x8));
    echo pack('nnVnnnnnnnnVVnnnnV', 0x5249, 0x4646, $file_size, 0x5741, 0x5645, 0x666d, 0x7420, 0x1000, 0x0, 0x100, 0x100, $sample_rate, $sample_rate, 0x100, 0x800, 0x6461, 0x7461, $data_size), $sound_word;
    // Noting more to add.
    die;
}
Ejemplo n.º 13
0
function RecentPosts()
{
    global $sourcedir, $txt, $scripturl, $user_info, $context, $modSettings, $board, $memberContext;
    if (!empty($modSettings['karmaMode'])) {
        require_once $sourcedir . '/lib/Subs-Ratings.php';
        $boards_like_see = boardsAllowedTo('like_see');
        $boards_like_give = boardsAllowedTo('like_give');
    } else {
        $context['can_see_like'] = $context['can_give_like'] = false;
        $boards_like_see = array();
        $boards_like_give = array();
    }
    $context['time_now'] = time();
    $context['need_synhlt'] = true;
    EoS_Smarty::loadTemplate('recent');
    $context['template_functions'] = 'recentposts';
    $context['messages_per_page'] = $modSettings['defaultMaxMessages'];
    $context['page_number'] = isset($_REQUEST['start']) ? $_REQUEST['start'] / $context['messages_per_page'] : 0;
    $context['page_title'] = $txt['recent_posts'] . ((int) $context['page_number'] > 0 ? ' - ' . $txt['page'] . ' ' . ($context['page_number'] + 1) : '');
    $boards_hidden_1 = boardsAllowedTo('see_hidden1');
    $boards_hidden_2 = boardsAllowedTo('see_hidden2');
    $boards_hidden_3 = boardsAllowedTo('see_hidden3');
    if (isset($_REQUEST['start']) && $_REQUEST['start'] > 95) {
        $_REQUEST['start'] = 95;
    }
    $query_parameters = array();
    if (!empty($_REQUEST['c']) && empty($board)) {
        $_REQUEST['c'] = explode(',', $_REQUEST['c']);
        foreach ($_REQUEST['c'] as $i => $c) {
            $_REQUEST['c'][$i] = (int) $c;
        }
        if (count($_REQUEST['c']) == 1) {
            $request = smf_db_query('
				SELECT name
				FROM {db_prefix}categories
				WHERE id_cat = {int:id_cat}
				LIMIT 1', array('id_cat' => $_REQUEST['c'][0]));
            list($name) = mysql_fetch_row($request);
            mysql_free_result($request);
            if (empty($name)) {
                fatal_lang_error('no_access', false);
            }
            $context['linktree'][] = array('url' => $scripturl . '#c' . (int) $_REQUEST['c'], 'name' => $name);
        }
        $request = smf_db_query('
			SELECT b.id_board, b.num_posts
			FROM {db_prefix}boards AS b
			WHERE b.id_cat IN ({array_int:category_list})
				AND {query_see_board}', array('category_list' => $_REQUEST['c']));
        $total_cat_posts = 0;
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            $boards[] = $row['id_board'];
            $total_cat_posts += $row['num_posts'];
        }
        mysql_free_result($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'b.id_board IN ({array_int:boards})';
        $query_parameters['boards'] = $boards;
        // If this category has a significant number of posts in it...
        if ($total_cat_posts > 100 && $total_cat_posts > $modSettings['totalMessages'] / 15) {
            $query_this_board .= '
					AND m.id_msg >= {int:max_id_msg}';
            $query_parameters['max_id_msg'] = max(0, $modSettings['maxMsgID'] - 400 - $_REQUEST['start'] * 7);
        }
        $context['page_index'] = $total_cat_posts ? constructPageIndex($scripturl . '?action=recent;c=' . implode(',', $_REQUEST['c']), $_REQUEST['start'], min(100, $total_cat_posts), $context['messages_per_page'], false) : '';
    } elseif (!empty($_REQUEST['boards'])) {
        $_REQUEST['boards'] = explode(',', $_REQUEST['boards']);
        foreach ($_REQUEST['boards'] as $i => $b) {
            $_REQUEST['boards'][$i] = (int) $b;
        }
        $request = smf_db_query('
			SELECT b.id_board, b.num_posts
			FROM {db_prefix}boards AS b
			WHERE b.id_board IN ({array_int:board_list})
				AND {query_see_board}
			LIMIT {int:limit}', array('board_list' => $_REQUEST['boards'], 'limit' => count($_REQUEST['boards'])));
        $total_posts = 0;
        $boards = array();
        while ($row = mysql_fetch_assoc($request)) {
            $boards[] = $row['id_board'];
            $total_posts += $row['num_posts'];
        }
        mysql_free_result($request);
        if (empty($boards)) {
            fatal_lang_error('error_no_boards_selected');
        }
        $query_this_board = 'b.id_board IN ({array_int:boards})';
        $query_parameters['boards'] = $boards;
        // If these boards have a significant number of posts in them...
        if ($total_posts > 100 && $total_posts > $modSettings['totalMessages'] / 12) {
            $query_this_board .= '
					AND m.id_msg >= {int:max_id_msg}';
            $query_parameters['max_id_msg'] = max(0, $modSettings['maxMsgID'] - 500 - $_REQUEST['start'] * 9);
        }
        $context['page_index'] = $total_posts ? constructPageIndex($scripturl . '?action=recent;boards=' . implode(',', $_REQUEST['boards']), $_REQUEST['start'], min(100, $total_posts), $context['messages_per_page'], false) : '';
    } elseif (!empty($board)) {
        $request = smf_db_query('
			SELECT num_posts
			FROM {db_prefix}boards
			WHERE id_board = {int:current_board}
			LIMIT 1', array('current_board' => $board));
        list($total_posts) = mysql_fetch_row($request);
        mysql_free_result($request);
        $query_this_board = 'b.id_board = {int:board}';
        $query_parameters['board'] = $board;
        // If this board has a significant number of posts in it...
        if ($total_posts > 80 && $total_posts > $modSettings['totalMessages'] / 10) {
            $query_this_board .= '
					AND m.id_msg >= {int:max_id_msg}';
            $query_parameters['max_id_msg'] = max(0, $modSettings['maxMsgID'] - 600 - $_REQUEST['start'] * 10);
        }
        $context['page_index'] = $total_posts ? constructPageIndex($scripturl . '?action=recent;board=' . $board . '.%1$d', $_REQUEST['start'], min(100, $total_posts), $context['messages_per_page'], true) : '';
    } else {
        $query_this_board = '{query_wanna_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
					AND b.id_board != {int:recycle_board}' : '') . '
					AND m.id_msg >= {int:max_id_msg}';
        $query_parameters['max_id_msg'] = max(0, $modSettings['maxMsgID'] - 100 - $_REQUEST['start'] * 6);
        $query_parameters['recycle_board'] = $modSettings['recycle_board'];
        // !!! This isn't accurate because we ignore the recycle bin.
        $context['page_index'] = constructPageIndex($scripturl . '?action=recent', $_REQUEST['start'], min(100, $modSettings['totalMessages']), $context['messages_per_page'], false);
    }
    $context['linktree'][] = array('url' => $scripturl . '?action=recent' . (empty($board) ? empty($_REQUEST['c']) ? '' : ';c=' . (int) $_REQUEST['c'] : ';board=' . $board . '.0'), 'name' => $context['page_title']);
    $context['start'] = isset($_REQUEST['start']) ? $_REQUEST['start'] : 0;
    $key = 'recent-' . $user_info['id'] . '-' . md5(serialize(array_diff_key($query_parameters, array('max_id_msg' => 0)))) . '-' . (int) $_REQUEST['start'];
    if (empty($modSettings['cache_enable']) || ($messages = CacheAPI::getCache($key, 120)) == null) {
        $done = false;
        while (!$done) {
            // Find the 10 most recent messages they can *view*.
            // !!!SLOW This query is really slow still, probably?
            $request = smf_db_query('
				SELECT m.id_msg
				FROM {db_prefix}messages AS m
					INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
				WHERE ' . $query_this_board . '
					AND m.approved = {int:is_approved}
				ORDER BY m.id_msg DESC
				LIMIT {int:offset}, {int:limit}', array_merge($query_parameters, array('is_approved' => 1, 'offset' => $_REQUEST['start'], 'limit' => $context['messages_per_page'])));
            // If we don't have 10 results, try again with an unoptimized version covering all rows, and cache the result.
            if (isset($query_parameters['max_id_msg']) && mysql_num_rows($request) < $context['messages_per_page']) {
                mysql_free_result($request);
                $query_this_board = str_replace('AND m.id_msg >= {int:max_id_msg}', '', $query_this_board);
                $cache_results = true;
                unset($query_parameters['max_id_msg']);
            } else {
                $done = true;
            }
        }
        $messages = array();
        while ($row = mysql_fetch_assoc($request)) {
            $messages[] = $row['id_msg'];
        }
        mysql_free_result($request);
        if (!empty($cache_results)) {
            CacheAPI::putCache($key, $messages, 120);
        }
    }
    // Nothing here... Or at least, nothing you can see...
    if (empty($messages)) {
        $context['posts'] = array();
        return;
    }
    // Get all the most recent posts.
    $request = smf_db_query('
		SELECT
			m.id_msg, m.subject, m.smileys_enabled, m.poster_time, m.modified_time, m.body, m.icon, m.id_topic, t.id_board, b.id_cat, mc.body AS cached_body,
			b.name AS bname, c.name AS cname, t.num_replies, m.id_member, m2.id_member AS id_first_member, ' . (!empty($modSettings['karmaMode']) ? 'lc.likes_count, lc.like_status, lc.updated AS like_updated, l.rtype AS liked, ' : '0 AS likes_count, 0 AS like_status, 0 AS like_updated, 0 AS liked, ') . '
			IFNULL(mem2.real_name, m2.poster_name) AS first_poster_name, t.id_first_msg, m2.subject AS first_subject, m2.poster_time AS time_started,
			IFNULL(mem.real_name, m.poster_name) AS poster_name, t.id_last_msg
		FROM {db_prefix}messages AS m
			INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			INNER JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
			INNER JOIN {db_prefix}messages AS m2 ON (m2.id_msg = t.id_first_msg)
			LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member)
			LEFT JOIN {db_prefix}members AS mem2 ON (mem2.id_member = m2.id_member)' . (!empty($modSettings['karmaMode']) ? '
			LEFT JOIN {db_prefix}likes AS l ON (l.id_msg = m.id_msg AND l.ctype = 1 AND l.id_user = {int:id_user})
			LEFT JOIN {db_prefix}like_cache AS lc ON (lc.id_msg = m.id_msg AND lc.ctype = 1)' : '') . '
			LEFT JOIN {db_prefix}messages_cache AS mc ON (mc.id_msg = m.id_msg AND mc.style = {int:style} AND mc.lang = {int:lang})
		WHERE m.id_msg IN ({array_int:message_list})
		ORDER BY m.id_msg DESC
		LIMIT ' . count($messages), array('message_list' => $messages, 'style' => $user_info['smiley_set_id'], 'lang' => $user_info['language_id'], 'id_user' => $user_info['id']));
    $counter = $_REQUEST['start'] + 1;
    $context['posts'] = array();
    $board_ids = array('own' => array(), 'any' => array());
    $userids = array();
    while ($row = mysql_fetch_assoc($request)) {
        $check_boards = array(0, $row['id_board']);
        // 0 is for admin
        $context['can_see_hidden_level1'] = count(array_intersect($check_boards, $boards_hidden_1)) > 0;
        $context['can_see_hidden_level2'] = count(array_intersect($check_boards, $boards_hidden_2)) > 0;
        $context['can_see_hidden_level3'] = count(array_intersect($check_boards, $boards_hidden_3)) > 0;
        $context['can_see_like'] = count(array_intersect($check_boards, $boards_like_see)) > 0;
        $context['can_give_like'] = count(array_intersect($check_boards, $boards_like_give)) > 0;
        // Censor everything.
        censorText($row['body']);
        censorText($row['subject']);
        getCachedPost($row);
        // this will also care about bbc parsing...
        // And build the array.
        $thref = URL::topic($row['id_topic'], $row['first_subject'], 0, false, '.msg' . $row['id_msg'], '#' . $row['id_msg']);
        $topichref = URL::topic($row['id_topic'], $row['first_subject'], 0);
        $bhref = URL::board($row['id_board'], $row['bname'], 0, false);
        $fhref = empty($row['id_first_member']) ? '' : URL::user($row['id_first_member'], $row['first_poster_name']);
        $userids[$row['id_msg']] = $row['id_member'];
        $context['posts'][$row['id_msg']] = array('id' => $row['id_msg'], 'counter' => $counter++, 'sequence_number' => true, 'icon' => $row['icon'], 'icon_url' => getPostIcon($row['icon']), 'category' => array('id' => $row['id_cat'], 'name' => $row['cname'], 'href' => $scripturl . '#c' . $row['id_cat'], 'link' => '<a href="' . $scripturl . '#c' . $row['id_cat'] . '">' . $row['cname'] . '</a>'), 'board' => array('id' => $row['id_board'], 'name' => $row['bname'], 'href' => $bhref, 'link' => '<a href="' . $bhref . '">' . $row['bname'] . '</a>'), 'href' => $thref, 'link' => '<a href="' . $thref . '" rel="nofollow">' . $row['subject'] . '</a>', 'start' => $row['num_replies'], 'subject' => $row['subject'], 'time' => timeformat($row['poster_time']), 'timestamp' => forum_time(true, $row['poster_time']), 'first_poster' => array('id' => $row['id_first_member'], 'name' => $row['first_poster_name'], 'href' => $fhref, 'link' => empty($row['id_first_member']) ? $row['first_poster_name'] : '<a href="' . $fhref . '">' . $row['first_poster_name'] . '</a>', 'time' => timeformat($row['time_started'])), 'topic' => array('id' => $row['id_topic'], 'href' => $topichref, 'link' => '<a href="' . $topichref . '" rel="nofollow">' . $row['first_subject'] . '</a>'), 'permahref' => URL::parse('?msg=' . $row['id_msg']), 'permalink' => $txt['view_in_thread'], 'id_member' => $row['id_member'], 'body' => $row['body'], 'can_reply' => false, 'can_mark_notify' => false, 'can_delete' => false, 'delete_possible' => ($row['id_first_msg'] != $row['id_msg'] || $row['id_last_msg'] == $row['id_msg']) && (empty($modSettings['edit_disable_time']) || $row['poster_time'] + $modSettings['edit_disable_time'] * 60 >= time()), 'likes_count' => $row['likes_count'], 'like_status' => $row['like_status'], 'liked' => $row['liked'], 'like_updated' => $row['like_updated'], 'likers' => '', 'likelink' => '');
        if ($context['can_see_like']) {
            Ratings::addContent($context['posts'][$row['id_msg']], $context['can_give_like'], $context['time_now']);
        }
        if ($user_info['id'] == $row['id_first_member']) {
            $board_ids['own'][$row['id_board']][] = $row['id_msg'];
        }
        $board_ids['any'][$row['id_board']][] = $row['id_msg'];
    }
    mysql_free_result($request);
    loadMemberData(array_unique($userids));
    // There might be - and are - different permissions between any and own.
    $permissions = array('own' => array('post_reply_own' => 'can_reply', 'delete_own' => 'can_delete'), 'any' => array('post_reply_any' => 'can_reply', 'mark_any_notify' => 'can_mark_notify', 'delete_any' => 'can_delete'));
    // Now go through all the permissions, looking for boards they can do it on.
    foreach ($permissions as $type => $list) {
        foreach ($list as $permission => $allowed) {
            // They can do it on these boards...
            $boards = boardsAllowedTo($permission);
            // If 0 is the only thing in the array, they can do it everywhere!
            if (!empty($boards) && $boards[0] == 0) {
                $boards = array_keys($board_ids[$type]);
            }
            // Go through the boards, and look for posts they can do this on.
            foreach ($boards as $board_id) {
                // Hmm, they have permission, but there are no topics from that board on this page.
                if (!isset($board_ids[$type][$board_id])) {
                    continue;
                }
                // Okay, looks like they can do it for these posts.
                foreach ($board_ids[$type][$board_id] as $counter) {
                    if ($type == 'any' || $context['posts'][$counter]['id_member'] == $user_info['id']) {
                        $context['posts'][$counter][$allowed] = true;
                    }
                }
            }
        }
    }
    $quote_enabled = empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC']));
    foreach ($context['posts'] as $counter => &$post) {
        loadMemberContext($post['id_member']);
        $post['member'] =& $memberContext[$post['id_member']];
        // Some posts - the first posts - can't just be deleted.
        $context['posts'][$counter]['can_delete'] &= $context['posts'][$counter]['delete_possible'];
        // And some cannot be quoted...
        $context['posts'][$counter]['can_quote'] = $context['posts'][$counter]['can_reply'] && $quote_enabled;
    }
}
Ejemplo n.º 14
0
function EditBoard2()
{
    global $txt, $sourcedir, $modSettings, $smcFunc, $context;
    checkSession();
    require_once $sourcedir . '/lib/Subs-Boards.php';
    $_POST['boardid'] = (int) $_POST['boardid'];
    // invalidate the cache for cached board names (pretty URLs)
    CacheAPI::putCache('simplesef_board_list', null, 0);
    // Mode: modify aka. don't delete.
    if (isset($_POST['edit']) || isset($_POST['add'])) {
        $boardOptions = array();
        // Move this board to a new category?
        if (!empty($_POST['new_cat'])) {
            $boardOptions['move_to'] = 'bottom';
            $boardOptions['target_category'] = (int) $_POST['new_cat'];
        } elseif (!empty($_POST['placement']) && !empty($_POST['board_order'])) {
            if (!in_array($_POST['placement'], array('before', 'after', 'child'))) {
                fatal_lang_error('mangled_post', false);
            }
            $boardOptions['move_to'] = $_POST['placement'];
            $boardOptions['target_board'] = (int) $_POST['board_order'];
        }
        // Checkboxes....
        $boardOptions['allow_topics'] = !isset($_POST['act_as_cat']);
        $boardOptions['automerge'] = isset($_POST['automerge']) ? $_POST['automerge'] : 0;
        $boardOptions['boardicon'] = isset($_POST['boardicon']) && !empty($_POST['boardicon']) ? $_POST['boardicon'] : '';
        $boardOptions['posts_count'] = isset($_POST['count']);
        $boardOptions['override_theme'] = isset($_POST['override_theme']);
        $boardOptions['board_theme'] = (int) $_POST['boardtheme'];
        $boardOptions['access_groups'] = array();
        if (!empty($_POST['groups'])) {
            foreach ($_POST['groups'] as $group) {
                $boardOptions['access_groups'][] = (int) $group;
            }
        }
        // Change '1 & 2' to '1 &amp; 2', but not '&amp;' to '&amp;amp;'...
        $boardOptions['board_name'] = preg_replace('~[&]([^;]{8}|[^;]{0,8}$)~', '&amp;$1', $_POST['board_name']);
        $boardOptions['board_description'] = preg_replace('~[&]([^;]{8}|[^;]{0,8}$)~', '&amp;$1', $_POST['desc']);
        $boardOptions['moderator_string'] = $_POST['moderators'];
        if (isset($_POST['moderator_list']) && is_array($_POST['moderator_list'])) {
            $moderators = array();
            foreach ($_POST['moderator_list'] as $moderator) {
                $moderators[(int) $moderator] = (int) $moderator;
            }
            $boardOptions['moderators'] = $moderators;
        }
        // Are they doing redirection?
        $boardOptions['redirect'] = !empty($_POST['redirect_enable']) && isset($_POST['redirect_address']) && trim($_POST['redirect_address']) != '' ? trim($_POST['redirect_address']) : '';
        // Profiles...
        $boardOptions['profile'] = $_POST['profile'];
        $boardOptions['inherit_permissions'] = $_POST['profile'] == -1;
        // We need to know what used to be case in terms of redirection.
        if (!empty($_POST['boardid'])) {
            $request = smf_db_query('
				SELECT redirect, num_posts
				FROM {db_prefix}boards
				WHERE id_board = {int:current_board}', array('current_board' => $_POST['boardid']));
            list($oldRedirect, $numPosts) = mysql_fetch_row($request);
            mysql_free_result($request);
            // If we're turning redirection on check the board doesn't have posts in it - if it does don't make it a redirection board.
            if ($boardOptions['redirect'] && empty($oldRedirect) && $numPosts) {
                unset($boardOptions['redirect']);
            } elseif (empty($boardOptions['redirect']) != empty($oldRedirect)) {
                $boardOptions['num_posts'] = 0;
            } elseif ($boardOptions['redirect'] && !empty($_POST['reset_redirect'])) {
                $boardOptions['num_posts'] = 0;
            }
        }
        // Create a new board...
        if (isset($_POST['add'])) {
            // New boards by default go to the bottom of the category.
            if (empty($_POST['new_cat'])) {
                $boardOptions['target_category'] = (int) $_POST['cur_cat'];
            }
            if (!isset($boardOptions['move_to'])) {
                $boardOptions['move_to'] = 'bottom';
            }
            $boardOptions['allow_topics'] = 1;
            $boardOptions['automerge'] = 0;
            $boardOptions['icon'] = '';
            createBoard($boardOptions);
        } else {
            modifyBoard($_POST['boardid'], $boardOptions);
        }
    } elseif (isset($_POST['delete']) && !isset($_POST['confirmation']) && !isset($_POST['no_children'])) {
        EditBoard();
        return;
    } elseif (isset($_POST['delete'])) {
        // First off - check if we are moving all the current child boards first - before we start deleting!
        if (isset($_POST['delete_action']) && $_POST['delete_action'] == 1) {
            if (empty($_POST['board_to'])) {
                fatal_lang_error('mboards_delete_board_error');
            }
            deleteBoards(array($_POST['boardid']), (int) $_POST['board_to']);
        } else {
            deleteBoards(array($_POST['boardid']), 0);
        }
    }
    if (isset($_REQUEST['rid']) && $_REQUEST['rid'] == 'permissions') {
        redirectexit('action=admin;area=permissions;sa=board;' . $context['session_var'] . '=' . $context['session_id']);
    } else {
        redirectexit('action=admin;area=manageboards');
    }
}
Ejemplo n.º 15
0
function updateAdminPreferences()
{
    global $options, $context, $smcFunc, $settings, $user_info;
    // This must exist!
    if (!isset($context['admin_preferences'])) {
        return false;
    }
    // This is what we'll be saving.
    $options['admin_preferences'] = serialize($context['admin_preferences']);
    // Just check we haven't ended up with something theme exclusive somehow.
    smf_db_query('
		DELETE FROM {db_prefix}themes
		WHERE id_theme != {int:default_theme}
		AND variable = {string:admin_preferences}', array('default_theme' => 1, 'admin_preferences' => 'admin_preferences'));
    // Update the themes table.
    smf_db_insert('replace', '{db_prefix}themes', array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), array($user_info['id'], 1, 'admin_preferences', $options['admin_preferences']), array('id_member', 'id_theme', 'variable'));
    // Make sure we invalidate any cache.
    CacheAPI::putCache('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 0);
}
Ejemplo n.º 16
0
function makeThemeChanges($memID, $id_theme)
{
    global $modSettings, $smcFunc, $context;
    $reservedVars = array('actual_theme_url', 'actual_images_url', 'base_theme_dir', 'base_theme_url', 'default_images_url', 'default_theme_dir', 'default_theme_url', 'default_template', 'images_url', 'number_recent_posts', 'smiley_sets_default', 'theme_dir', 'theme_id', 'theme_layers', 'theme_templates', 'theme_url');
    // Can't change reserved vars.
    if (isset($_POST['options']) && array_intersect($_POST['options'], $reservedVars) != array() || isset($_POST['default_options']) && array_intersect($_POST['default_options'], $reservedVars) != array()) {
        fatal_lang_error('no_access', false);
    }
    // Don't allow any overriding of custom fields with default or non-default options.
    $request = smf_db_query('
		SELECT col_name
		FROM {db_prefix}custom_fields
		WHERE active = {int:is_active}', array('is_active' => 1));
    $custom_fields = array();
    while ($row = mysql_fetch_assoc($request)) {
        $custom_fields[] = $row['col_name'];
    }
    mysql_free_result($request);
    // These are the theme changes...
    $themeSetArray = array();
    if (isset($_POST['options']) && is_array($_POST['options'])) {
        foreach ($_POST['options'] as $opt => $val) {
            if (in_array($opt, $custom_fields)) {
                continue;
            }
            // These need to be controlled.
            if ($opt == 'topics_per_page' || $opt == 'messages_per_page') {
                $val = max(0, min($val, 50));
            }
            $themeSetArray[] = array($memID, $id_theme, $opt, is_array($val) ? implode(',', $val) : $val);
        }
    }
    $erase_options = array();
    if (isset($_POST['default_options']) && is_array($_POST['default_options'])) {
        foreach ($_POST['default_options'] as $opt => $val) {
            if (in_array($opt, $custom_fields)) {
                continue;
            }
            // These need to be controlled.
            if ($opt == 'topics_per_page' || $opt == 'messages_per_page') {
                $val = max(0, min($val, 50));
            }
            $themeSetArray[] = array($memID, 1, $opt, is_array($val) ? implode(',', $val) : $val);
            $erase_options[] = $opt;
        }
    }
    // If themeSetArray isn't still empty, send it to the database.
    if (empty($context['password_auth_failed'])) {
        if (!empty($themeSetArray)) {
            smf_db_insert('replace', '{db_prefix}themes', array('id_member' => 'int', 'id_theme' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), $themeSetArray, array('id_member', 'id_theme', 'variable'));
        }
        if (!empty($erase_options)) {
            smf_db_query('
				DELETE FROM {db_prefix}themes
				WHERE id_theme != {int:id_theme}
					AND variable IN ({array_string:erase_variables})
					AND id_member = {int:id_member}', array('id_theme' => 1, 'id_member' => $memID, 'erase_variables' => $erase_options));
        }
        $themes = explode(',', $modSettings['knownThemes']);
        foreach ($themes as $t) {
            CacheAPI::putCache('theme_settings-' . $t . ':' . $memID, null, 60);
        }
    }
}
Ejemplo n.º 17
0
function ModifySpamSettings($return_config = false)
{
    global $txt, $scripturl, $context, $settings, $sc, $modSettings, $smcFunc;
    // Generate a sample registration image.
    $context['use_graphic_library'] = in_array('gd', get_loaded_extensions());
    $context['verification_image_href'] = $scripturl . '?action=verificationcode;rand=' . md5(mt_rand());
    $config_vars = array(array('check', 'reg_verification'), array('check', 'search_enable_captcha'), 'guest_verify' => array('check', 'guests_require_captcha', 'subtext' => $txt['setting_guests_require_captcha_desc']), array('int', 'posts_require_captcha', 'subtext' => $txt['posts_require_captcha_desc'], 'onchange' => 'if (this.value > 0){ document.getElementById(\'guests_require_captcha\').checked = true; document.getElementById(\'guests_require_captcha\').disabled = true;} else {document.getElementById(\'guests_require_captcha\').disabled = false;}'), array('check', 'guests_report_require_captcha'), '', 'pm1' => array('int', 'max_pm_recipients'), 'pm2' => array('int', 'pm_posts_verification'), 'pm3' => array('int', 'pm_posts_per_hour'), array('title', 'configure_verification_means'), array('desc', 'configure_verification_means_desc'), 'vv' => array('select', 'visual_verification_type', array($txt['setting_image_verification_off'], $txt['setting_image_verification_vsimple'], $txt['setting_image_verification_simple'], $txt['setting_image_verification_medium'], $txt['setting_image_verification_high'], $txt['setting_image_verification_extreme']), 'subtext' => $txt['setting_visual_verification_type_desc'], 'onchange' => $context['use_graphic_library'] ? 'refreshImages();' : ''), array('int', 'qa_verification_number', 'subtext' => $txt['setting_qa_verification_number_desc']), array('title', 'setup_verification_questions'), array('desc', 'setup_verification_questions_desc'), array('callback', 'question_answer_list'));
    if ($return_config) {
        return $config_vars;
    }
    // Load any question and answers!
    $context['question_answers'] = array();
    $request = smf_db_query('
		SELECT id_comment, body AS question, recipient_name AS answer
		FROM {db_prefix}log_comments
		WHERE comment_type = {string:ver_test}', array('ver_test' => 'ver_test'));
    while ($row = mysql_fetch_assoc($request)) {
        $context['question_answers'][$row['id_comment']] = array('id' => $row['id_comment'], 'question' => $row['question'], 'answer' => $row['answer']);
    }
    mysql_free_result($request);
    // Saving?
    if (isset($_GET['save'])) {
        checkSession();
        // Fix PM settings.
        $_POST['pm_spam_settings'] = (int) $_POST['max_pm_recipients'] . ',' . (int) $_POST['pm_posts_verification'] . ',' . (int) $_POST['pm_posts_per_hour'];
        // Hack in guest requiring verification!
        if (empty($_POST['posts_require_captcha']) && !empty($_POST['guests_require_captcha'])) {
            $_POST['posts_require_captcha'] = -1;
        }
        $save_vars = $config_vars;
        unset($save_vars['pm1'], $save_vars['pm2'], $save_vars['pm3'], $save_vars['guest_verify']);
        $save_vars[] = array('text', 'pm_spam_settings');
        // Handle verification questions.
        $questionInserts = array();
        $count_questions = 0;
        foreach ($_POST['question'] as $id => $question) {
            $question = trim(commonAPI::htmlspecialchars($question, ENT_COMPAT));
            $answer = trim(commonAPI::strtolower(commonAPI::htmlspecialchars($_POST['answer'][$id], ENT_COMPAT)));
            // Already existed?
            if (isset($context['question_answers'][$id])) {
                $count_questions++;
                // Changed?
                if ($context['question_answers'][$id]['question'] != $question || $context['question_answers'][$id]['answer'] != $answer) {
                    if ($question == '' || $answer == '') {
                        smf_db_query('
							DELETE FROM {db_prefix}log_comments
							WHERE comment_type = {string:ver_test}
								AND id_comment = {int:id}', array('id' => $id, 'ver_test' => 'ver_test'));
                        $count_questions--;
                    } else {
                        $request = smf_db_query('
							UPDATE {db_prefix}log_comments
							SET body = {string:question}, recipient_name = {string:answer}
							WHERE comment_type = {string:ver_test}
								AND id_comment = {int:id}', array('id' => $id, 'ver_test' => 'ver_test', 'question' => $question, 'answer' => $answer));
                    }
                }
            } elseif ($question != '' && $answer != '') {
                $questionInserts[] = array('comment_type' => 'ver_test', 'body' => $question, 'recipient_name' => $answer);
            }
        }
        // Any questions to insert?
        if (!empty($questionInserts)) {
            smf_db_insert('', '{db_prefix}log_comments', array('comment_type' => 'string', 'body' => 'string-65535', 'recipient_name' => 'string-80'), $questionInserts, array('id_comment'));
            $count_questions++;
        }
        if (empty($count_questions) || $_POST['qa_verification_number'] > $count_questions) {
            $_POST['qa_verification_number'] = $count_questions;
        }
        // Now save.
        saveDBSettings($save_vars);
        CacheAPI::putCache('verificationQuestionIds', null, 300);
        redirectexit('action=admin;area=securitysettings;sa=spam');
    }
    $character_range = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P', 'R'), range('T', 'Y'));
    $_SESSION['visual_verification_code'] = '';
    for ($i = 0; $i < 6; $i++) {
        $_SESSION['visual_verification_code'] .= $character_range[array_rand($character_range)];
    }
    // Some javascript for CAPTCHA.
    $context['settings_post_javascript'] = '';
    if ($context['use_graphic_library']) {
        $context['settings_post_javascript'] .= '
		function refreshImages()
		{
			var imageType = document.getElementById(\'visual_verification_type\').value;
			document.getElementById(\'verification_image\').src = \'' . $context['verification_image_href'] . ';type=\' + imageType;
		}';
    }
    // Show the image itself, or text saying we can't.
    if ($context['use_graphic_library']) {
        $config_vars['vv']['postinput'] = '<br /><img src="' . $context['verification_image_href'] . ';type=' . (empty($modSettings['visual_verification_type']) ? 0 : $modSettings['visual_verification_type']) . '" alt="' . $txt['setting_image_verification_sample'] . '" id="verification_image" /><br />';
    } else {
        $config_vars['vv']['postinput'] = '<br /><span class="smalltext">' . $txt['setting_image_verification_nogd'] . '</span>';
    }
    // Hack for PM spam settings.
    list($modSettings['max_pm_recipients'], $modSettings['pm_posts_verification'], $modSettings['pm_posts_per_hour']) = explode(',', $modSettings['pm_spam_settings']);
    // Hack for guests requiring verification.
    $modSettings['guests_require_captcha'] = !empty($modSettings['posts_require_captcha']);
    $modSettings['posts_require_captcha'] = !isset($modSettings['posts_require_captcha']) || $modSettings['posts_require_captcha'] == -1 ? 0 : $modSettings['posts_require_captcha'];
    // Some minor javascript for the guest post setting.
    if ($modSettings['posts_require_captcha']) {
        $context['settings_post_javascript'] .= '
		document.getElementById(\'guests_require_captcha\').disabled = true;';
    }
    $context['post_url'] = $scripturl . '?action=admin;area=securitysettings;save;sa=spam';
    $context['settings_title'] = $txt['antispam_Settings'];
    prepareDBSettingContext($config_vars);
}
Ejemplo n.º 18
0
 public function searchQuery($search_params, $searchWords, $excludedIndexWords, &$participants, &$searchArray)
 {
     global $modSettings, $context, $sourcedir, $user_info, $scripturl;
     if (($cached_results = CacheAPI::getCache('search_results_' . md5($user_info['query_see_board'] . '_' . $context['params']))) === null) {
         require_once $sourcedir . '/contrib/sphinxapi.php';
         $mySphinx = new SphinxClient();
         $mySphinx->SetServer($modSettings['sphinx_searchd_server'], (int) $modSettings['sphinx_searchd_port']);
         $mySphinx->SetLimits(0, (int) $modSettings['sphinx_max_results']);
         $mySphinx->SetMatchMode(SPH_MATCH_BOOLEAN);
         if (!$search_params['show_complete']) {
             $mySphinx->SetGroupBy('ID_TOPIC', SPH_GROUPBY_ATTR);
         }
         $mySphinx->SetSortMode($search_params['sort_dir'] === 'asc' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, $search_params['sort'] === 'ID_MSG' ? 'ID_TOPIC' : $search_params['sort']);
         if (!empty($search_params['topic'])) {
             $mySphinx->SetFilter('ID_TOPIC', array((int) $search_params['topic']));
         }
         if (!empty($search_params['min_msg_id']) || !empty($search_params['max_msg_id'])) {
             $mySphinx->SetIDRange(empty($search_params['min_msg_id']) ? 0 : (int) $search_params['min_msg_id'], empty($search_params['max_msg_id']) ? (int) $modSettings['maxMsgID'] : (int) $search_params['max_msg_id']);
         }
         if (!empty($search_params['brd'])) {
             $mySphinx->SetFilter('ID_BOARD', $search_params['brd']);
         }
         if (!empty($search_params['prefix'])) {
             $mySphinx->SetFilter('ID_PREFIX', $search_params['prefix']);
         }
         if (!empty($search_params['memberlist'])) {
             $mySphinx->SetFilter('ID_MEMBER', $search_params['memberlist']);
         }
         $orResults = array();
         foreach ($searchWords as $orIndex => $words) {
             $andResult = '';
             foreach ($words['indexed_words'] as $sphinxWord) {
                 $andResult .= (in_array($sphinxWord, $excludedIndexWords) ? '-' : '') . $sphinxWord . ' & ';
             }
             $orResults[] = substr($andResult, 0, -3);
         }
         $query = count($orResults) === 1 ? $orResults[0] : '(' . implode(') | (', $orResults) . ')';
         // Execute the search query.
         $request = $mySphinx->Query($query, 'smf_index');
         // Can a connection to the deamon be made?
         if ($request === false) {
             fatal_lang_error('error_no_search_daemon');
         }
         // Get the relevant information from the search results.
         $cached_results = array('matches' => array(), 'num_results' => $request['total']);
         if (isset($request['matches'])) {
             foreach ($request['matches'] as $msgID => $match) {
                 $cached_results['matches'][$msgID] = array('id' => $match['attrs']['id_topic'], 'relevance' => round($match['attrs']['relevance'] / 10000, 1) . '%', 'matches' => array());
                 if (!$search_params['show_complete']) {
                     $cached_results['matches'][$msgID]['num_matches'] = $match['attrs']['@count'];
                 }
             }
         }
         CacheAPI::putCache('search_results_' . md5($user_info['query_see_board']) . '_' . $context['params'], $cached_results, 600);
     }
     foreach (array_slice(array_keys($cached_results['matches']), $_REQUEST['start'], $modSettings['search_results_per_page']) as $msgID) {
         $context['topics'][$msgID] = $cached_results['matches'][$msgID];
         $participants[$cached_results['matches'][$msgID]['id']] = false;
     }
     // Sentences need to be broken up in words for proper highlighting.
     foreach ($searchWords as $orIndex => $words) {
         $searchArray = array_merge($searchArray, $searchWords[$orIndex]['subject_words']);
     }
     // Now that we know how many results to expect we can start calculating the page numbers.
     $context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $cached_results['num_results'], $modSettings['search_results_per_page'], false);
     return $cached_results['num_results'];
 }
Ejemplo n.º 19
0
function Display()
{
    global $scripturl, $txt, $modSettings, $context, $settings, $memberContext, $output;
    global $options, $sourcedir, $user_info, $user_profile, $board_info, $topic, $board;
    global $attachments, $messages_request, $topicinfo, $language;
    $context['response_prefixlen'] = strlen($txt['response_prefix']);
    $context['need_synhlt'] = true;
    $context['is_display_std'] = true;
    $context['pcache_update_counter'] = !empty($modSettings['use_post_cache']) ? 0 : PCACHE_UPDATE_PER_VIEW + 1;
    $context['time_cutoff_ref'] = time();
    $context['template_hooks']['display'] = array('header' => '', 'extend_topicheader' => '', 'above_posts' => '', 'below_posts' => '', 'footer' => '');
    //EoS_Smarty::getConfigInstance()->registerHookTemplate('postbit_below', 'overrides/foo');
    if (!empty($modSettings['karmaMode'])) {
        require_once $sourcedir . '/lib/Subs-Ratings.php';
    } else {
        $context['can_see_like'] = $context['can_give_like'] = false;
    }
    // What are you gonna display if these are empty?!
    if (empty($topic)) {
        fatal_lang_error('no_board', false);
    }
    // Not only does a prefetch make things slower for the server, but it makes it impossible to know if they read it.
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Prefetch Forbidden');
        die;
    }
    // How much are we sticking on each page?
    $context['messages_per_page'] = commonAPI::getMessagesPerPage();
    $context['page_number'] = isset($_REQUEST['start']) ? $_REQUEST['start'] / $context['messages_per_page'] : 0;
    // Let's do some work on what to search index.
    //$context['multiquote_cookiename'] = 'mq_' . $context['current_topic'];
    $context['multiquote_posts'] = array();
    if (isset($_COOKIE[$context['multiquote_cookiename']]) && strlen($_COOKIE[$context['multiquote_cookiename']]) > 1) {
        $context['multiquote_posts'] = explode(',', $_COOKIE[$context['multiquote_cookiename']]);
    }
    $context['multiquote_posts_count'] = count($context['multiquote_posts']);
    if (count($_GET) > 2) {
        foreach ($_GET as $k => $v) {
            if (!in_array($k, array('topic', 'board', 'start', session_name()))) {
                $context['robot_no_index'] = true;
            }
        }
    }
    if (!empty($_REQUEST['start']) && (!is_numeric($_REQUEST['start']) || $_REQUEST['start'] % $context['messages_per_page'] != 0)) {
        $context['robot_no_index'] = true;
    }
    // Find the previous or next topic.  Make a fuss if there are no more.
    if (isset($_REQUEST['prev_next']) && ($_REQUEST['prev_next'] == 'prev' || $_REQUEST['prev_next'] == 'next')) {
        // No use in calculating the next topic if there's only one.
        if ($board_info['num_topics'] > 1) {
            // Just prepare some variables that are used in the query.
            $gt_lt = $_REQUEST['prev_next'] == 'prev' ? '>' : '<';
            $order = $_REQUEST['prev_next'] == 'prev' ? '' : ' DESC';
            $request = smf_db_query('
				SELECT t2.id_topic
				FROM {db_prefix}topics AS t
					INNER JOIN {db_prefix}topics AS t2 ON (' . (empty($modSettings['enableStickyTopics']) ? '
					t2.id_last_msg ' . $gt_lt . ' t.id_last_msg' : '
					(t2.id_last_msg ' . $gt_lt . ' t.id_last_msg AND t2.is_sticky ' . $gt_lt . '= t.is_sticky) OR t2.is_sticky ' . $gt_lt . ' t.is_sticky') . ')
				WHERE t.id_topic = {int:current_topic}
					AND t2.id_board = {int:current_board}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
					AND (t2.approved = {int:is_approved} OR (t2.id_member_started != {int:id_member_started} AND t2.id_member_started = {int:current_member}))') . '
				ORDER BY' . (empty($modSettings['enableStickyTopics']) ? '' : ' t2.is_sticky' . $order . ',') . ' t2.id_last_msg' . $order . '
				LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic, 'is_approved' => 1, 'id_member_started' => 0));
            // No more left.
            if (mysql_num_rows($request) == 0) {
                mysql_free_result($request);
                // Roll over - if we're going prev, get the last - otherwise the first.
                $request = smf_db_query('
					SELECT id_topic
					FROM {db_prefix}topics
					WHERE id_board = {int:current_board}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : '
						AND (approved = {int:is_approved} OR (id_member_started != {int:id_member_started} AND id_member_started = {int:current_member}))') . '
					ORDER BY' . (empty($modSettings['enableStickyTopics']) ? '' : ' is_sticky' . $order . ',') . ' id_last_msg' . $order . '
					LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'is_approved' => 1, 'id_member_started' => 0));
            }
            // Now you can be sure $topic is the id_topic to view.
            list($topic) = mysql_fetch_row($request);
            mysql_free_result($request);
            $context['current_topic'] = $topic;
        }
        // Go to the newest message on this topic.
        $_REQUEST['start'] = 'new';
    }
    // Add 1 to the number of views of this topic.
    if (empty($_SESSION['last_read_topic']) || $_SESSION['last_read_topic'] != $topic) {
        smf_db_query('
			UPDATE {db_prefix}topics
			SET num_views = num_views + 1
			WHERE id_topic = {int:current_topic}', array('current_topic' => $topic));
        $_SESSION['last_read_topic'] = $topic;
    }
    if ($modSettings['tags_active']) {
        $dbresult = smf_db_query('
		   SELECT t.tag,l.ID,t.ID_TAG FROM {db_prefix}tags_log as l, {db_prefix}tags as t
			WHERE t.ID_TAG = l.ID_TAG && l.ID_TOPIC = {int:topic}', array('topic' => $topic));
        $context['topic_tags'] = array();
        while ($row = mysql_fetch_assoc($dbresult)) {
            $context['topic_tags'][] = array('ID' => $row['ID'], 'ID_TAG' => $row['ID_TAG'], 'tag' => $row['tag']);
        }
        mysql_free_result($dbresult);
        $context['tags_active'] = true;
    } else {
        $context['topic_tags'] = $context['tags_active'] = 0;
    }
    // Get all the important topic info.
    $request = smf_db_query('SELECT
			t.num_replies, t.num_views, t.locked, ms.poster_name, ms.subject, ms.poster_email, ms.poster_time AS first_post_time, t.is_sticky, t.id_poll,
			t.id_member_started, t.id_first_msg, t.id_last_msg, t.approved, t.unapproved_posts, t.id_layout, 
			' . ($user_info['is_guest'] ? 't.id_last_msg + 1' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from
			' . (!empty($modSettings['recycle_board']) && $modSettings['recycle_board'] == $board ? ', id_previous_board, id_previous_topic' : '') . ',
			p.name AS prefix_name, ms1.poster_time AS last_post_time, ms1.modified_time AS last_modified_time, IFNULL(b.automerge, 0) AS automerge
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			INNER JOIN {db_prefix}messages AS ms1 ON (ms1.id_msg = t.id_last_msg)
			INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)' . ($user_info['is_guest'] ? '' : '
			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
			LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})') . '
			LEFT JOIN {db_prefix}prefixes as p ON p.id_prefix = t.id_prefix 
		WHERE t.id_topic = {int:current_topic}
		LIMIT 1', array('current_member' => $user_info['id'], 'current_topic' => $topic, 'current_board' => $board));
    if (mysql_num_rows($request) == 0) {
        fatal_lang_error('not_a_topic', false);
    }
    // Added by Related Topics
    if (isset($modSettings['have_related_topics']) && $modSettings['have_related_topics'] && !empty($modSettings['relatedTopicsEnabled'])) {
        require_once $sourcedir . '/lib/Subs-Related.php';
        loadRelated($topic);
    }
    $topicinfo = mysql_fetch_assoc($request);
    mysql_free_result($request);
    $context['topic_banned_members'] = array();
    $request = smf_db_query('SELECT id_member FROM {db_prefix}topicbans WHERE id_topic = {int:topic}', array('topic' => $topic));
    if (mysql_num_rows($request) != 0) {
        while ($row = mysql_fetch_row($request)) {
            $context['topic_banned_members'][] = $row[0];
        }
    }
    mysql_free_result($request);
    $context['topic_banned_members_count'] = count($context['topic_banned_members']);
    $context['topic_last_modified'] = max($topicinfo['last_post_time'], $topicinfo['last_modified_time']);
    // todo: considering - make post cutoff time for the cache depend on the modification time of the topic's last post
    $context['real_num_replies'] = $context['num_replies'] = $topicinfo['num_replies'];
    $context['topic_first_message'] = $topicinfo['id_first_msg'];
    $context['topic_last_message'] = $topicinfo['id_last_msg'];
    $context['first_subject'] = $topicinfo['subject'];
    $context['prefix'] = !empty($topicinfo['prefix_name']) ? html_entity_decode($topicinfo['prefix_name']) . '&nbsp;' : '';
    $context['automerge'] = $topicinfo['automerge'] > 0;
    // Add up unapproved replies to get real number of replies...
    if ($modSettings['postmod_active'] && allowedTo('approve_posts')) {
        $context['real_num_replies'] += $topicinfo['unapproved_posts'] - ($topicinfo['approved'] ? 0 : 1);
    }
    // If this topic has unapproved posts, we need to work out how many posts the user can see, for page indexing.
    if ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !$user_info['is_guest'] && !allowedTo('approve_posts')) {
        $request = smf_db_query('
			SELECT COUNT(id_member) AS my_unapproved_posts
			FROM {db_prefix}messages
			WHERE id_topic = {int:current_topic}
				AND id_member = {int:current_member}
				AND approved = 0', array('current_topic' => $topic, 'current_member' => $user_info['id']));
        list($myUnapprovedPosts) = mysql_fetch_row($request);
        mysql_free_result($request);
        $context['total_visible_posts'] = $context['num_replies'] + $myUnapprovedPosts + ($topicinfo['approved'] ? 1 : 0);
    } else {
        $context['total_visible_posts'] = $context['num_replies'] + $topicinfo['unapproved_posts'] + ($topicinfo['approved'] ? 1 : 0);
    }
    // When was the last time this topic was replied to?  Should we warn them about it?
    /* redundant query? last_post_time is already in $topicinfo[]
    	$request = smf_db_query( '
    		SELECT poster_time
    		FROM {db_prefix}messages
    		WHERE id_msg = {int:id_last_msg}
    		LIMIT 1',
    		array(
    			'id_last_msg' => $topicinfo['id_last_msg'],
    		)
    	);
    
    	list ($lastPostTime) = mysql_fetch_row($request);
    	mysql_free_result($request);
    	*/
    $lastPostTime = $topicinfo['last_post_time'];
    $context['oldTopicError'] = !empty($modSettings['oldTopicDays']) && $lastPostTime + $modSettings['oldTopicDays'] * 86400 < time() && empty($sticky);
    // The start isn't a number; it's information about what to do, where to go.
    if (!is_numeric($_REQUEST['start'])) {
        // Redirect to the page and post with new messages, originally by Omar Bazavilvazo.
        if ($_REQUEST['start'] == 'new') {
            // Guests automatically go to the last post.
            if ($user_info['is_guest']) {
                $context['start_from'] = $context['total_visible_posts'] - 1;
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : 0;
            } else {
                // Find the earliest unread message in the topic. (the use of topics here is just for both tables.)
                $request = smf_db_query('
					SELECT IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1 AS new_from
					FROM {db_prefix}topics AS t
						LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
						LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})
					WHERE t.id_topic = {int:current_topic}
					LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic));
                list($new_from) = mysql_fetch_row($request);
                mysql_free_result($request);
                // Fall through to the next if statement.
                $_REQUEST['start'] = 'msg' . $new_from;
            }
        }
        // Start from a certain time index, not a message.
        if (substr($_REQUEST['start'], 0, 4) == 'from') {
            $timestamp = (int) substr($_REQUEST['start'], 4);
            if ($timestamp === 0) {
                $_REQUEST['start'] = 0;
            } else {
                // Find the number of messages posted before said time...
                $request = smf_db_query('
					SELECT COUNT(*)
					FROM {db_prefix}messages
					WHERE poster_time < {int:timestamp}
						AND id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts') ? '
						AND (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')' : ''), array('current_topic' => $topic, 'current_member' => $user_info['id'], 'is_approved' => 1, 'timestamp' => $timestamp));
                list($context['start_from']) = mysql_fetch_row($request);
                mysql_free_result($request);
                // Handle view_newest_first options, and get the correct start value.
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $context['total_visible_posts'] - $context['start_from'] - 1;
            }
        } elseif (substr($_REQUEST['start'], 0, 3) == 'msg') {
            $virtual_msg = (int) substr($_REQUEST['start'], 3);
            if (!$topicinfo['unapproved_posts'] && $virtual_msg >= $topicinfo['id_last_msg']) {
                $context['start_from'] = $context['total_visible_posts'] - 1;
            } elseif (!$topicinfo['unapproved_posts'] && $virtual_msg <= $topicinfo['id_first_msg']) {
                $context['start_from'] = 0;
            } else {
                // Find the start value for that message......
                $request = smf_db_query('
					SELECT COUNT(*)
					FROM {db_prefix}messages
					WHERE id_msg < {int:virtual_msg}
						AND id_topic = {int:current_topic}' . ($modSettings['postmod_active'] && $topicinfo['unapproved_posts'] && !allowedTo('approve_posts') ? '
						AND (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')' : ''), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'virtual_msg' => $virtual_msg, 'is_approved' => 1, 'no_member' => 0));
                list($context['start_from']) = mysql_fetch_row($request);
                mysql_free_result($request);
            }
            // We need to reverse the start as well in this case.
            if (isset($_REQUEST['perma'])) {
                $_REQUEST['start'] = $virtual_msg;
            } else {
                $_REQUEST['start'] = empty($options['view_newest_first']) ? $context['start_from'] : $context['total_visible_posts'] - $context['start_from'] - 1;
            }
        }
    }
    // Create a previous next string if the selected theme has it as a selected option.
    $context['previous_next'] = $modSettings['enablePreviousNext'] ? '<a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=prev#new">' . $txt['previous_next_back'] . '</a> <a href="' . $scripturl . '?topic=' . $topic . '.0;prev_next=next#new">' . $txt['previous_next_forward'] . '</a>' : '';
    // Do we need to show the visual verification image?
    $context['require_verification'] = !$user_info['is_mod'] && !$user_info['is_admin'] && !empty($modSettings['posts_require_captcha']) && ($user_info['posts'] < $modSettings['posts_require_captcha'] || $user_info['is_guest'] && $modSettings['posts_require_captcha'] == -1);
    if ($context['require_verification']) {
        require_once $sourcedir . '/lib/Subs-Editor.php';
        $verificationOptions = array('id' => 'post', 'skip_template' => true);
        $context['require_verification'] = create_control_verification($verificationOptions);
        $context['visual_verification_id'] = $verificationOptions['id'];
    }
    // Are we showing signatures - or disabled fields?
    $context['signature_enabled'] = substr($modSettings['signature_settings'], 0, 1) == 1;
    $context['disabled_fields'] = isset($modSettings['disabled_profile_fields']) ? array_flip(explode(',', $modSettings['disabled_profile_fields'])) : array();
    // Censor the title...
    censorText($topicinfo['subject']);
    $context['page_title'] = $topicinfo['subject'] . ((int) $context['page_number'] > 0 ? ' - ' . $txt['page'] . ' ' . ($context['page_number'] + 1) : '');
    // Is this topic sticky, or can it even be?
    $topicinfo['is_sticky'] = empty($modSettings['enableStickyTopics']) ? '0' : $topicinfo['is_sticky'];
    // Default this topic to not marked for notifications... of course...
    $context['is_marked_notify'] = false;
    // Did we report a post to a moderator just now?
    $context['report_sent'] = isset($_GET['reportsent']);
    // Let's get nosey, who is viewing this topic?
    if (!empty($settings['display_who_viewing'])) {
        // Start out with no one at all viewing it.
        $context['view_members'] = array();
        $context['view_members_list'] = array();
        $context['view_num_hidden'] = 0;
        // Search for members who have this topic set in their GET data.
        $request = smf_db_query('
			SELECT
				lo.id_member, lo.log_time, mem.real_name, mem.member_name, mem.show_online, mem.id_group, mem.id_post_group
			FROM {db_prefix}log_online AS lo
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lo.id_member)
			WHERE INSTR(lo.url, {string:in_url_string}) > 0 OR lo.session = {string:session}', array('in_url_string' => 's:5:"topic";i:' . $topic . ';', 'session' => $user_info['is_guest'] ? 'ip' . $user_info['ip'] : session_id()));
        while ($row = mysql_fetch_assoc($request)) {
            if (empty($row['id_member'])) {
                continue;
            }
            $class = 'member group_' . (empty($row['id_group']) ? $row['id_post_group'] : $row['id_group']) . (in_array($row['id_member'], $user_info['buddies']) ? ' buddy' : '');
            $href = URL::user($row['id_member'], $row['real_name']);
            if ($row['id_member'] == $user_info['id']) {
                $link = '<strong>' . $txt['you'] . '</strong>';
            } else {
                $link = '<a onclick="getMcard(' . $row['id_member'] . ');return(false);" class="' . $class . '" href="' . $href . '">' . $row['real_name'] . '</a>';
            }
            // Add them both to the list and to the more detailed list.
            if (!empty($row['show_online']) || allowedTo('moderate_forum')) {
                $context['view_members_list'][$row['log_time'] . $row['member_name']] = empty($row['show_online']) ? '<em>' . $link . '</em>' : $link;
            }
            $context['view_members'][$row['log_time'] . $row['member_name']] = array('id' => $row['id_member'], 'username' => $row['member_name'], 'name' => $row['real_name'], 'group' => $row['id_group'], 'href' => $href, 'link' => $link, 'hidden' => empty($row['show_online']));
            if (empty($row['show_online'])) {
                $context['view_num_hidden']++;
            }
        }
        // The number of guests is equal to the rows minus the ones we actually used ;).
        $context['view_num_guests'] = mysql_num_rows($request) - count($context['view_members']);
        mysql_free_result($request);
        // Sort the list.
        krsort($context['view_members']);
        krsort($context['view_members_list']);
    }
    // If all is set, but not allowed... just unset it.
    $can_show_all = !empty($modSettings['enableAllMessages']) && $context['total_visible_posts'] > $context['messages_per_page'] && $context['total_visible_posts'] < $modSettings['enableAllMessages'];
    if (isset($_REQUEST['all']) && !$can_show_all) {
        unset($_REQUEST['all']);
    } elseif (isset($_REQUEST['all'])) {
        $_REQUEST['start'] = -1;
    }
    // Construct the page index, allowing for the .START method...
    if (!isset($_REQUEST['perma'])) {
        $context['page_index'] = constructPageIndex(URL::topic($topic, $topicinfo['subject'], '%1$d'), $_REQUEST['start'], $context['total_visible_posts'], $context['messages_per_page'], true);
    }
    $context['start'] = $_REQUEST['start'];
    // This is information about which page is current, and which page we're on - in case you don't like the constructed page index. (again, wireles..)
    $context['page_info'] = array('current_page' => $_REQUEST['start'] / $context['messages_per_page'] + 1, 'num_pages' => floor(($context['total_visible_posts'] - 1) / $context['messages_per_page']) + 1);
    $context['links'] = array('first' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.0' : '', 'prev' => $_REQUEST['start'] >= $context['messages_per_page'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] - $context['messages_per_page']) : '', 'next' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . ($_REQUEST['start'] + $context['messages_per_page']) : '', 'last' => $_REQUEST['start'] + $context['messages_per_page'] < $context['total_visible_posts'] ? $scripturl . '?topic=' . $topic . '.' . floor($context['total_visible_posts'] / $context['messages_per_page']) * $context['messages_per_page'] : '', 'up' => $scripturl . '?board=' . $board . '.0');
    // If they are viewing all the posts, show all the posts, otherwise limit the number.
    if ($can_show_all) {
        if (isset($_REQUEST['all'])) {
            // No limit! (actually, there is a limit, but...)
            $context['messages_per_page'] = -1;
            $context['page_index'] .= '[<strong>' . $txt['all'] . '</strong>] ';
            // Set start back to 0...
            $_REQUEST['start'] = 0;
        } else {
            if (!isset($context['page_index'])) {
                $context['page_index'] = '';
            }
            $context['page_index'] .= '&nbsp;<a href="' . $scripturl . '?topic=' . $topic . '.0;all">' . $txt['all'] . '</a> ';
        }
    }
    // Build the link tree.
    $context['linktree'][] = array('url' => URL::topic($topic, $topicinfo['subject'], 0), 'name' => $topicinfo['subject'], 'extra_before' => $settings['linktree_inline'] ? $txt['topic'] . ': ' : '');
    // Build a list of this board's moderators.
    $context['moderators'] =& $board_info['moderators'];
    $context['link_moderators'] = array();
    if (!empty($board_info['moderators'])) {
        // Add a link for each moderator...
        foreach ($board_info['moderators'] as $mod) {
            $context['link_moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $mod['id'] . '" title="' . $txt['board_moderator'] . '">' . $mod['name'] . '</a>';
        }
        // And show it after the board's name.
        //$context['linktree'][count($context['linktree']) - 2]['extra_after'] = ' (' . (count($context['link_moderators']) == 1 ? $txt['moderator'] : $txt['moderators']) . ': ' . implode(', ', $context['link_moderators']) . ')';
    }
    // Information about the current topic...
    $context['is_locked'] = $topicinfo['locked'];
    $context['is_sticky'] = $topicinfo['is_sticky'];
    $context['is_very_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicVeryPosts'];
    $context['is_hot'] = $topicinfo['num_replies'] >= $modSettings['hotTopicPosts'];
    $context['is_approved'] = $topicinfo['approved'];
    // We don't want to show the poll icon in the topic class here, so pretend it's not one.
    $context['is_poll'] = false;
    determineTopicClass($context);
    $context['is_poll'] = $topicinfo['id_poll'] > 0 && $modSettings['pollMode'] == '1' && allowedTo('poll_view');
    // Did this user start the topic or not?
    $context['user']['started'] = $user_info['id'] == $topicinfo['id_member_started'] && !$user_info['is_guest'];
    $context['topic_starter_id'] = $topicinfo['id_member_started'];
    // Set the topic's information for the template.
    $context['subject'] = $topicinfo['subject'];
    $context['num_views'] = $topicinfo['num_views'];
    $context['mark_unread_time'] = $topicinfo['new_from'];
    // Set a canonical URL for this page.
    $context['canonical_url'] = URL::topic($topic, $topicinfo['subject'], $context['start']);
    $context['share_url'] = $scripturl . '?topic=' . $topic;
    // For quick reply we need a response prefix in the default forum language.
    if (!isset($context['response_prefix']) && !($context['response_prefix'] = CacheAPI::getCache('response_prefix', 600))) {
        if ($language === $user_info['language']) {
            $context['response_prefix'] = $txt['response_prefix'];
        } else {
            loadLanguage('index', $language, false);
            $context['response_prefix'] = $txt['response_prefix'];
            loadLanguage('index');
        }
        CacheAPI::putCache('response_prefix', $context['response_prefix'], 600);
    }
    // If we want to show event information in the topic, prepare the data.
    if (allowedTo('calendar_view') && !empty($modSettings['cal_showInTopic']) && !empty($modSettings['cal_enabled'])) {
        // First, try create a better time format, ignoring the "time" elements.
        if (preg_match('~%[AaBbCcDdeGghjmuYy](?:[^%]*%[AaBbCcDdeGghjmuYy])*~', $user_info['time_format'], $matches) == 0 || empty($matches[0])) {
            $date_string = $user_info['time_format'];
        } else {
            $date_string = $matches[0];
        }
        // Any calendar information for this topic?
        $request = smf_db_query('
			SELECT cal.id_event, cal.start_date, cal.end_date, cal.title, cal.id_member, mem.real_name
			FROM {db_prefix}calendar AS cal
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = cal.id_member)
			WHERE cal.id_topic = {int:current_topic}
			ORDER BY start_date', array('current_topic' => $topic));
        $context['linked_calendar_events'] = array();
        while ($row = mysql_fetch_assoc($request)) {
            // Prepare the dates for being formatted.
            $start_date = sscanf($row['start_date'], '%04d-%02d-%02d');
            $start_date = mktime(12, 0, 0, $start_date[1], $start_date[2], $start_date[0]);
            $end_date = sscanf($row['end_date'], '%04d-%02d-%02d');
            $end_date = mktime(12, 0, 0, $end_date[1], $end_date[2], $end_date[0]);
            $context['linked_calendar_events'][] = array('id' => $row['id_event'], 'title' => $row['title'], 'can_edit' => allowedTo('calendar_edit_any') || $row['id_member'] == $user_info['id'] && allowedTo('calendar_edit_own'), 'modify_href' => $scripturl . '?action=post;msg=' . $topicinfo['id_first_msg'] . ';topic=' . $topic . '.0;calendar;eventid=' . $row['id_event'] . ';' . $context['session_var'] . '=' . $context['session_id'], 'start_date' => timeformat_static($start_date, $date_string, 'none'), 'start_timestamp' => $start_date, 'end_date' => timeformat_static($end_date, $date_string, 'none'), 'end_timestamp' => $end_date, 'is_last' => false);
        }
        mysql_free_result($request);
        if (!empty($context['linked_calendar_events'])) {
            $context['linked_calendar_events'][count($context['linked_calendar_events']) - 1]['is_last'] = true;
        }
    }
    // Create the poll info if it exists.
    if ($context['is_poll']) {
        // Get the question and if it's locked.
        $request = smf_db_query('
			SELECT
				p.question, p.voting_locked, p.hide_results, p.expire_time, p.max_votes, p.change_vote,
				p.guest_vote, p.id_member, IFNULL(mem.real_name, p.poster_name) AS poster_name, p.num_guest_voters, p.reset_poll
			FROM {db_prefix}polls AS p
				LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = p.id_member)
			WHERE p.id_poll = {int:id_poll}
			LIMIT 1', array('id_poll' => $topicinfo['id_poll']));
        $pollinfo = mysql_fetch_assoc($request);
        mysql_free_result($request);
        $request = smf_db_query('
			SELECT COUNT(DISTINCT id_member) AS total
			FROM {db_prefix}log_polls
			WHERE id_poll = {int:id_poll}
				AND id_member != {int:not_guest}', array('id_poll' => $topicinfo['id_poll'], 'not_guest' => 0));
        list($pollinfo['total']) = mysql_fetch_row($request);
        mysql_free_result($request);
        // Total voters needs to include guest voters
        $pollinfo['total'] += $pollinfo['num_guest_voters'];
        // Get all the options, and calculate the total votes.
        $request = smf_db_query('
			SELECT pc.id_choice, pc.label, pc.votes, IFNULL(lp.id_choice, -1) AS voted_this
			FROM {db_prefix}poll_choices AS pc
				LEFT JOIN {db_prefix}log_polls AS lp ON (lp.id_choice = pc.id_choice AND lp.id_poll = {int:id_poll} AND lp.id_member = {int:current_member} AND lp.id_member != {int:not_guest})
			WHERE pc.id_poll = {int:id_poll}', array('current_member' => $user_info['id'], 'id_poll' => $topicinfo['id_poll'], 'not_guest' => 0));
        $pollOptions = array();
        $realtotal = 0;
        $pollinfo['has_voted'] = false;
        while ($row = mysql_fetch_assoc($request)) {
            censorText($row['label']);
            $pollOptions[$row['id_choice']] = $row;
            $realtotal += $row['votes'];
            $pollinfo['has_voted'] |= $row['voted_this'] != -1;
        }
        mysql_free_result($request);
        // If this is a guest we need to do our best to work out if they have voted, and what they voted for.
        if ($user_info['is_guest'] && $pollinfo['guest_vote'] && allowedTo('poll_vote')) {
            if (!empty($_COOKIE['guest_poll_vote']) && preg_match('~^[0-9,;]+$~', $_COOKIE['guest_poll_vote']) && strpos($_COOKIE['guest_poll_vote'], ';' . $topicinfo['id_poll'] . ',') !== false) {
                // ;id,timestamp,[vote,vote...]; etc
                $guestinfo = explode(';', $_COOKIE['guest_poll_vote']);
                // Find the poll we're after.
                foreach ($guestinfo as $i => $guestvoted) {
                    $guestvoted = explode(',', $guestvoted);
                    if ($guestvoted[0] == $topicinfo['id_poll']) {
                        break;
                    }
                }
                // Has the poll been reset since guest voted?
                if ($pollinfo['reset_poll'] > $guestvoted[1]) {
                    // Remove the poll info from the cookie to allow guest to vote again
                    unset($guestinfo[$i]);
                    if (!empty($guestinfo)) {
                        $_COOKIE['guest_poll_vote'] = ';' . implode(';', $guestinfo);
                    } else {
                        unset($_COOKIE['guest_poll_vote']);
                    }
                } else {
                    // What did they vote for?
                    unset($guestvoted[0], $guestvoted[1]);
                    foreach ($pollOptions as $choice => $details) {
                        $pollOptions[$choice]['voted_this'] = in_array($choice, $guestvoted) ? 1 : -1;
                        $pollinfo['has_voted'] |= $pollOptions[$choice]['voted_this'] != -1;
                    }
                    unset($choice, $details, $guestvoted);
                }
                unset($guestinfo, $guestvoted, $i);
            }
        }
        // Set up the basic poll information.
        $context['poll'] = array('id' => $topicinfo['id_poll'], 'image' => 'normal_' . (empty($pollinfo['voting_locked']) ? 'poll' : 'locked_poll'), 'question' => parse_bbc($pollinfo['question']), 'total_votes' => $pollinfo['total'], 'change_vote' => !empty($pollinfo['change_vote']), 'is_locked' => !empty($pollinfo['voting_locked']), 'options' => array(), 'lock' => allowedTo('poll_lock_any') || $context['user']['started'] && allowedTo('poll_lock_own'), 'edit' => allowedTo('poll_edit_any') || $context['user']['started'] && allowedTo('poll_edit_own'), 'allowed_warning' => $pollinfo['max_votes'] > 1 ? sprintf($txt['poll_options6'], min(count($pollOptions), $pollinfo['max_votes'])) : '', 'is_expired' => !empty($pollinfo['expire_time']) && $pollinfo['expire_time'] < time(), 'expire_time' => !empty($pollinfo['expire_time']) ? timeformat($pollinfo['expire_time']) : 0, 'has_voted' => !empty($pollinfo['has_voted']), 'starter' => array('id' => $pollinfo['id_member'], 'name' => $row['poster_name'], 'href' => $pollinfo['id_member'] == 0 ? '' : $scripturl . '?action=profile;u=' . $pollinfo['id_member'], 'link' => $pollinfo['id_member'] == 0 ? $row['poster_name'] : '<a href="' . $scripturl . '?action=profile;u=' . $pollinfo['id_member'] . '">' . $row['poster_name'] . '</a>'));
        // Make the lock and edit permissions defined above more directly accessible.
        $context['allow_lock_poll'] = $context['poll']['lock'];
        $context['allow_edit_poll'] = $context['poll']['edit'];
        // You're allowed to vote if:
        // 1. the poll did not expire, and
        // 2. you're either not a guest OR guest voting is enabled... and
        // 3. you're not trying to view the results, and
        // 4. the poll is not locked, and
        // 5. you have the proper permissions, and
        // 6. you haven't already voted before.
        $context['allow_vote'] = !$context['poll']['is_expired'] && (!$user_info['is_guest'] || $pollinfo['guest_vote'] && allowedTo('poll_vote')) && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && !$context['poll']['has_voted'];
        // You're allowed to view the results if:
        // 1. you're just a super-nice-guy, or
        // 2. anyone can see them (hide_results == 0), or
        // 3. you can see them after you voted (hide_results == 1), or
        // 4. you've waited long enough for the poll to expire. (whether hide_results is 1 or 2.)
        $context['allow_poll_view'] = allowedTo('moderate_board') || $pollinfo['hide_results'] == 0 || $pollinfo['hide_results'] == 1 && $context['poll']['has_voted'] || $context['poll']['is_expired'];
        $context['poll']['show_results'] = $context['allow_poll_view'] && (isset($_REQUEST['viewresults']) || isset($_REQUEST['viewResults']));
        $context['show_view_results_button'] = $context['allow_vote'] && (!$context['allow_poll_view'] || !$context['poll']['show_results'] || !$context['poll']['has_voted']);
        // You're allowed to change your vote if:
        // 1. the poll did not expire, and
        // 2. you're not a guest... and
        // 3. the poll is not locked, and
        // 4. you have the proper permissions, and
        // 5. you have already voted, and
        // 6. the poll creator has said you can!
        $context['allow_change_vote'] = !$context['poll']['is_expired'] && !$user_info['is_guest'] && empty($pollinfo['voting_locked']) && allowedTo('poll_vote') && $context['poll']['has_voted'] && $context['poll']['change_vote'];
        // You're allowed to return to voting options if:
        // 1. you are (still) allowed to vote.
        // 2. you are currently seeing the results.
        $context['allow_return_vote'] = $context['allow_vote'] && $context['poll']['show_results'];
        // Calculate the percentages and bar lengths...
        $divisor = $realtotal == 0 ? 1 : $realtotal;
        // Determine if a decimal point is needed in order for the options to add to 100%.
        $precision = $realtotal == 100 ? 0 : 1;
        // Now look through each option, and...
        foreach ($pollOptions as $i => $option) {
            // First calculate the percentage, and then the width of the bar...
            $bar = round($option['votes'] * 100 / $divisor, $precision);
            $barWide = $bar == 0 ? 1 : floor($bar * 8 / 3);
            // Now add it to the poll's contextual theme data.
            $context['poll']['options'][$i] = array('id' => 'options-' . $i, 'percent' => $bar, 'votes' => $option['votes'], 'voted_this' => $option['voted_this'] != -1, 'bar' => '<span style="white-space: nowrap;"><img src="' . $settings['images_url'] . '/poll_' . ($context['right_to_left'] ? 'right' : 'left') . '.gif" alt="" /><img src="' . $settings['images_url'] . '/poll_middle.gif" width="' . $barWide . '" height="12" alt="-" /><img src="' . $settings['images_url'] . '/poll_' . ($context['right_to_left'] ? 'left' : 'right') . '.gif" alt="" /></span>', 'bar_ndt' => $bar > 0 ? '<div class="bar" style="width: ' . ($bar * 3.5 + 4) . 'px;"></div>' : '', 'bar_width' => $barWide, 'option' => parse_bbc($option['label']), 'vote_button' => '<input type="' . ($pollinfo['max_votes'] > 1 ? 'checkbox' : 'radio') . '" name="options[]" id="options-' . $i . '" value="' . $i . '" class="input_' . ($pollinfo['max_votes'] > 1 ? 'check' : 'radio') . '" />');
        }
    }
    // Calculate the fastest way to get the messages!
    $ascending = empty($options['view_newest_first']);
    $start = $_REQUEST['start'];
    $limit = $context['messages_per_page'];
    $firstIndex = 0;
    if ($start >= $context['total_visible_posts'] / 2 && $context['messages_per_page'] != -1) {
        $ascending = !$ascending;
        $limit = $context['total_visible_posts'] <= $start + $limit ? $context['total_visible_posts'] - $start : $limit;
        $start = $context['total_visible_posts'] <= $start + $limit ? 0 : $context['total_visible_posts'] - $start - $limit;
        $firstIndex = $limit - 1;
    }
    if (!isset($_REQUEST['perma'])) {
        // Get each post and poster in this topic.
        $request = smf_db_query('
			SELECT id_msg, id_member, approved
			FROM {db_prefix}messages
			WHERE id_topic = {int:current_topic}' . (!$modSettings['postmod_active'] || allowedTo('approve_posts') ? '' : (!empty($modSettings['db_mysql_group_by_fix']) ? '' : '
			GROUP BY id_msg') . '
			HAVING (approved = {int:is_approved}' . ($user_info['is_guest'] ? '' : ' OR id_member = {int:current_member}') . ')') . '
			ORDER BY id_msg ' . ($ascending ? '' : 'DESC') . ($context['messages_per_page'] == -1 ? '' : '
			LIMIT ' . $start . ', ' . $limit), array('current_member' => $user_info['id'], 'current_topic' => $topic, 'is_approved' => 1, 'blank_id_member' => 0));
        $messages = array();
        $all_posters = array();
        while ($row = mysql_fetch_assoc($request)) {
            if (!empty($row['id_member'])) {
                $all_posters[$row['id_msg']] = $row['id_member'];
            }
            $messages[] = $row['id_msg'];
        }
        mysql_free_result($request);
        $posters[$context['topic_first_message']] = $context['topic_starter_id'];
        $posters = array_unique($all_posters);
    } else {
        $request = smf_db_query('
			SELECT id_member, approved
			FROM {db_prefix}messages
			WHERE id_msg = {int:id_msg}', array('id_msg' => $virtual_msg));
        list($id_member, $approved) = mysql_fetch_row($request);
        mysql_free_result($request);
        EoS_Smarty::loadTemplate('topic/topic_singlepost');
        //loadTemplate('DisplaySingle');
        $context['sub_template'] = isset($_REQUEST['xml']) ? 'single_post_xml' : 'single_post';
        if (isset($_REQUEST['xml'])) {
            $context['template_layers'] = array();
            header('Content-Type: text/xml; charset=UTF-8');
        }
        $messages = array($virtual_msg);
        $posters[$virtual_msg] = $id_member;
    }
    // Guests can't mark topics read or for notifications, just can't sorry.
    if (!$user_info['is_guest']) {
        $mark_at_msg = max($messages);
        if ($mark_at_msg >= $topicinfo['id_last_msg']) {
            $mark_at_msg = $modSettings['maxMsgID'];
        }
        if ($mark_at_msg >= $topicinfo['new_from']) {
            smf_db_insert($topicinfo['new_from'] == 0 ? 'ignore' : 'replace', '{db_prefix}log_topics', array('id_member' => 'int', 'id_topic' => 'int', 'id_msg' => 'int'), array($user_info['id'], $topic, $mark_at_msg), array('id_member', 'id_topic'));
        }
        // Check for notifications on this topic OR board.
        $request = smf_db_query('
			SELECT sent, id_topic
			FROM {db_prefix}log_notify
			WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
				AND id_member = {int:current_member}
			LIMIT 2', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic));
        $do_once = true;
        while ($row = mysql_fetch_assoc($request)) {
            // Find if this topic is marked for notification...
            if (!empty($row['id_topic'])) {
                $context['is_marked_notify'] = true;
            }
            // Only do this once, but mark the notifications as "not sent yet" for next time.
            if (!empty($row['sent']) && $do_once) {
                smf_db_query('
					UPDATE {db_prefix}log_notify
					SET sent = {int:is_not_sent}
					WHERE (id_topic = {int:current_topic} OR id_board = {int:current_board})
						AND id_member = {int:current_member}', array('current_board' => $board, 'current_member' => $user_info['id'], 'current_topic' => $topic, 'is_not_sent' => 0));
                $do_once = false;
            }
        }
        // Have we recently cached the number of new topics in this board, and it's still a lot?
        if (isset($_REQUEST['topicseen']) && isset($_SESSION['topicseen_cache'][$board]) && $_SESSION['topicseen_cache'][$board] > 5) {
            $_SESSION['topicseen_cache'][$board]--;
        } elseif (isset($_REQUEST['topicseen'])) {
            // Use the mark read tables... and the last visit to figure out if this should be read or not.
            $request = smf_db_query('
				SELECT COUNT(*)
				FROM {db_prefix}topics AS t
					LEFT JOIN {db_prefix}log_boards AS lb ON (lb.id_board = {int:current_board} AND lb.id_member = {int:current_member})
					LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = t.id_topic AND lt.id_member = {int:current_member})
				WHERE t.id_board = {int:current_board}
					AND t.id_last_msg > IFNULL(lb.id_msg, 0)
					AND t.id_last_msg > IFNULL(lt.id_msg, 0)' . (empty($_SESSION['id_msg_last_visit']) ? '' : '
					AND t.id_last_msg > {int:id_msg_last_visit}'), array('current_board' => $board, 'current_member' => $user_info['id'], 'id_msg_last_visit' => (int) $_SESSION['id_msg_last_visit']));
            list($numNewTopics) = mysql_fetch_row($request);
            mysql_free_result($request);
            // If there're no real new topics in this board, mark the board as seen.
            if (empty($numNewTopics)) {
                $_REQUEST['boardseen'] = true;
            } else {
                $_SESSION['topicseen_cache'][$board] = $numNewTopics;
            }
        } elseif (isset($_SESSION['topicseen_cache'][$board])) {
            $_SESSION['topicseen_cache'][$board]--;
        }
        // Mark board as seen if we came using last post link from BoardIndex. (or other places...)
        if (isset($_REQUEST['boardseen'])) {
            smf_db_insert('replace', '{db_prefix}log_boards', array('id_msg' => 'int', 'id_member' => 'int', 'id_board' => 'int'), array($modSettings['maxMsgID'], $user_info['id'], $board), array('id_member', 'id_board'));
        }
    }
    $attachments = array();
    // deal with possible sticky posts and different postbit layouts for
    // the first post
    // topic.id_layout meanings: bit 0-6 > layout id, bit 7 > first post sticky on every page.
    // don't blame me for using bit magic here. I'm a C guy and a 8bits can store more than just one bool :P
    $layout = (int) ($topicinfo['id_layout'] & 0x7f);
    $postbit_classes =& EoS_Smarty::getConfigInstance()->getPostbitClasses();
    // set defaults...
    $context['postbit_callbacks'] = array('firstpost' => 'template_postbit_normal', 'post' => 'template_postbit_normal');
    $context['postbit_template_class'] = array('firstpost' => $postbit_classes['normal'], 'post' => $postbit_classes['normal']);
    if ($topicinfo['id_layout']) {
        $this_start = isset($_REQUEST['perma']) ? 0 : (int) $_REQUEST['start'];
        if ((int) $topicinfo['id_layout'] & 0x80) {
            if ($this_start > 0) {
                array_unshift($messages, intval($topicinfo['id_first_msg']));
            }
            $context['postbit_callbacks']['firstpost'] = $layout == 0 ? 'template_postbit_normal' : ($layout == 2 ? 'template_postbit_clean' : 'template_postbit_lean');
            $context['postbit_callbacks']['post'] = $layout == 2 ? 'template_postbit_comment' : 'template_postbit_normal';
            $context['postbit_template_class']['firstpost'] = $layout == 0 ? $postbit_classes['normal'] : ($layout == 2 ? $postbit_classes['article'] : $postbit_classes['lean']);
            $context['postbit_template_class']['post'] = $layout == 2 ? $postbit_classes['commentstyle'] : $postbit_classes['normal'];
        } elseif ($layout) {
            $context['postbit_callbacks']['firstpost'] = $layout == 0 || $this_start != 0 ? 'template_postbit_normal' : ($layout == 2 ? 'template_postbit_clean' : 'template_postbit_lean');
            $context['postbit_callbacks']['post'] = $layout == 2 ? 'template_postbit_comment' : 'template_postbit_normal';
            $context['postbit_template_class']['firstpost'] = $layout == 0 || $this_start != 0 ? $postbit_classes['normal'] : ($layout == 2 ? $postbit_classes['article'] : $postbit_classes['lean']);
            $context['postbit_template_class']['post'] = $layout == 2 ? $postbit_classes['commentstyle'] : $postbit_classes['normal'];
        }
    }
    // now we know which display template we need
    if (!isset($_REQUEST['perma'])) {
        EoS_Smarty::loadTemplate($layout > 1 ? 'topic/topic_page' : 'topic/topic');
    }
    /*
    if($user_info['is_admin']) {
    	EoS_Smarty::init();
    	if(!isset($_REQUEST['perma']))
    		EoS_Smarty::loadTemplate($layout > 1 ? 'topic_page' : 'topic');
    }
    else {
    	if(!isset($_REQUEST['perma']))
    		loadTemplate($layout > 1 ? 'DisplayPage' : 'Display');
    	loadTemplate('Postbit');
    }
    */
    // If there _are_ messages here... (probably an error otherwise :!)
    if (!empty($messages)) {
        // Fetch attachments.
        if (!empty($modSettings['attachmentEnable']) && allowedTo('view_attachments')) {
            $request = smf_db_query('
				SELECT
					a.id_attach, a.id_folder, a.id_msg, a.filename, a.file_hash, IFNULL(a.size, 0) AS filesize, a.downloads, a.approved,
					a.width, a.height' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : ',
					IFNULL(thumb.id_attach, 0) AS id_thumb, thumb.width AS thumb_width, thumb.height AS thumb_height') . '
				FROM {db_prefix}attachments AS a' . (empty($modSettings['attachmentShowImages']) || empty($modSettings['attachmentThumbnails']) ? '' : '
					LEFT JOIN {db_prefix}attachments AS thumb ON (thumb.id_attach = a.id_thumb)') . '
				WHERE a.id_msg IN ({array_int:message_list})
					AND a.attachment_type = {int:attachment_type}', array('message_list' => $messages, 'attachment_type' => 0, 'is_approved' => 1));
            $temp = array();
            while ($row = mysql_fetch_assoc($request)) {
                if (!$row['approved'] && $modSettings['postmod_active'] && !allowedTo('approve_posts') && (!isset($all_posters[$row['id_msg']]) || $all_posters[$row['id_msg']] != $user_info['id'])) {
                    continue;
                }
                $temp[$row['id_attach']] = $row;
                if (!isset($attachments[$row['id_msg']])) {
                    $attachments[$row['id_msg']] = array();
                }
            }
            mysql_free_result($request);
            // This is better than sorting it with the query...
            ksort($temp);
            foreach ($temp as $row) {
                $attachments[$row['id_msg']][] = $row;
            }
        }
        // What?  It's not like it *couldn't* be only guests in this topic...
        if (!isset($posters[$context['topic_starter_id']])) {
            $posters[] = $context['topic_starter_id'];
        }
        if (!empty($posters)) {
            loadMemberData($posters);
        }
        if (!isset($user_profile[$context['topic_starter_id']])) {
            $context['topicstarter']['name'] = $topicinfo['poster_name'];
            $context['topicstarter']['id'] = 0;
            $context['topicstarter']['group'] = $txt['guest_title'];
            $context['topicstarter']['link'] = $topicinfo['poster_name'];
            $context['topicstarter']['email'] = $topicinfo['poster_email'];
            $context['topicstarter']['show_email'] = showEmailAddress(true, 0);
            $context['topicstarter']['is_guest'] = true;
            $context['topicstarter']['avatar'] = array();
        } else {
            loadMemberContext($context['topic_starter_id'], true);
            $context['topicstarter'] =& $memberContext[$context['topic_starter_id']];
        }
        $context['topicstarter']['start_time'] = timeformat($topicinfo['first_post_time']);
        $sql_what = '
			m.id_msg, m.icon, m.subject, m.poster_time, m.poster_ip, m.id_member, m.modified_time, m.modified_name, m.body, mc.body AS cached_body,
			m.smileys_enabled, m.poster_name, m.poster_email, m.approved, m.locked,' . (!empty($modSettings['karmaMode']) ? 'c.likes_count, c.like_status, c.updated AS like_updated, l.rtype AS liked,' : '0 AS likes_count, 0 AS like_status, 0 AS like_updated, 0 AS liked,') . '
			m.id_msg_modified < {int:new_from} AS is_read';
        $sql_from_tables = '
			FROM {db_prefix}messages AS m';
        $sql_from_joins = (!empty($modSettings['karmaMode']) ? '
			LEFT JOIN {db_prefix}likes AS l ON (l.id_msg = m.id_msg AND l.ctype = 1 AND l.id_user = {int:id_user})
			LEFT JOIN {db_prefix}like_cache AS c ON (c.id_msg = m.id_msg AND c.ctype = 1)' : '') . '
			LEFT JOIN {db_prefix}messages_cache AS mc on mc.id_msg = m.id_msg AND mc.style = {int:style} AND mc.lang = {int:lang}';
        $sql_array = array('message_list' => $messages, 'new_from' => $topicinfo['new_from'], 'style' => $user_info['smiley_set_id'], 'lang' => $user_info['language_id'], 'id_user' => $user_info['id']);
        HookAPI::callHook('display_messagerequest', array(&$sql_what, &$sql_from_tables, &$sql_from_joins, &$sql_array));
        $messages_request = smf_db_query('
			SELECT ' . $sql_what . ' ' . $sql_from_tables . $sql_from_joins . '
			WHERE m.id_msg IN ({array_int:message_list})
			ORDER BY m.id_msg' . (empty($options['view_newest_first']) ? '' : ' DESC'), $sql_array);
        // Go to the last message if the given time is beyond the time of the last message.
        if (isset($context['start_from']) && $context['start_from'] >= $topicinfo['num_replies']) {
            $context['start_from'] = $topicinfo['num_replies'];
        }
        // Since the anchor information is needed on the top of the page we load these variables beforehand.
        $context['first_message'] = isset($messages[$firstIndex]) ? $messages[$firstIndex] : $messages[0];
        if (empty($options['view_newest_first'])) {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $context['start_from'];
        } else {
            $context['first_new_message'] = isset($context['start_from']) && $_REQUEST['start'] == $topicinfo['num_replies'] - $context['start_from'];
        }
    } else {
        $messages_request = false;
        $context['first_message'] = 0;
        $context['first_new_message'] = false;
    }
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => htmlspecialchars(strtr(strip_tags($board_info['name']), array('&amp;' => '&'))), 'child_level' => $board_info['child_level']);
    // Set the callback.  (do you REALIZE how much memory all the messages would take?!?)
    $context['get_message'] = 'prepareDisplayContext';
    // Now set all the wonderful, wonderful permissions... like moderation ones...
    $common_permissions = array('can_approve' => 'approve_posts', 'can_ban' => 'manage_bans', 'can_sticky' => 'make_sticky', 'can_merge' => 'merge_any', 'can_split' => 'split_any', 'calendar_post' => 'calendar_post', 'can_mark_notify' => 'mark_any_notify', 'can_send_topic' => 'send_topic', 'can_send_pm' => 'pm_send', 'can_report_moderator' => 'report_any', 'can_moderate_forum' => 'moderate_forum', 'can_issue_warning' => 'issue_warning', 'can_restore_topic' => 'move_any', 'can_restore_msg' => 'move_any');
    foreach ($common_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm);
    }
    // Permissions with _any/_own versions.  $context[YYY] => ZZZ_any/_own.
    $anyown_permissions = array('can_move' => 'move', 'can_lock' => 'lock', 'can_delete' => 'remove', 'can_add_poll' => 'poll_add', 'can_remove_poll' => 'poll_remove', 'can_reply' => 'post_reply', 'can_reply_unapproved' => 'post_unapproved_replies');
    foreach ($anyown_permissions as $contextual => $perm) {
        $context[$contextual] = allowedTo($perm . '_any') || $context['user']['started'] && allowedTo($perm . '_own');
    }
    $context['can_add_tags'] = $context['user']['started'] && allowedTo('smftags_add') || allowedTo('smftags_manage');
    $context['can_delete_tags'] = $context['user']['started'] && allowedTo('smftags_del') || allowedTo('smftags_manage');
    $context['can_moderate_board'] = allowedTo('moderate_board');
    $context['can_modify_any'] = allowedTo('modify_any');
    $context['can_modify_replies'] = allowedTo('modify_replies');
    $context['can_modify_own'] = allowedTo('modify_own');
    $context['can_delete_any'] = allowedTo('delete_any');
    $context['can_delete_replies'] = allowedTo('delete_replies');
    $context['can_delete_own'] = allowedTo('delete_own');
    $context['use_share'] = !$user_info['possibly_robot'] && allowedTo('use_share') && ($context['user']['is_guest'] || (empty($options['use_share_bar']) ? 1 : !$options['use_share_bar']));
    $context['can_unapprove'] = $context['can_approve'] && !empty($modSettings['postmod_active']);
    $context['can_profile_view_any'] = allowedTo('profile_view_any');
    $context['can_profile_view_own'] = allowedTo('profile_view_own');
    $context['is_banned_from_topic'] = !$user_info['is_admin'] && !$context['can_moderate_forum'] && !$context['can_moderate_board'] && (!empty($context['topic_banned_members']) ? in_array($user_info['id'], $context['topic_banned_members']) : false);
    $context['banned_notice'] = $context['is_banned_from_topic'] ? $txt['topic_banned_notice'] : '';
    // Cleanup all the permissions with extra stuff...
    $context['can_mark_notify'] &= !$context['user']['is_guest'];
    $context['can_sticky'] &= !empty($modSettings['enableStickyTopics']);
    $context['calendar_post'] &= !empty($modSettings['cal_enabled']);
    $context['can_add_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['id_poll'] <= 0;
    $context['can_remove_poll'] &= $modSettings['pollMode'] == '1' && $topicinfo['id_poll'] > 0;
    $context['can_reply'] &= empty($topicinfo['locked']) || allowedTo('moderate_board');
    $context['can_reply_unapproved'] &= $modSettings['postmod_active'] && (empty($topicinfo['locked']) || allowedTo('moderate_board'));
    $context['can_issue_warning'] &= in_array('w', $context['admin_features']) && $modSettings['warning_settings'][0] == 1;
    // Handle approval flags...
    $context['can_reply_approved'] = $context['can_reply'];
    $context['can_reply'] |= $context['can_reply_unapproved'];
    $context['can_quote'] = $context['can_reply'] && (empty($modSettings['disabledBBC']) || !in_array('quote', explode(',', $modSettings['disabledBBC'])));
    $context['can_mark_unread'] = !$user_info['is_guest'] && $settings['show_mark_read'];
    $context['can_send_topic'] = (!$modSettings['postmod_active'] || $topicinfo['approved']) && allowedTo('send_topic');
    // Start this off for quick moderation - it will be or'd for each post.
    $context['can_remove_post'] = allowedTo('delete_any') || allowedTo('delete_replies') && $context['user']['started'];
    // Can restore topic?  That's if the topic is in the recycle board and has a previous restore state.
    $context['can_restore_topic'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_board']);
    $context['can_restore_msg'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_topic']);
    if ($context['is_banned_from_topic']) {
        $context['can_add_tags'] = $context['can_delete_tags'] = $context['can_modify_any'] = $context['can_modify_replies'] = $context['can_modify_own'] = $context['can_delete_any'] = $context['can_delete_replies'] = $context['can_delete_own'] = $context['can_lock'] = $context['can_sticky'] = $context['calendar_post'] = $context['can_add_poll'] = $context['can_remove_poll'] = $context['can_reply'] = $context['can_reply_unapproved'] = $context['can_quote'] = $context['can_remove_post'] = false;
    }
    // Load up the "double post" sequencing magic.
    if (!empty($options['display_quick_reply'])) {
        checkSubmitOnce('register');
        $context['name'] = isset($_SESSION['guest_name']) ? $_SESSION['guest_name'] : '';
        $context['email'] = isset($_SESSION['guest_email']) ? $_SESSION['guest_email'] : '';
    }
    // todo: drafts -> plugin
    $context['can_save_draft'] = false;
    //$context['can_reply'] && !$context['user']['is_guest'] && in_array('dr', $context['admin_features']) && !empty($options['use_drafts']) && allowedTo('drafts_allow');
    $context['can_autosave_draft'] = false;
    //$context['can_save_draft'] && !empty($modSettings['enableAutoSaveDrafts']) && allowedTo('drafts_autosave_allow');
    enqueueThemeScript('topic', 'scripts/topic.js', true);
    if ($context['can_autosave_draft']) {
        enqueueThemeScript('drafts', 'scripts/drafts.js', true);
    }
    $context['can_moderate_member'] = $context['can_issue_warning'] || $context['can_moderate_board'];
    $context['topic_has_banned_members_msg'] = $context['topic_banned_members_count'] > 0 && $context['can_moderate_board'] ? sprintf($txt['topic_has_bans_msg'], URL::parse('?action=moderate;area=topicbans;sa=bytopic;t=' . $topic)) : '';
    if (EoS_Smarty::isActive()) {
        if (isset($context['poll'])) {
            $context['poll_buttons'] = array('vote' => array('test' => 'allow_return_vote', 'text' => 'poll_return_vote', 'image' => 'poll_options.gif', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start']), 'results' => array('test' => 'show_view_results_button', 'text' => 'poll_results', 'image' => 'poll_results.gif', 'lang' => true, 'url' => $scripturl . '?topic=' . $context['current_topic'] . '.' . $context['start'] . ';viewresults'), 'change_vote' => array('test' => 'allow_change_vote', 'text' => 'poll_change_vote', 'image' => 'poll_change_vote.gif', 'lang' => true, 'url' => $scripturl . '?action=vote;topic=' . $context['current_topic'] . '.' . $context['start'] . ';poll=' . $context['poll']['id'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'lock' => array('test' => 'allow_lock_poll', 'text' => !$context['poll']['is_locked'] ? 'poll_lock' : 'poll_unlock', 'image' => 'poll_lock.gif', 'lang' => true, 'url' => $scripturl . '?action=lockvoting;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'edit' => array('test' => 'allow_edit_poll', 'text' => 'poll_edit', 'image' => 'poll_edit.gif', 'lang' => true, 'url' => $scripturl . '?action=editpoll;topic=' . $context['current_topic'] . '.' . $context['start']), 'remove_poll' => array('test' => 'can_remove_poll', 'text' => 'poll_remove', 'image' => 'admin_remove_poll.gif', 'lang' => true, 'custom' => 'onclick="return Eos_Confirm(\'\', \'' . $txt['poll_remove_warn'] . '\', $(this).attr(\'href\'));"', 'url' => $scripturl . '?action=removepoll;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']));
        }
        $context['normal_buttons'] = array('reply' => array('test' => 'can_reply', 'text' => 'reply', 'custom' => 'onclick="return oQuickReply.quote(0);" ', 'image' => 'reply.gif', 'lang' => true, 'url' => $scripturl . '?action=post;topic=' . $context['current_topic'] . '.' . $context['start'] . ';last_msg=' . $context['topic_last_message'], 'active' => true), 'add_poll' => array('test' => 'can_add_poll', 'text' => 'add_poll', 'image' => 'add_poll.gif', 'lang' => true, 'url' => $scripturl . '?action=editpoll;add;topic=' . $context['current_topic'] . '.' . $context['start']), 'mark_unread' => array('test' => 'can_mark_unread', 'text' => 'mark_unread', 'image' => 'markunread.gif', 'lang' => true, 'url' => $scripturl . '?action=markasread;sa=topic;t=' . $context['mark_unread_time'] . ';topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']));
        HookAPI::callHook('integrate_display_buttons', array(&$context['normal_buttons']));
        $remove_url = $scripturl . '?action=removetopic2;topic=' . $context['current_topic'] . '.0;' . $context['session_var'] . '=' . $context['session_id'];
        $context['mod_buttons'] = array('move' => array('test' => 'can_move', 'text' => 'move_topic', 'image' => 'admin_move.gif', 'lang' => true, 'url' => $scripturl . '?action=movetopic;topic=' . $context['current_topic'] . '.0'), 'delete' => array('test' => 'can_delete', 'text' => 'remove_topic', 'image' => 'admin_rem.gif', 'lang' => true, 'custom' => 'onclick="return Eos_Confirm(\'\',\'' . $txt['are_sure_remove_topic'] . '\',\'' . $remove_url . '\');"', 'url' => $remove_url), 'lock' => array('test' => 'can_lock', 'text' => empty($context['is_locked']) ? 'set_lock' : 'set_unlock', 'image' => 'admin_lock.gif', 'lang' => true, 'url' => $scripturl . '?action=lock;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'sticky' => array('test' => 'can_sticky', 'text' => empty($context['is_sticky']) ? 'set_sticky' : 'set_nonsticky', 'image' => 'admin_sticky.gif', 'lang' => true, 'url' => $scripturl . '?action=sticky;topic=' . $context['current_topic'] . '.' . $context['start'] . ';' . $context['session_var'] . '=' . $context['session_id']), 'merge' => array('test' => 'can_merge', 'text' => 'merge', 'image' => 'merge.gif', 'lang' => true, 'url' => $scripturl . '?action=mergetopics;board=' . $context['current_board'] . '.0;from=' . $context['current_topic']), 'calendar' => array('test' => 'calendar_post', 'text' => 'calendar_link', 'image' => 'linktocal.gif', 'lang' => true, 'url' => $scripturl . '?action=post;calendar;msg=' . $context['topic_first_message'] . ';topic=' . $context['current_topic'] . '.0'));
        // Restore topic. eh?  No monkey business.
        if ($context['can_restore_topic']) {
            $context['mod_buttons'][] = array('text' => 'restore_topic', 'image' => '', 'lang' => true, 'url' => $scripturl . '?action=restoretopic;topics=' . $context['current_topic'] . ';' . $context['session_var'] . '=' . $context['session_id']);
        }
        // Allow adding new mod buttons easily.
        HookAPI::callHook('integrate_mod_buttons', array(&$context['mod_buttons']));
        $context['message_ids'] = $messages;
        $context['perma_request'] = isset($_REQUEST['perma']) ? true : false;
        $context['mod_buttons_style'] = array('id' => 'moderationbuttons_strip', 'class' => 'buttonlist');
        $context['full_members_viewing_list'] = empty($context['view_members_list']) ? '0 ' . $txt['members'] : implode(', ', $context['view_members_list']) . (empty($context['view_num_hidden']) || $context['can_moderate_forum'] ? '' : ' (+ ' . $context['view_num_hidden'] . ' ' . $txt['hidden'] . ')');
    }
    fetchNewsItems($board, $topic);
    HookAPI::callHook('display_general', array());
    /*
     * $message is always available in templates as global variable
     * prepareDisplayContext() just repopulates it and is called from
     * the topic display template via $SUPPORT object callback.
     */
    EoS_Smarty::getSmartyInstance()->assignByRef('message', $output);
}
Ejemplo n.º 20
0
function smf_main()
{
    global $context, $modSettings, $settings, $user_info, $board, $topic, $board_info, $maintenance, $sourcedir, $backend_subdir, $db_show_debug;
    // Special case: session keep-alive, output a transparent pixel.
    if (isset($_GET['action']) && $_GET['action'] == 'keepalive') {
        header('Content-Type: image/gif');
        die("GIF89a€!ù,D;");
    }
    // Load the user's cookie (or set as guest) and load their settings.
    loadUserSettings();
    // Load the current board's information.
    loadBoard();
    // Load the current user's permissions.
    loadPermissions();
    $context['can_search'] = allowedTo('search_posts');
    $context['additional_admin_errors'] .= CacheAPI::verifyFileCache();
    // Attachments don't require the entire theme to be loaded.
    if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'dlattach' && (!empty($modSettings['allow_guestAccess']) && $user_info['is_guest'])) {
        detectBrowser();
        $context['forum_name_html_safe'] = '';
    } else {
        loadTheme();
        EoS_Smarty::init($db_show_debug);
    }
    $user_info['notify_count'] += !empty($context['open_mod_reports']) ? 1 : 0;
    URL::setSID();
    array_unshift($context['linktree'], array('url' => URL::home(), 'name' => $context['forum_name_html_safe']));
    // Check if the user should be disallowed access.
    is_not_banned();
    $context['can_see_hidden_level1'] = allowedTo('see_hidden1');
    $context['can_see_hidden_level2'] = allowedTo('see_hidden2');
    $context['can_see_hidden_level2'] = allowedTo('see_hidden2');
    // If we are in a topic and don't have permission to approve it then duck out now.
    if (!empty($topic) && empty($board_info['cur_topic_approved']) && !allowedTo('approve_posts') && ($user_info['id'] != $board_info['cur_topic_starter'] || $user_info['is_guest'])) {
        fatal_lang_error('not_a_topic', false);
    }
    // Do some logging, unless this is an attachment, avatar, toggle of editor buttons, theme option, XML feed etc.
    if (empty($_REQUEST['action']) || !in_array($_REQUEST['action'], array('dlattach', 'findmember', 'jseditor', 'jsoption', 'requestmembers', 'smstats', '.xml', 'xmlhttp', 'verificationcode', 'viewquery', 'viewsmfile'))) {
        // Log this user as online.
        writeLog();
        // Track forum statistics and hits...?
        if (!empty($modSettings['hitStats'])) {
            trackStats(array('hits' => '+'));
        }
    }
    // Is the forum in maintenance mode? (doesn't apply to administrators.)
    if (!empty($maintenance) && !allowedTo('admin_forum')) {
        // You can only login.... otherwise, you're getting the "maintenance mode" display.
        if (isset($_REQUEST['action']) && ($_REQUEST['action'] == 'login2' || $_REQUEST['action'] == 'logout')) {
            require_once $sourcedir . '/LogInOut.php';
            return $_REQUEST['action'] == 'login2' ? 'Login2' : 'Logout';
        } else {
            require_once $sourcedir . '/lib/Subs-Auth.php';
            return 'InMaintenance';
        }
    } elseif (empty($modSettings['allow_guestAccess']) && $user_info['is_guest'] && (!isset($_REQUEST['action']) || !in_array($_REQUEST['action'], array('coppa', 'login', 'login2', 'register', 'register2', 'reminder', 'activate', 'help', 'smstats', 'mailq', 'verificationcode', 'openidreturn')))) {
        require_once $sourcedir . '/lib/Subs-Auth.php';
        return 'KickGuest';
    } elseif (empty($_REQUEST['action'])) {
        // Action and board are both empty... BoardIndex!
        if (empty($board) && empty($topic)) {
            require_once $sourcedir . '/BoardIndex.php';
            return 'BoardIndex';
        } elseif (empty($topic)) {
            require_once $sourcedir . '/MessageIndex.php';
            return 'MessageIndex';
        } else {
            require_once $sourcedir . '/Display.php';
            return 'Display';
        }
    }
    // Here's the monstrous $_REQUEST['action'] array - $_REQUEST['action'] => array($file, $function).
    $actionArray = array('activate' => array('Register.php', 'Activate'), 'admin' => array($backend_subdir . '/Admin.php', 'AdminMain'), 'announce' => array('Post.php', 'AnnounceTopic'), 'attachapprove' => array('lib/Subs-ManageAttachments.php', 'ApproveAttach'), 'buddy' => array('lib/Subs-Members.php', 'BuddyListToggle'), 'calendar' => array('Calendar.php', 'CalendarMain'), 'clock' => array('Calendar.php', 'clock'), 'collapse' => array('BoardIndex.php', 'CollapseCategory'), 'coppa' => array('Register.php', 'CoppaForm'), 'credits' => array('Who.php', 'Credits'), 'deletemsg' => array('RemoveTopic.php', 'DeleteMessage'), 'display' => array('Display.php', 'Display'), 'dlattach' => array('Display.php', 'Download'), 'editpoll' => array('Poll.php', 'EditPoll'), 'editpoll2' => array('Poll.php', 'EditPoll2'), 'emailuser' => array('SendTopic.php', 'EmailUser'), 'findmember' => array('lib/Subs-Auth.php', 'JSMembers'), 'groups' => array('Groups.php', 'Groups'), 'help' => array('Help.php', 'ShowHelp'), 'helpadmin' => array('Help.php', 'ShowAdminHelp'), 'im' => array('PersonalMessage.php', 'MessageMain'), 'jseditor' => array('lib/Subs-Editor.php', 'EditorMain'), 'jsmodify' => array('Post.php', 'JavaScriptModify'), 'jsoption' => array($backend_subdir . '/Themes.php', 'SetJavaScript'), 'lock' => array('LockTopic.php', 'LockTopic'), 'lockvoting' => array('Poll.php', 'LockVoting'), 'login' => array('LogInOut.php', 'Login'), 'login2' => array('LogInOut.php', 'Login2'), 'logout' => array('LogInOut.php', 'Logout'), 'markasread' => array('lib/Subs-Boards.php', 'MarkRead'), 'mergetopics' => array('SplitTopics.php', 'MergeTopics'), 'mlist' => array('Memberlist.php', 'Memberlist'), 'moderate' => array('ModerationCenter.php', 'ModerationMain'), 'modifycat' => array('ManageBoards.php', 'ModifyCat'), 'movetopic' => array('MoveTopic.php', 'MoveTopic'), 'movetopic2' => array('MoveTopic.php', 'MoveTopic2'), 'notify' => array('Notify.php', 'Notify'), 'notifyboard' => array('Notify.php', 'BoardNotify'), 'openidreturn' => array('lib/Subs-OpenID.php', 'smf_openID_return'), 'pm' => array('PersonalMessage.php', 'MessageMain'), 'post' => array('Post.php', 'Post'), 'post2' => array('Post.php', 'Post2'), 'printpage' => array('Printpage.php', 'PrintTopic'), 'profile' => array('Profile.php', 'ModifyProfile'), 'quotefast' => array('Post.php', 'QuoteFast'), 'quickmod' => array('MessageIndex.php', 'QuickModeration'), 'quickmod2' => array('Display.php', 'QuickInTopicModeration'), 'recent' => array('Recent.php', 'RecentPosts'), 'register' => array('Register.php', 'Register'), 'register2' => array('Register.php', 'Register2'), 'reminder' => array('Reminder.php', 'RemindMe'), 'removepoll' => array('Poll.php', 'RemovePoll'), 'removetopic2' => array('RemoveTopic.php', 'RemoveTopic2'), 'reporttm' => array('SendTopic.php', 'ReportToModerator'), 'requestmembers' => array('lib/Subs-Auth.php', 'RequestMembers'), 'restoretopic' => array('RemoveTopic.php', 'RestoreTopic'), 'search' => array('Search.php', 'PlushSearch1'), 'search2' => array('Search.php', 'PlushSearch2'), 'sendtopic' => array('SendTopic.php', 'EmailUser'), 'smstats' => array('Stats.php', 'SMStats'), 'suggest' => array('lib/Subs-Editor.php', 'AutoSuggestHandler'), 'splittopics' => array('SplitTopics.php', 'SplitTopics'), 'stats' => array('Stats.php', 'DisplayStats'), 'sticky' => array('LockTopic.php', 'Sticky'), 'theme' => array($backend_subdir . '/Themes.php', 'ThemesMain'), 'trackip' => array('Profile-View.php', 'trackIP'), 'about:unknown' => array('Karma.php', 'BookOfUnknown'), 'unread' => array('Recent.php', 'UnreadTopics'), 'unreadreplies' => array('Recent.php', 'UnreadTopics'), 'verificationcode' => array('Register.php', 'VerificationCode'), 'viewprofile' => array('Profile.php', 'ModifyProfile'), 'vote' => array('Poll.php', 'Vote'), 'viewquery' => array('ViewQuery.php', 'ViewQuery'), 'who' => array('Who.php', 'Who'), '.xml' => array('News.php', 'ShowXmlFeed'), 'xmlhttp' => array('Xml.php', 'XMLhttpMain'), 'like' => array('Ratings.php', 'LikeDispatch'), 'tags' => array('Tagging.php', 'TagsMain'), 'astream' => array('Activities.php', 'aStreamDispatch'), 'dismissnews' => array('Profile-Actions.php', 'DismissNews'), 'whatsnew' => array('Recent.php', 'WhatsNew'));
    // Allow modifying $actionArray easily.
    HookAPI::callHook('integrate_actions', array(&$actionArray));
    // Get the function and file to include - if it's not there, do the board index.
    if (!isset($_REQUEST['action']) || !isset($actionArray[$_REQUEST['action']])) {
        // Catch the action with the theme?
        if (!empty($settings['catch_action'])) {
            require_once $sourcedir . '/' . $backend_subdir . '/Themes.php';
            return 'WrapAction';
        }
        // Fall through to the board index then...
        require_once $sourcedir . '/BoardIndex.php';
        return 'BoardIndex';
    }
    // Otherwise, it was set - so let's go to that action.
    require_once $sourcedir . '/' . $actionArray[$_REQUEST['action']][0];
    return $actionArray[$_REQUEST['action']][1];
}
Ejemplo n.º 21
0
function Logout($internal = false, $redirect = true)
{
    global $sourcedir, $user_info, $user_settings, $context, $modSettings, $smcFunc;
    // Make sure they aren't being auto-logged out.
    if (!$internal) {
        checkSession('get');
    }
    require_once $sourcedir . '/lib/Subs-Auth.php';
    if (isset($_SESSION['pack_ftp'])) {
        $_SESSION['pack_ftp'] = null;
    }
    // They cannot be open ID verified any longer.
    if (isset($_SESSION['openid'])) {
        unset($_SESSION['openid']);
    }
    // It won't be first login anymore.
    unset($_SESSION['first_login']);
    // Just ensure they aren't a guest!
    if (!$user_info['is_guest']) {
        // Pass the logout information to integrations.
        HookAPI::callHook('integrate_logout', array($user_settings['member_name']));
        // If you log out, you aren't online anymore :P.
        smf_db_query('
			DELETE FROM {db_prefix}log_online
			WHERE id_member = {int:current_member}', array('current_member' => $user_info['id']));
    }
    $_SESSION['log_time'] = 0;
    // Empty the cookie! (set it in the past, and for id_member = 0)
    setLoginCookie(-3600, 0);
    CacheAPI::putCache('_team_members_online', null, 0);
    // Off to the merry board index we go!
    if ($redirect) {
        if (empty($_SESSION['logout_url'])) {
            redirectexit('', $context['server']['needs_login_fix']);
        } else {
            $temp = $_SESSION['logout_url'];
            unset($_SESSION['logout_url']);
            redirectexit($temp, $context['server']['needs_login_fix']);
        }
    }
}
Ejemplo n.º 22
0
function DisplayStats()
{
    global $txt, $scripturl, $modSettings, $user_info, $context, $smcFunc;
    isAllowedTo('view_stats');
    if (!empty($_REQUEST['expand'])) {
        $context['robot_no_index'] = true;
        $month = (int) substr($_REQUEST['expand'], 4);
        $year = (int) substr($_REQUEST['expand'], 0, 4);
        if ($year > 1900 && $year < 2200 && $month >= 1 && $month <= 12) {
            $_SESSION['expanded_stats'][$year][] = $month;
        }
    } elseif (!empty($_REQUEST['collapse'])) {
        $context['robot_no_index'] = true;
        $month = (int) substr($_REQUEST['collapse'], 4);
        $year = (int) substr($_REQUEST['collapse'], 0, 4);
        if (!empty($_SESSION['expanded_stats'][$year])) {
            $_SESSION['expanded_stats'][$year] = array_diff($_SESSION['expanded_stats'][$year], array($month));
        }
    }
    // Handle the XMLHttpRequest.
    if (isset($_REQUEST['xml'])) {
        // Collapsing stats only needs adjustments of the session variables.
        if (!empty($_REQUEST['collapse'])) {
            obExit(false);
        }
        $context['sub_template'] = 'stats';
        getDailyStats('YEAR(date) = {int:year} AND MONTH(date) = {int:month}', array('year' => $year, 'month' => $month));
        $context['yearly'][$year]['months'][$month]['date'] = array('month' => sprintf('%02d', $month), 'year' => $year);
        return;
    }
    loadLanguage('Stats');
    Eos_Smarty::loadTemplate('forumstats');
    // Build the link tree......
    $context['linktree'][] = array('url' => $scripturl . '?action=stats', 'name' => $txt['stats_center']);
    $context['page_title'] = $context['forum_name'] . ' - ' . $txt['stats_center'];
    $context['show_member_list'] = allowedTo('view_mlist');
    // Get averages...
    $result = smf_db_query('
		SELECT
			SUM(posts) AS posts, SUM(topics) AS topics, SUM(registers) AS registers,
			SUM(most_on) AS most_on, MIN(date) AS date, SUM(hits) AS hits
		FROM {db_prefix}log_activity', array());
    $row = mysql_fetch_assoc($result);
    mysql_free_result($result);
    // This would be the amount of time the forum has been up... in days...
    $total_days_up = ceil((time() - strtotime($row['date'])) / (60 * 60 * 24));
    $context['average_posts'] = comma_format(round($row['posts'] / $total_days_up, 2));
    $context['average_topics'] = comma_format(round($row['topics'] / $total_days_up, 2));
    $context['average_members'] = comma_format(round($row['registers'] / $total_days_up, 2));
    $context['average_online'] = comma_format(round($row['most_on'] / $total_days_up, 2));
    $context['average_hits'] = comma_format(round($row['hits'] / $total_days_up, 2));
    $context['num_hits'] = comma_format($row['hits'], 0);
    // How many users are online now.
    $result = smf_db_query('
		SELECT COUNT(*)
		FROM {db_prefix}log_online', array());
    list($context['users_online']) = mysql_fetch_row($result);
    mysql_free_result($result);
    // Statistics such as number of boards, categories, etc.
    $result = smf_db_query('
		SELECT COUNT(*)
		FROM {db_prefix}boards AS b
		WHERE b.redirect = {string:blank_redirect}', array('blank_redirect' => ''));
    list($context['num_boards']) = mysql_fetch_row($result);
    mysql_free_result($result);
    $result = smf_db_query('
		SELECT COUNT(*)
		FROM {db_prefix}categories AS c', array());
    list($context['num_categories']) = mysql_fetch_row($result);
    mysql_free_result($result);
    // Format the numbers nicely.
    $context['users_online'] = comma_format($context['users_online']);
    $context['num_boards'] = comma_format($context['num_boards']);
    $context['num_categories'] = comma_format($context['num_categories']);
    $context['num_members'] = comma_format($modSettings['totalMembers']);
    $context['num_posts'] = comma_format($modSettings['totalMessages']);
    $context['num_topics'] = comma_format($modSettings['totalTopics']);
    $context['most_members_online'] = array('number' => comma_format($modSettings['mostOnline']), 'date' => timeformat($modSettings['mostDate']));
    $context['latest_member'] =& $context['common_stats']['latest_member'];
    // Male vs. female ratio - let's calculate this only every four minutes.
    if (($context['gender'] = CacheAPI::getCache('stats_gender', 240)) == null) {
        $result = smf_db_query('
			SELECT COUNT(*) AS total_members, gender
			FROM {db_prefix}members
			GROUP BY gender', array());
        $context['gender'] = array();
        while ($row = mysql_fetch_assoc($result)) {
            // Assuming we're telling... male or female?
            if (!empty($row['gender'])) {
                $context['gender'][$row['gender'] == 2 ? 'females' : 'males'] = $row['total_members'];
            }
        }
        mysql_free_result($result);
        // Set these two zero if the didn't get set at all.
        if (empty($context['gender']['males'])) {
            $context['gender']['males'] = 0;
        }
        if (empty($context['gender']['females'])) {
            $context['gender']['females'] = 0;
        }
        // Try and come up with some "sensible" default states in case of a non-mixed board.
        if ($context['gender']['males'] == $context['gender']['females']) {
            $context['gender']['ratio'] = '1:1';
        } elseif ($context['gender']['males'] == 0) {
            $context['gender']['ratio'] = '0:1';
        } elseif ($context['gender']['females'] == 0) {
            $context['gender']['ratio'] = '1:0';
        } elseif ($context['gender']['males'] > $context['gender']['females']) {
            $context['gender']['ratio'] = round($context['gender']['males'] / $context['gender']['females'], 1) . ':1';
        } elseif ($context['gender']['females'] > $context['gender']['males']) {
            $context['gender']['ratio'] = '1:' . round($context['gender']['females'] / $context['gender']['males'], 1);
        }
        CacheAPI::putCache('stats_gender', $context['gender'], 240);
    }
    $date = strftime('%Y-%m-%d', forum_time(false));
    // Members online so far today.
    $result = smf_db_query('
		SELECT most_on
		FROM {db_prefix}log_activity
		WHERE date = {date:today_date}
		LIMIT 1', array('today_date' => $date));
    list($context['online_today']) = mysql_fetch_row($result);
    mysql_free_result($result);
    $context['online_today'] = comma_format((int) $context['online_today']);
    // Poster top 10.
    $members_result = smf_db_query('
		SELECT id_member, real_name, posts
		FROM {db_prefix}members
		WHERE posts > {int:no_posts}
		ORDER BY posts DESC
		LIMIT 10', array('no_posts' => 0));
    $context['top_posters'] = array();
    $max_num_posts = 1;
    while ($row_members = mysql_fetch_assoc($members_result)) {
        $context['top_posters'][] = array('name' => $row_members['real_name'], 'id' => $row_members['id_member'], 'num_posts' => $row_members['posts'], 'href' => $scripturl . '?action=profile;u=' . $row_members['id_member'], 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row_members['id_member'] . '">' . $row_members['real_name'] . '</a>');
        if ($max_num_posts < $row_members['posts']) {
            $max_num_posts = $row_members['posts'];
        }
    }
    mysql_free_result($members_result);
    foreach ($context['top_posters'] as $i => $poster) {
        $context['top_posters'][$i]['post_percent'] = round($poster['num_posts'] * 100 / $max_num_posts);
        $context['top_posters'][$i]['num_posts'] = comma_format($context['top_posters'][$i]['num_posts']);
    }
    // Board top 10.
    $boards_result = smf_db_query('
		SELECT id_board, name, num_posts
		FROM {db_prefix}boards AS b
		WHERE {query_see_board}' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
			AND b.id_board != {int:recycle_board}' : '') . '
			AND b.redirect = {string:blank_redirect}
		ORDER BY num_posts DESC
		LIMIT 10', array('recycle_board' => $modSettings['recycle_board'], 'blank_redirect' => ''));
    $context['top_boards'] = array();
    $max_num_posts = 1;
    while ($row_board = mysql_fetch_assoc($boards_result)) {
        $context['top_boards'][] = array('id' => $row_board['id_board'], 'name' => $row_board['name'], 'num_posts' => $row_board['num_posts'], 'href' => $scripturl . '?board=' . $row_board['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row_board['id_board'] . '.0">' . $row_board['name'] . '</a>');
        if ($max_num_posts < $row_board['num_posts']) {
            $max_num_posts = $row_board['num_posts'];
        }
    }
    mysql_free_result($boards_result);
    foreach ($context['top_boards'] as $i => $board) {
        $context['top_boards'][$i]['post_percent'] = round($board['num_posts'] * 100 / $max_num_posts);
        $context['top_boards'][$i]['num_posts'] = comma_format($context['top_boards'][$i]['num_posts']);
    }
    // Are you on a larger forum?  If so, let's try to limit the number of topics we search through.
    if ($modSettings['totalMessages'] > 100000) {
        $request = smf_db_query('
			SELECT id_topic
			FROM {db_prefix}topics
			WHERE num_replies != {int:no_replies}' . ($modSettings['postmod_active'] ? '
				AND approved = {int:is_approved}' : '') . '
			ORDER BY num_replies DESC
			LIMIT 100', array('no_replies' => 0, 'is_approved' => 1));
        $topic_ids = array();
        while ($row = mysql_fetch_assoc($request)) {
            $topic_ids[] = $row['id_topic'];
        }
        mysql_free_result($request);
    } else {
        $topic_ids = array();
    }
    // Topic replies top 10.
    $topic_reply_result = smf_db_query('
		SELECT m.subject, t.num_replies, t.id_board, t.id_topic, b.name
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
			AND b.id_board != {int:recycle_board}' : '') . ')
		WHERE {query_see_board}' . (!empty($topic_ids) ? '
			AND t.id_topic IN ({array_int:topic_list})' : ($modSettings['postmod_active'] ? '
			AND t.approved = {int:is_approved}' : '')) . '
		ORDER BY t.num_replies DESC
		LIMIT 10', array('topic_list' => $topic_ids, 'recycle_board' => $modSettings['recycle_board'], 'is_approved' => 1));
    $context['top_topics_replies'] = array();
    $max_num_replies = 1;
    while ($row_topic_reply = mysql_fetch_assoc($topic_reply_result)) {
        censorText($row_topic_reply['subject']);
        $context['top_topics_replies'][] = array('id' => $row_topic_reply['id_topic'], 'board' => array('id' => $row_topic_reply['id_board'], 'name' => $row_topic_reply['name'], 'href' => $scripturl . '?board=' . $row_topic_reply['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row_topic_reply['id_board'] . '.0">' . $row_topic_reply['name'] . '</a>'), 'subject' => $row_topic_reply['subject'], 'num_replies' => $row_topic_reply['num_replies'], 'href' => $scripturl . '?topic=' . $row_topic_reply['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row_topic_reply['id_topic'] . '.0">' . $row_topic_reply['subject'] . '</a>');
        if ($max_num_replies < $row_topic_reply['num_replies']) {
            $max_num_replies = $row_topic_reply['num_replies'];
        }
    }
    mysql_free_result($topic_reply_result);
    foreach ($context['top_topics_replies'] as $i => $topic) {
        $context['top_topics_replies'][$i]['post_percent'] = round($topic['num_replies'] * 100 / $max_num_replies);
        $context['top_topics_replies'][$i]['num_replies'] = comma_format($context['top_topics_replies'][$i]['num_replies']);
    }
    // Large forums may need a bit more prodding...
    if ($modSettings['totalMessages'] > 100000) {
        $request = smf_db_query('
			SELECT id_topic
			FROM {db_prefix}topics
			WHERE num_views != {int:no_views}
			ORDER BY num_views DESC
			LIMIT 100', array('no_views' => 0));
        $topic_ids = array();
        while ($row = mysql_fetch_assoc($request)) {
            $topic_ids[] = $row['id_topic'];
        }
        mysql_free_result($request);
    } else {
        $topic_ids = array();
    }
    // Topic views top 10.
    $topic_view_result = smf_db_query('
		SELECT m.subject, t.num_views, t.id_board, t.id_topic, b.name
		FROM {db_prefix}topics AS t
			INNER JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)
			INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
			AND b.id_board != {int:recycle_board}' : '') . ')
		WHERE {query_see_board}' . (!empty($topic_ids) ? '
			AND t.id_topic IN ({array_int:topic_list})' : ($modSettings['postmod_active'] ? '
			AND t.approved = {int:is_approved}' : '')) . '
		ORDER BY t.num_views DESC
		LIMIT 10', array('topic_list' => $topic_ids, 'recycle_board' => $modSettings['recycle_board'], 'is_approved' => 1));
    $context['top_topics_views'] = array();
    $max_num_views = 1;
    while ($row_topic_views = mysql_fetch_assoc($topic_view_result)) {
        censorText($row_topic_views['subject']);
        $context['top_topics_views'][] = array('id' => $row_topic_views['id_topic'], 'board' => array('id' => $row_topic_views['id_board'], 'name' => $row_topic_views['name'], 'href' => $scripturl . '?board=' . $row_topic_views['id_board'] . '.0', 'link' => '<a href="' . $scripturl . '?board=' . $row_topic_views['id_board'] . '.0">' . $row_topic_views['name'] . '</a>'), 'subject' => $row_topic_views['subject'], 'num_views' => $row_topic_views['num_views'], 'href' => $scripturl . '?topic=' . $row_topic_views['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row_topic_views['id_topic'] . '.0">' . $row_topic_views['subject'] . '</a>');
        if ($max_num_views < $row_topic_views['num_views']) {
            $max_num_views = $row_topic_views['num_views'];
        }
    }
    mysql_free_result($topic_view_result);
    foreach ($context['top_topics_views'] as $i => $topic) {
        $context['top_topics_views'][$i]['post_percent'] = round($topic['num_views'] * 100 / $max_num_views);
        $context['top_topics_views'][$i]['num_views'] = comma_format($context['top_topics_views'][$i]['num_views']);
    }
    // Try to cache this when possible, because it's a little unavoidably slow.
    if (($members = CacheAPI::getCache('stats_top_starters', 360)) == null) {
        $request = smf_db_query('
			SELECT id_member_started, COUNT(*) AS hits
			FROM {db_prefix}topics' . (!empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
			WHERE id_board != {int:recycle_board}' : '') . '
			GROUP BY id_member_started
			ORDER BY hits DESC
			LIMIT 20', array('recycle_board' => $modSettings['recycle_board']));
        $members = array();
        while ($row = mysql_fetch_assoc($request)) {
            $members[$row['id_member_started']] = $row['hits'];
        }
        mysql_free_result($request);
        CacheAPI::putCache('stats_top_starters', $members, 360);
    }
    if (empty($members)) {
        $members = array(0 => 0);
    }
    // Topic poster top 10.
    $members_result = smf_db_query('
		SELECT id_member, real_name
		FROM {db_prefix}members
		WHERE id_member IN ({array_int:member_list})
		ORDER BY FIND_IN_SET(id_member, {string:top_topic_posters})
		LIMIT 10', array('member_list' => array_keys($members), 'top_topic_posters' => implode(',', array_keys($members))));
    $context['top_starters'] = array();
    $max_num_topics = 1;
    while ($row_members = mysql_fetch_assoc($members_result)) {
        $context['top_starters'][] = array('name' => $row_members['real_name'], 'id' => $row_members['id_member'], 'num_topics' => $members[$row_members['id_member']], 'href' => $scripturl . '?action=profile;u=' . $row_members['id_member'], 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row_members['id_member'] . '">' . $row_members['real_name'] . '</a>');
        if ($max_num_topics < $members[$row_members['id_member']]) {
            $max_num_topics = $members[$row_members['id_member']];
        }
    }
    mysql_free_result($members_result);
    foreach ($context['top_starters'] as $i => $topic) {
        $context['top_starters'][$i]['post_percent'] = round($topic['num_topics'] * 100 / $max_num_topics);
        $context['top_starters'][$i]['num_topics'] = comma_format($context['top_starters'][$i]['num_topics']);
    }
    // Time online top 10.
    $temp = CacheAPI::getCache('stats_total_time_members', 600);
    $members_result = smf_db_query('
		SELECT id_member, real_name, total_time_logged_in
		FROM {db_prefix}members' . (!empty($temp) ? '
		WHERE id_member IN ({array_int:member_list_cached})' : '') . '
		ORDER BY total_time_logged_in DESC
		LIMIT 20', array('member_list_cached' => $temp));
    $context['top_time_online'] = array();
    $temp2 = array();
    $max_time_online = 1;
    while ($row_members = mysql_fetch_assoc($members_result)) {
        $temp2[] = (int) $row_members['id_member'];
        if (count($context['top_time_online']) >= 10) {
            continue;
        }
        // Figure out the days, hours and minutes.
        $timeDays = floor($row_members['total_time_logged_in'] / 86400);
        $timeHours = floor($row_members['total_time_logged_in'] % 86400 / 3600);
        // Figure out which things to show... (days, hours, minutes, etc.)
        $timelogged = '';
        if ($timeDays > 0) {
            $timelogged .= $timeDays . $txt['totalTimeLogged5'];
        }
        if ($timeHours > 0) {
            $timelogged .= $timeHours . $txt['totalTimeLogged6'];
        }
        $timelogged .= floor($row_members['total_time_logged_in'] % 3600 / 60) . $txt['totalTimeLogged7'];
        $context['top_time_online'][] = array('id' => $row_members['id_member'], 'name' => $row_members['real_name'], 'time_online' => $timelogged, 'seconds_online' => $row_members['total_time_logged_in'], 'href' => $scripturl . '?action=profile;u=' . $row_members['id_member'], 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row_members['id_member'] . '">' . $row_members['real_name'] . '</a>');
        if ($max_time_online < $row_members['total_time_logged_in']) {
            $max_time_online = $row_members['total_time_logged_in'];
        }
    }
    mysql_free_result($members_result);
    foreach ($context['top_time_online'] as $i => $member) {
        $context['top_time_online'][$i]['time_percent'] = round($member['seconds_online'] * 100 / $max_time_online);
    }
    // Cache the ones we found for a bit, just so we don't have to look again.
    if ($temp !== $temp2) {
        CacheAPI::putCache('stats_total_time_members', $temp2, 480);
    }
    // Activity by month.
    $months_result = smf_db_query('
		SELECT
			YEAR(date) AS stats_year, MONTH(date) AS stats_month, SUM(hits) AS hits, SUM(registers) AS registers, SUM(topics) AS topics, SUM(posts) AS posts, MAX(most_on) AS most_on, COUNT(*) AS num_days
		FROM {db_prefix}log_activity
		GROUP BY stats_year, stats_month', array());
    $context['yearly'] = array();
    while ($row_months = mysql_fetch_assoc($months_result)) {
        $ID_MONTH = $row_months['stats_year'] . sprintf('%02d', $row_months['stats_month']);
        $expanded = !empty($_SESSION['expanded_stats'][$row_months['stats_year']]) && in_array($row_months['stats_month'], $_SESSION['expanded_stats'][$row_months['stats_year']]);
        if (!isset($context['yearly'][$row_months['stats_year']])) {
            $context['yearly'][$row_months['stats_year']] = array('year' => $row_months['stats_year'], 'new_topics' => 0, 'new_posts' => 0, 'new_members' => 0, 'most_members_online' => 0, 'hits' => 0, 'num_months' => 0, 'months' => array(), 'expanded' => false, 'current_year' => $row_months['stats_year'] == date('Y'));
        }
        $context['yearly'][$row_months['stats_year']]['months'][(int) $row_months['stats_month']] = array('id' => $ID_MONTH, 'date' => array('month' => sprintf('%02d', $row_months['stats_month']), 'year' => $row_months['stats_year']), 'href' => $scripturl . '?action=stats;' . ($expanded ? 'collapse' : 'expand') . '=' . $ID_MONTH . '#m' . $ID_MONTH, 'link' => '<a href="' . $scripturl . '?action=stats;' . ($expanded ? 'collapse' : 'expand') . '=' . $ID_MONTH . '#m' . $ID_MONTH . '">' . $txt['months'][(int) $row_months['stats_month']] . ' ' . $row_months['stats_year'] . '</a>', 'month' => $txt['months'][(int) $row_months['stats_month']], 'year' => $row_months['stats_year'], 'new_topics' => comma_format($row_months['topics']), 'new_posts' => comma_format($row_months['posts']), 'new_members' => comma_format($row_months['registers']), 'most_members_online' => comma_format($row_months['most_on']), 'hits' => comma_format($row_months['hits']), 'num_days' => $row_months['num_days'], 'days' => array(), 'expanded' => $expanded);
        $context['yearly'][$row_months['stats_year']]['new_topics'] += $row_months['topics'];
        $context['yearly'][$row_months['stats_year']]['new_posts'] += $row_months['posts'];
        $context['yearly'][$row_months['stats_year']]['new_members'] += $row_months['registers'];
        $context['yearly'][$row_months['stats_year']]['hits'] += $row_months['hits'];
        $context['yearly'][$row_months['stats_year']]['num_months']++;
        $context['yearly'][$row_months['stats_year']]['expanded'] |= $expanded;
        $context['yearly'][$row_months['stats_year']]['most_members_online'] = max($context['yearly'][$row_months['stats_year']]['most_members_online'], $row_months['most_on']);
    }
    krsort($context['yearly']);
    $context['collapsed_years'] = array();
    foreach ($context['yearly'] as $year => $data) {
        // This gets rid of the filesort on the query ;).
        krsort($context['yearly'][$year]['months']);
        $context['yearly'][$year]['new_topics'] = comma_format($data['new_topics']);
        $context['yearly'][$year]['new_posts'] = comma_format($data['new_posts']);
        $context['yearly'][$year]['new_members'] = comma_format($data['new_members']);
        $context['yearly'][$year]['most_members_online'] = comma_format($data['most_members_online']);
        $context['yearly'][$year]['hits'] = comma_format($data['hits']);
        // Keep a list of collapsed years.
        if (!$data['expanded'] && !$data['current_year']) {
            $context['collapsed_years'][] = $year;
        }
    }
    if (empty($_SESSION['expanded_stats'])) {
        return;
    }
    $condition_text = array();
    $condition_params = array();
    foreach ($_SESSION['expanded_stats'] as $year => $months) {
        if (!empty($months)) {
            $condition_text[] = 'YEAR(date) = {int:year_' . $year . '} AND MONTH(date) IN ({array_int:months_' . $year . '})';
            $condition_params['year_' . $year] = $year;
            $condition_params['months_' . $year] = $months;
        }
    }
    // No daily stats to even look at?
    if (empty($condition_text)) {
        return;
    }
    getDailyStats(implode(' OR ', $condition_text), $condition_params);
}
Ejemplo n.º 23
0
function ModifyLanguage()
{
    global $settings, $context, $txt, $modSettings, $boarddir, $sourcedir, $language;
    loadLanguage('ManageSettings');
    // Select the languages tab.
    $context['menu_data_' . $context['admin_menu_id']]['current_subsection'] = 'edit';
    $context['page_title'] = $txt['edit_languages'];
    $context['sub_template'] = 'modify_language_entries';
    $context['lang_id'] = $_GET['lid'];
    list($theme_id, $file_id) = empty($_REQUEST['tfid']) || strpos($_REQUEST['tfid'], '+') === false ? array(1, '') : explode('+', $_REQUEST['tfid']);
    // Clean the ID - just in case.
    preg_match('~([A-Za-z0-9_-]+)~', $context['lang_id'], $matches);
    $context['lang_id'] = $matches[1];
    // Get all the theme data.
    $request = smf_db_query('
		SELECT id_theme, variable, value
		FROM {db_prefix}themes
		WHERE id_theme != {int:default_theme}
			AND id_member = {int:no_member}
			AND variable IN ({string:name}, {string:theme_dir})', array('default_theme' => 1, 'no_member' => 0, 'name' => 'name', 'theme_dir' => 'theme_dir'));
    $themes = array(1 => array('name' => $txt['dvc_default'], 'theme_dir' => $settings['default_theme_dir']));
    while ($row = mysql_fetch_assoc($request)) {
        $themes[$row['id_theme']][$row['variable']] = $row['value'];
    }
    mysql_free_result($request);
    // This will be where we look
    $lang_dirs = array();
    // Check we have themes with a path and a name - just in case - and add the path.
    foreach ($themes as $id => $data) {
        if (count($data) != 2) {
            unset($themes[$id]);
        } elseif (is_dir($data['theme_dir'] . '/languages')) {
            $lang_dirs[$id] = $data['theme_dir'] . '/languages';
        }
        // How about image directories?
        if (is_dir($data['theme_dir'] . '/images/' . $context['lang_id'])) {
            $images_dirs[$id] = $data['theme_dir'] . '/images/' . $context['lang_id'];
        }
    }
    $current_file = $file_id ? $lang_dirs[$theme_id] . '/' . $file_id . '.' . $context['lang_id'] . '.php' : '';
    // Now for every theme get all the files and stick them in context!
    $context['possible_files'] = array();
    foreach ($lang_dirs as $theme => $theme_dir) {
        // Open it up.
        $dir = dir($theme_dir);
        while ($entry = $dir->read()) {
            // We're only after the files for this language.
            if (preg_match('~^([A-Za-z]+)\\.' . $context['lang_id'] . '\\.php$~', $entry, $matches) == 0) {
                continue;
            }
            //!!! Temp!
            if ($matches[1] == 'EmailTemplates') {
                continue;
            }
            if (!isset($context['possible_files'][$theme])) {
                $context['possible_files'][$theme] = array('id' => $theme, 'name' => $themes[$theme]['name'], 'files' => array());
            }
            $context['possible_files'][$theme]['files'][] = array('id' => $matches[1], 'name' => isset($txt['lang_file_desc_' . $matches[1]]) ? $txt['lang_file_desc_' . $matches[1]] : $matches[1], 'selected' => $theme_id == $theme && $file_id == $matches[1]);
        }
        $dir->close();
    }
    // We no longer wish to speak this language.
    if (!empty($_POST['delete_main']) && $context['lang_id'] != 'english') {
        checkSession();
        // !!! Todo: FTP Controls?
        require_once $sourcedir . '/lib/Subs-Package.php';
        // First, Make a backup?
        if (!empty($modSettings['package_make_backups']) && (!isset($_SESSION['last_backup_for']) || $_SESSION['last_backup_for'] != $context['lang_id'] . '$$$')) {
            $_SESSION['last_backup_for'] = $context['lang_id'] . '$$$';
            package_create_backup('backup_lang_' . $context['lang_id']);
        }
        // Second, loop through the array to remove the files.
        foreach ($lang_dirs as $curPath) {
            foreach ($context['possible_files'][1]['files'] as $lang) {
                if (file_exists($curPath . '/' . $lang['id'] . '.' . $context['lang_id'] . '.php')) {
                    unlink($curPath . '/' . $lang['id'] . '.' . $context['lang_id'] . '.php');
                }
            }
            // Check for the email template.
            if (file_exists($curPath . '/EmailTemplates.' . $context['lang_id'] . '.php')) {
                unlink($curPath . '/EmailTemplates.' . $context['lang_id'] . '.php');
            }
        }
        // Third, the agreement file.
        if (file_exists($boarddir . '/agreement.' . $context['lang_id'] . '.txt')) {
            unlink($boarddir . '/agreement.' . $context['lang_id'] . '.txt');
        }
        // Fourth, a related images folder?
        foreach ($images_dirs as $curPath) {
            if (is_dir($curPath)) {
                deltree($curPath);
            }
        }
        // Members can no longer use this language.
        smf_db_query('
			UPDATE {db_prefix}members
			SET lngfile = {string:empty_string}
			WHERE lngfile = {string:current_language}', array('empty_string' => '', 'current_language' => $context['lang_id']));
        // Fifth, update getLanguages() cache.
        if (!empty($modSettings['cache_enable'])) {
            CacheAPI::putCache('known_languages', null, !empty($modSettings['cache_enable']) && $modSettings['cache_enable'] < 1 ? 86400 : 3600);
            CacheAPI::putCache('known_languages_all', null, !empty($modSettings['cache_enable']) && $modSettings['cache_enable'] < 1 ? 86400 : 3600);
        }
        // Sixth, if we deleted the default language, set us back to english?
        if ($context['lang_id'] == $language) {
            require_once $sourcedir . '/lib/Subs-Admin.php';
            $language = 'english';
            updateSettingsFile(array('language' => '\'' . $language . '\''));
        }
        // Seventh, get out of here.
        redirectexit('action=admin;area=languages;sa=edit;' . $context['session_var'] . '=' . $context['session_id']);
    }
    // Saving primary settings?
    $madeSave = false;
    if (!empty($_POST['save_main']) && !$current_file) {
        checkSession();
        // Read in the current file.
        $current_data = implode('', file($settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php'));
        // These are the replacements. old => new
        $replace_array = array('~\\$txt\\[\'lang_character_set\'\\]\\s=\\s(\'|")[^\\r\\n]+~' => '$txt[\'lang_character_set\'] = \'' . addslashes($_POST['character_set']) . '\';', '~\\$txt\\[\'lang_locale\'\\]\\s=\\s(\'|")[^\\r\\n]+~' => '$txt[\'lang_locale\'] = \'' . addslashes($_POST['locale']) . '\';', '~\\$txt\\[\'lang_dictionary\'\\]\\s=\\s(\'|")[^\\r\\n]+~' => '$txt[\'lang_dictionary\'] = \'' . addslashes($_POST['dictionary']) . '\';', '~\\$txt\\[\'lang_spelling\'\\]\\s=\\s(\'|")[^\\r\\n]+~' => '$txt[\'lang_spelling\'] = \'' . addslashes($_POST['spelling']) . '\';', '~\\$txt\\[\'lang_rtl\'\\]\\s=\\s[A-Za-z0-9]+;~' => '$txt[\'lang_rtl\'] = ' . (!empty($_POST['rtl']) ? 'true' : 'false') . ';');
        $current_data = preg_replace(array_keys($replace_array), array_values($replace_array), $current_data);
        $fp = fopen($settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php', 'w+');
        fwrite($fp, $current_data);
        fclose($fp);
        $madeSave = true;
    }
    // Quickly load index language entries.
    $old_txt = $txt;
    require $settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php';
    $context['lang_file_not_writable_message'] = is_writable($settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php') ? '' : sprintf($txt['lang_file_not_writable'], $settings['default_theme_dir'] . '/languages/index.' . $context['lang_id'] . '.php');
    // Setup the primary settings context.
    $context['primary_settings'] = array('name' => commonAPI::ucwords(strtr($context['lang_id'], array('_' => ' ', '-utf8' => ''))), 'character_set' => $txt['lang_character_set'], 'locale' => $txt['lang_locale'], 'dictionary' => $txt['lang_dictionary'], 'spelling' => $txt['lang_spelling'], 'rtl' => $txt['lang_rtl']);
    // Restore normal service.
    $txt = $old_txt;
    // Are we saving?
    $save_strings = array();
    if (isset($_POST['save_entries']) && !empty($_POST['entry'])) {
        checkSession();
        // Clean each entry!
        foreach ($_POST['entry'] as $k => $v) {
            // Only try to save if it's changed!
            if ($_POST['entry'][$k] != $_POST['comp'][$k]) {
                $save_strings[$k] = cleanLangString($v, false);
            }
        }
    }
    // If we are editing a file work away at that.
    if ($current_file) {
        $context['entries_not_writable_message'] = is_writable($current_file) ? '' : sprintf($txt['lang_entries_not_writable'], $current_file);
        $entries = array();
        // We can't just require it I'm afraid - otherwise we pass in all kinds of variables!
        $multiline_cache = '';
        foreach (file($current_file) as $line) {
            // Got a new entry?
            if ($line[0] == '$' && !empty($multiline_cache)) {
                preg_match('~\\$(helptxt|txt)\\[\'(.+)\'\\]\\s=\\s(.+);~', strtr($multiline_cache, array("\n" => '', "\t" => '')), $matches);
                if (!empty($matches[3])) {
                    $entries[$matches[2]] = array('type' => $matches[1], 'full' => $matches[0], 'entry' => $matches[3]);
                    $multiline_cache = '';
                }
            }
            $multiline_cache .= $line . "\n";
        }
        // Last entry to add?
        if ($multiline_cache) {
            preg_match('~\\$(helptxt|txt)\\[\'(.+)\'\\]\\s=\\s(.+);~', strtr($multiline_cache, array("\n" => '', "\t" => '')), $matches);
            if (!empty($matches[3])) {
                $entries[$matches[2]] = array('type' => $matches[1], 'full' => $matches[0], 'entry' => $matches[3]);
            }
        }
        // These are the entries we can definitely save.
        $final_saves = array();
        $context['file_entries'] = array();
        foreach ($entries as $entryKey => $entryValue) {
            // Ignore some things we set separately.
            $ignore_files = array('lang_character_set', 'lang_locale', 'lang_dictionary', 'lang_spelling', 'lang_rtl');
            if (in_array($entryKey, $ignore_files)) {
                continue;
            }
            // These are arrays that need breaking out.
            $arrays = array('days', 'days_short', 'months', 'months_titles', 'months_short');
            if (in_array($entryKey, $arrays)) {
                // Get off the first bits.
                $entryValue['entry'] = substr($entryValue['entry'], strpos($entryValue['entry'], '(') + 1, strrpos($entryValue['entry'], ')') - strpos($entryValue['entry'], '('));
                $entryValue['entry'] = explode(',', strtr($entryValue['entry'], array(' ' => '')));
                // Now create an entry for each item.
                $cur_index = 0;
                $save_cache = array('enabled' => false, 'entries' => array());
                foreach ($entryValue['entry'] as $id => $subValue) {
                    // Is this a new index?
                    if (preg_match('~^(\\d+)~', $subValue, $matches)) {
                        $cur_index = $matches[1];
                        $subValue = substr($subValue, strpos($subValue, '\''));
                    }
                    // Clean up some bits.
                    $subValue = strtr($subValue, array('"' => '', '\'' => '', ')' => ''));
                    // Can we save?
                    if (isset($save_strings[$entryKey . '-+- ' . $cur_index])) {
                        $save_cache['entries'][$cur_index] = strtr($save_strings[$entryKey . '-+- ' . $cur_index], array('\'' => ''));
                        $save_cache['enabled'] = true;
                    } else {
                        $save_cache['entries'][$cur_index] = $subValue;
                    }
                    $context['file_entries'][] = array('key' => $entryKey . '-+- ' . $cur_index, 'value' => $subValue, 'rows' => 1);
                    $cur_index++;
                }
                // Do we need to save?
                if ($save_cache['enabled']) {
                    // Format the string, checking the indexes first.
                    $items = array();
                    $cur_index = 0;
                    foreach ($save_cache['entries'] as $k2 => $v2) {
                        // Manually show the custom index.
                        if ($k2 != $cur_index) {
                            $items[] = $k2 . ' => \'' . $v2 . '\'';
                            $cur_index = $k2;
                        } else {
                            $items[] = '\'' . $v2 . '\'';
                        }
                        $cur_index++;
                    }
                    // Now create the string!
                    $final_saves[$entryKey] = array('find' => $entryValue['full'], 'replace' => '$' . $entryValue['type'] . '[\'' . $entryKey . '\'] = array(' . implode(', ', $items) . ');');
                }
            } else {
                // Saving?
                if (isset($save_strings[$entryKey]) && $save_strings[$entryKey] != $entryValue['entry']) {
                    // !!! Fix this properly.
                    if ($save_strings[$entryKey] == '') {
                        $save_strings[$entryKey] = '\'\'';
                    }
                    // Set the new value.
                    $entryValue['entry'] = $save_strings[$entryKey];
                    // And we know what to save now!
                    $final_saves[$entryKey] = array('find' => $entryValue['full'], 'replace' => '$' . $entryValue['type'] . '[\'' . $entryKey . '\'] = ' . $save_strings[$entryKey] . ';');
                }
                $editing_string = cleanLangString($entryValue['entry'], true);
                $context['file_entries'][] = array('key' => $entryKey, 'value' => $editing_string, 'rows' => (int) (strlen($editing_string) / 38) + substr_count($editing_string, "\n") + 1);
            }
        }
        // Any saves to make?
        if (!empty($final_saves)) {
            checkSession();
            $file_contents = implode('', file($current_file));
            foreach ($final_saves as $save) {
                $file_contents = strtr($file_contents, array($save['find'] => $save['replace']));
            }
            // Save the actual changes.
            $fp = fopen($current_file, 'w+');
            fwrite($fp, $file_contents);
            fclose($fp);
            $madeSave = true;
        }
        // Another restore.
        $txt = $old_txt;
    }
    // If we saved, redirect.
    if ($madeSave) {
        redirectexit('action=admin;area=languages;sa=editlang;lid=' . $context['lang_id']);
    }
}
Ejemplo n.º 24
0
    /**
     * Loads all board names from the forum into a variable and cache (if possible)
     * This helps reduce the number of queries needed for SimpleSEF to run
     *
     * @global array $smcFunc
     * @global string $language
     * @param boolean $force Forces a reload of board names
     */
    private static function loadBoardNames($force = FALSE)
    {
        global $language;
        if ($force || (self::$boardNames = CacheAPI::getCache('simplesef_board_list', 3600)) == NULL) {
            loadLanguage('index', $language, false);
            $request = smf_db_query('
				SELECT id_board, name
				FROM {db_prefix}boards', array());
            $boards = array();
            while ($row = mysql_fetch_assoc($request)) {
                // A bit extra overhead to account for duplicate board names
                $temp_name = self::encode($row['name']);
                $i = 0;
                while (!empty($boards[$temp_name . (!empty($i) ? $i + 1 : '')])) {
                    $i++;
                }
                //$boards[$temp_name . (!empty($i) ? $i + 1 : '')] = $row['id_board'];
                $boards[$temp_name . '.' . trim($row['id_board'])] = $row['id_board'];
            }
            mysql_free_result($request);
            self::$boardNames = array_flip($boards);
            // Add one to the query cound and put the data into the cache
            self::$queryCount++;
            CacheAPI::putCache('simplesef_board_list', self::$boardNames, 3600);
            //self::log('Cache hit failed, reloading board names');
        }
    }
Ejemplo n.º 25
0
function show_db_error($loadavg = false)
{
    global $sourcedir, $mbname, $maintenance, $mtitle, $mmessage, $modSettings;
    global $db_connection, $webmaster_email, $db_last_error, $db_error_send, $smcFunc;
    // Don't cache this page!
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
    header('Cache-Control: no-cache');
    // Send the right error codes.
    header('HTTP/1.1 503 Service Temporarily Unavailable');
    header('Status: 503 Service Temporarily Unavailable');
    header('Retry-After: 3600');
    if ($loadavg == false) {
        // For our purposes, we're gonna want this on if at all possible.
        $modSettings['cache_enable'] = '1';
        if (($temp = CacheAPI::getCache('db_last_error', 600)) !== null) {
            $db_last_error = max($db_last_error, $temp);
        }
        if ($db_last_error < time() - 3600 * 24 * 3 && empty($maintenance) && !empty($db_error_send)) {
            require_once $sourcedir . '/lib/Subs-Admin.php';
            // Avoid writing to the Settings.php file if at all possible; use shared memory instead.
            CacheAPI::putCache('db_last_error', time(), 600);
            if (($temp = CacheAPI::getCache('db_last_error', 600)) == null) {
                updateLastDatabaseError();
            }
            // Language files aren't loaded yet :(.
            $db_error = @mysql_error($db_connection);
            @mail($webmaster_email, $mbname . ': SMF Database Error!', 'There has been a problem with the database!' . ($db_error == '' ? '' : "\n" . 'MySQL' . ' reported:' . "\n" . $db_error) . "\n\n" . 'This is a notice email to let you know that SMF could not connect to the database, contact your host if this continues.');
        }
    }
    if (!empty($maintenance)) {
        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta name="robots" content="noindex" />
		<title>', $mtitle, '</title>
	</head>
	<body>
		<h3>', $mtitle, '</h3>
		', $mmessage, '
	</body>
</html>';
    } elseif ($loadavg) {
        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta name="robots" content="noindex" />
		<title>Temporarily Unavailable</title>
	</head>
	<body>
		<h3>Temporarily Unavailable</h3>
		Due to high stress on the server the forum is temporarily unavailable.  Please try again later.
	</body>
</html>';
    } else {
        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
	<head>
		<meta name="robots" content="noindex" />
		<title>Connection Problems</title>
	</head>
	<body>
		<h3>Connection Problems</h3>
		Sorry, SMF was unable to connect to the database.  This may be caused by the server being busy.  Please try again later.
	</body>
</html>';
    }
    die;
}
Ejemplo n.º 26
0
function PlushSearch2()
{
    global $scripturl, $modSettings, $sourcedir, $txt;
    global $user_info, $context, $options, $messages_request, $boards_can;
    global $excludedWords, $participants, $search_versions, $searchAPI;
    if (!empty($context['load_average']) && !empty($modSettings['loadavg_search']) && $context['load_average'] >= $modSettings['loadavg_search']) {
        fatal_lang_error('loadavg_search_disabled', false);
    }
    $_ctx = new SearchContext();
    // No, no, no... this is a bit hard on the server, so don't you go prefetching it!
    if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') {
        ob_end_clean();
        header('HTTP/1.1 403 Forbidden');
        die;
    }
    $weight_factors = array('frequency', 'age', 'length', 'subject', 'first_message', 'sticky');
    $weight = array();
    $weight_total = 0;
    foreach ($weight_factors as $weight_factor) {
        $weight[$weight_factor] = empty($modSettings['search_weight_' . $weight_factor]) ? 0 : (int) $modSettings['search_weight_' . $weight_factor];
        $weight_total += $weight[$weight_factor];
    }
    // Zero weight.  Weightless :P.
    if (empty($weight_total)) {
        fatal_lang_error('search_invalid_weights');
    }
    // These vars don't require an interface, they're just here for tweaking.
    $recentPercentage = 0.3;
    $humungousTopicPosts = 200;
    $maxMembersToSearch = 500;
    $maxMessageResults = empty($modSettings['search_max_results']) ? 0 : $modSettings['search_max_results'] * 5;
    // Start with no errors.
    $context['search_errors'] = array();
    // Number of pages hard maximum - normally not set at all.
    $modSettings['search_max_results'] = empty($modSettings['search_max_results']) ? 200 * $modSettings['search_results_per_page'] : (int) $modSettings['search_max_results'];
    // Maximum length of the string.
    $context['search_string_limit'] = 100;
    loadLanguage('Search');
    // Are you allowed?
    isAllowedTo('search_posts');
    require_once $sourcedir . '/Display.php';
    require_once $sourcedir . '/lib/Subs-Package.php';
    // Search has a special database set.
    db_extend('search');
    // Load up the search API we are going to use.
    $modSettings['search_index'] = empty($modSettings['search_index']) ? 'standard' : $modSettings['search_index'];
    if (!file_exists($sourcedir . '/SearchAPI-' . ucwords($modSettings['search_index']) . '.php')) {
        fatal_lang_error('search_api_missing');
    }
    loadClassFile('SearchAPI-' . ucwords($modSettings['search_index']) . '.php');
    // Create an instance of the search API and check it is valid for this version of SMF.
    $search_class_name = $modSettings['search_index'] . '_search';
    $searchAPI = new $search_class_name();
    if (!$searchAPI || $searchAPI->supportsMethod('isValid') && !$searchAPI->isValid() || !matchPackageVersion($search_versions['forum_version'], $searchAPI->min_smf_version . '-' . $searchAPI->version_compatible)) {
        // Log the error.
        loadLanguage('Errors');
        log_error(sprintf($txt['search_api_not_compatible'], 'SearchAPI-' . ucwords($modSettings['search_index']) . '.php'), 'critical');
        loadClassFile('SearchAPI-Standard.php');
        $searchAPI = new standard_search();
    }
    // $search_params will carry all settings that differ from the default search parameters.
    // That way, the URLs involved in a search page will be kept as short as possible.
    $search_params = array();
    if (isset($_REQUEST['params'])) {
        // Due to IE's 2083 character limit, we have to compress long search strings
        $temp_params = base64_decode(str_replace(array('-', '_', '.'), array('+', '/', '='), $_REQUEST['params']));
        // Test for gzuncompress failing
        $temp_params2 = @gzuncompress($temp_params);
        $temp_params = explode('|"|', !empty($temp_params2) ? $temp_params2 : $temp_params);
        foreach ($temp_params as $i => $data) {
            @(list($k, $v) = explode('|\'|', $data));
            $search_params[$k] = $v;
        }
        if (isset($search_params['brd'])) {
            $search_params['brd'] = empty($search_params['brd']) ? array() : explode(',', $search_params['brd']);
        }
    }
    // Store whether simple search was used (needed if the user wants to do another query).
    if (!isset($search_params['advanced'])) {
        $search_params['advanced'] = empty($_REQUEST['advanced']) ? 0 : 1;
    }
    // 1 => 'allwords' (default, don't set as param) / 2 => 'anywords'.
    if (!empty($search_params['searchtype']) || !empty($_REQUEST['searchtype']) && $_REQUEST['searchtype'] == 2) {
        $search_params['searchtype'] = 2;
    }
    // Minimum age of messages. Default to zero (don't set param in that case).
    if (!empty($search_params['minage']) || !empty($_REQUEST['minage']) && $_REQUEST['minage'] > 0) {
        $search_params['minage'] = !empty($search_params['minage']) ? (int) $search_params['minage'] : (int) $_REQUEST['minage'];
    }
    // Maximum age of messages. Default to infinite (9999 days: param not set).
    if (!empty($search_params['maxage']) || !empty($_REQUEST['maxage']) && $_REQUEST['maxage'] < 9999) {
        $search_params['maxage'] = !empty($search_params['maxage']) ? (int) $search_params['maxage'] : (int) $_REQUEST['maxage'];
    }
    // Searching a specific topic?
    if (!empty($_REQUEST['topic'])) {
        $search_params['topic'] = (int) $_REQUEST['topic'];
        $search_params['show_complete'] = true;
    } elseif (!empty($search_params['topic'])) {
        $search_params['topic'] = (int) $search_params['topic'];
    }
    if (!empty($search_params['minage']) || !empty($search_params['maxage'])) {
        $request = smf_db_query('
			SELECT ' . (empty($search_params['maxage']) ? '0, ' : 'IFNULL(MIN(id_msg), -1), ') . (empty($search_params['minage']) ? '0' : 'IFNULL(MAX(id_msg), -1)') . '
			FROM {db_prefix}messages
			WHERE 1=1' . ($modSettings['postmod_active'] ? '
				AND approved = {int:is_approved_true}' : '') . (empty($search_params['minage']) ? '' : '
				AND poster_time <= {int:timestamp_minimum_age}') . (empty($search_params['maxage']) ? '' : '
				AND poster_time >= {int:timestamp_maximum_age}'), array('timestamp_minimum_age' => empty($search_params['minage']) ? 0 : time() - 86400 * $search_params['minage'], 'timestamp_maximum_age' => empty($search_params['maxage']) ? 0 : time() - 86400 * $search_params['maxage'], 'is_approved_true' => 1));
        list($minMsgID, $maxMsgID) = mysql_fetch_row($request);
        if ($minMsgID < 0 || $maxMsgID < 0) {
            $context['search_errors']['no_messages_in_time_frame'] = true;
        }
        mysql_free_result($request);
    }
    // Default the user name to a wildcard matching every user (*).
    if (!empty($search_params['userspec']) || !empty($_REQUEST['userspec']) && $_REQUEST['userspec'] != '*') {
        $search_params['userspec'] = isset($search_params['userspec']) ? $search_params['userspec'] : $_REQUEST['userspec'];
    }
    // If there's no specific user, then don't mention it in the main query.
    if (empty($search_params['userspec'])) {
        $userQuery = '';
    } else {
        $userString = strtr(commonAPI::htmlspecialchars($search_params['userspec'], ENT_QUOTES), array('&quot;' => '"'));
        $userString = strtr($userString, array('%' => '\\%', '_' => '\\_', '*' => '%', '?' => '_'));
        preg_match_all('~"([^"]+)"~', $userString, $matches);
        $possible_users = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $userString)));
        for ($k = 0, $n = count($possible_users); $k < $n; $k++) {
            $possible_users[$k] = trim($possible_users[$k]);
            if (strlen($possible_users[$k]) == 0) {
                unset($possible_users[$k]);
            }
        }
        // Create a list of database-escaped search names.
        $realNameMatches = array();
        foreach ($possible_users as $possible_user) {
            $realNameMatches[] = smf_db_quote('{string:possible_user}', array('possible_user' => $possible_user));
        }
        // Retrieve a list of possible members.
        $request = smf_db_query('
			SELECT id_member
			FROM {db_prefix}members
			WHERE {raw:match_possible_users}', array('match_possible_users' => 'real_name LIKE ' . implode(' OR real_name LIKE ', $realNameMatches)));
        // Simply do nothing if there're too many members matching the criteria.
        if (mysql_num_rows($request) > $maxMembersToSearch) {
            $userQuery = '';
        } elseif (mysql_num_rows($request) == 0) {
            $userQuery = smf_db_quote('m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})', array('id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches)));
        } else {
            $memberlist = array();
            while ($row = mysql_fetch_assoc($request)) {
                $memberlist[] = $row['id_member'];
            }
            $userQuery = smf_db_quote('(m.id_member IN ({array_int:matched_members}) OR (m.id_member = {int:id_member_guest} AND ({raw:match_possible_guest_names})))', array('matched_members' => $memberlist, 'id_member_guest' => 0, 'match_possible_guest_names' => 'm.poster_name LIKE ' . implode(' OR m.poster_name LIKE ', $realNameMatches)));
        }
        mysql_free_result($request);
    }
    // If the boards were passed by URL (params=), temporarily put them back in $_REQUEST.
    if (!empty($search_params['brd']) && is_array($search_params['brd'])) {
        $_REQUEST['brd'] = $search_params['brd'];
    }
    // Ensure that brd is an array.
    if (!empty($_REQUEST['brd']) && !is_array($_REQUEST['brd'])) {
        $_REQUEST['brd'] = strpos($_REQUEST['brd'], ',') !== false ? explode(',', $_REQUEST['brd']) : array($_REQUEST['brd']);
    }
    // Make sure all boards are integers.
    if (!empty($_REQUEST['brd'])) {
        foreach ($_REQUEST['brd'] as $id => $brd) {
            $_REQUEST['brd'][$id] = (int) $brd;
        }
    }
    // Special case for boards: searching just one topic?
    if (!empty($search_params['topic'])) {
        $request = smf_db_query('
			SELECT b.id_board
			FROM {db_prefix}topics AS t
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
			WHERE t.id_topic = {int:search_topic_id}
				AND {query_see_board}' . ($modSettings['postmod_active'] ? '
				AND t.approved = {int:is_approved_true}' : '') . '
			LIMIT 1', array('search_topic_id' => $search_params['topic'], 'is_approved_true' => 1));
        if (mysql_num_rows($request) == 0) {
            fatal_lang_error('topic_gone', false);
        }
        $search_params['brd'] = array();
        list($search_params['brd'][0]) = mysql_fetch_row($request);
        mysql_free_result($request);
    } elseif ($user_info['is_admin'] && (!empty($search_params['advanced']) || !empty($_REQUEST['brd']))) {
        $search_params['brd'] = empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'];
    } else {
        $see_board = empty($search_params['advanced']) ? 'query_wanna_see_board' : 'query_see_board';
        $request = smf_db_query('
			SELECT b.id_board
			FROM {db_prefix}boards AS b
			WHERE {raw:boards_allowed_to_see}
				AND redirect = {string:empty_string}' . (empty($_REQUEST['brd']) ? !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] > 0 ? '
				AND b.id_board != {int:recycle_board_id}' : '' : '
				AND b.id_board IN ({array_int:selected_search_boards})'), array('boards_allowed_to_see' => $user_info[$see_board], 'empty_string' => '', 'selected_search_boards' => empty($_REQUEST['brd']) ? array() : $_REQUEST['brd'], 'recycle_board_id' => $modSettings['recycle_board']));
        $search_params['brd'] = array();
        while ($row = mysql_fetch_assoc($request)) {
            $search_params['brd'][] = $row['id_board'];
        }
        mysql_free_result($request);
        // This error should pro'bly only happen for hackers.
        if (empty($search_params['brd'])) {
            $context['search_errors']['no_boards_selected'] = true;
        }
    }
    if (count($search_params['brd']) != 0) {
        foreach ($search_params['brd'] as $k => $v) {
            $search_params['brd'][$k] = (int) $v;
        }
        // If we've selected all boards, this parameter can be left empty.
        $request = smf_db_query('
			SELECT COUNT(*)
			FROM {db_prefix}boards
			WHERE redirect = {string:empty_string}', array('empty_string' => ''));
        list($num_boards) = mysql_fetch_row($request);
        mysql_free_result($request);
        if (count($search_params['brd']) == $num_boards) {
            $boardQuery = '';
        } elseif (count($search_params['brd']) == $num_boards - 1 && !empty($modSettings['recycle_board']) && !in_array($modSettings['recycle_board'], $search_params['brd'])) {
            $boardQuery = '!= ' . $modSettings['recycle_board'];
        } else {
            $boardQuery = 'IN (' . implode(', ', $search_params['brd']) . ')';
        }
    } else {
        $boardQuery = '';
    }
    $search_params['show_complete'] = !empty($search_params['show_complete']) || !empty($_REQUEST['show_complete']);
    $search_params['subject_only'] = !empty($search_params['subject_only']) || !empty($_REQUEST['subject_only']);
    $context['compact'] = !$search_params['show_complete'];
    EoS_Smarty::loadTemplate('search/base');
    if (!isset($_REQUEST['xml'])) {
        EoS_Smarty::getConfigInstance()->registerHookTemplate('search_content_area', $context['compact'] ? 'search/results_compact' : 'search/results_as_messages');
    } else {
        EoS_Smarty::getConfigInstance()->registerHookTemplate('search_content_area', 'search/results_xml');
    }
    // Get the sorting parameters right. Default to sort by relevance descending.
    $sort_columns = array('relevance', 'num_replies', 'id_msg');
    if (empty($search_params['sort']) && !empty($_REQUEST['sort'])) {
        list($search_params['sort'], $search_params['sort_dir']) = array_pad(explode('|', $_REQUEST['sort']), 2, '');
    }
    $search_params['sort'] = !empty($search_params['sort']) && in_array($search_params['sort'], $sort_columns) ? $search_params['sort'] : 'relevance';
    if (!empty($search_params['topic']) && $search_params['sort'] === 'num_replies') {
        $search_params['sort'] = 'id_msg';
    }
    // Sorting direction: descending unless stated otherwise.
    $search_params['sort_dir'] = !empty($search_params['sort_dir']) && $search_params['sort_dir'] == 'asc' ? 'asc' : 'desc';
    // Determine some values needed to calculate the relevance.
    $minMsg = (int) ((1 - $recentPercentage) * $modSettings['maxMsgID']);
    $recentMsg = $modSettings['maxMsgID'] - $minMsg;
    // *** Parse the search query
    // Unfortunately, searching for words like this is going to be slow, so we're blacklisting them.
    // !!! Setting to add more here?
    // !!! Maybe only blacklist if they are the only word, or "any" is used?
    $blacklisted_words = array('img', 'url', 'quote', 'www', 'http', 'the', 'is', 'it', 'are', 'if');
    // What are we searching for?
    if (empty($search_params['search'])) {
        if (isset($_GET['search'])) {
            $search_params['search'] = un_htmlspecialchars($_GET['search']);
        } elseif (isset($_POST['search'])) {
            $search_params['search'] = $_POST['search'];
        } else {
            $search_params['search'] = '';
        }
    }
    // Nothing??
    if (!isset($search_params['search']) || $search_params['search'] == '') {
        $context['search_errors']['invalid_search_string'] = true;
    } elseif (commonAPI::strlen($search_params['search']) > $context['search_string_limit']) {
        $context['search_errors']['string_too_long'] = true;
        $txt['error_string_too_long'] = sprintf($txt['error_string_too_long'], $context['search_string_limit']);
    }
    // Change non-word characters into spaces.
    $stripped_query = preg_replace('~(?:[\\x0B\\0' . ($context['server']['complex_preg_chars'] ? '\\x{A0}' : " ") . '\\t\\r\\s\\n(){}\\[\\]<>!@$%^*.,:+=`\\~\\?/\\\\]+|&(?:amp|lt|gt|quot);)+~u', ' ', $search_params['search']);
    // Make the query lower case. It's gonna be case insensitive anyway.
    $stripped_query = un_htmlspecialchars(commonAPI::strtolower($stripped_query));
    // This (hidden) setting will do fulltext searching in the most basic way.
    if (!empty($modSettings['search_simple_fulltext'])) {
        $stripped_query = strtr($stripped_query, array('"' => ''));
    }
    $no_regexp = preg_match('~&#(?:\\d{1,7}|x[0-9a-fA-F]{1,6});~', $stripped_query) === 1;
    // Extract phrase parts first (e.g. some words "this is a phrase" some more words.)
    preg_match_all('/(?:^|\\s)([-]?)"([^"]+)"(?:$|\\s)/', $stripped_query, $matches, PREG_PATTERN_ORDER);
    $phraseArray = $matches[2];
    // Remove the phrase parts and extract the words.
    $wordArray = explode(' ', preg_replace('~(?:^|\\s)(?:[-]?)"(?:[^"]+)"(?:$|\\s)~u', ' ', $search_params['search']));
    // A minus sign in front of a word excludes the word.... so...
    $excludedWords = array();
    $excludedIndexWords = array();
    $excludedSubjectWords = array();
    $excludedPhrases = array();
    // .. first, we check for things like -"some words", but not "-some words".
    foreach ($matches[1] as $index => $word) {
        if ($word === '-') {
            if (($word = trim($phraseArray[$index], '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = $word;
            }
            unset($phraseArray[$index]);
        }
    }
    // Now we look for -test, etc.... normaller.
    foreach ($wordArray as $index => $word) {
        if (strpos(trim($word), '-') === 0) {
            if (($word = trim($word, '-_\' ')) !== '' && !in_array($word, $blacklisted_words)) {
                $excludedWords[] = $word;
            }
            unset($wordArray[$index]);
        }
    }
    // The remaining words and phrases are all included.
    $searchArray = array_merge($phraseArray, $wordArray);
    // Trim everything and make sure there are no words that are the same.
    foreach ($searchArray as $index => $value) {
        // Skip anything practically empty.
        if (($searchArray[$index] = trim($value, '-_\' ')) === '') {
            unset($searchArray[$index]);
        } elseif (in_array($searchArray[$index], $blacklisted_words)) {
            $foundBlackListedWords = true;
            unset($searchArray[$index]);
        } elseif (commonAPI::strlen($value) < 2) {
            $context['search_errors']['search_string_small_words'] = true;
            unset($searchArray[$index]);
        } else {
            $searchArray[$index] = $searchArray[$index];
        }
    }
    $searchArray = array_slice(array_unique($searchArray), 0, 10);
    // Create an array of replacements for highlighting.
    $context['mark'] = array();
    foreach ($searchArray as $word) {
        $context['mark'][$word] = '<strong class="highlight">' . $word . '</strong>';
    }
    // Initialize two arrays storing the words that have to be searched for.
    $orParts = array();
    $searchWords = array();
    // Make sure at least one word is being searched for.
    if (empty($searchArray)) {
        $context['search_errors']['invalid_search_string' . (!empty($foundBlackListedWords) ? '_blacklist' : '')] = true;
    } elseif (empty($search_params['searchtype'])) {
        $orParts[0] = $searchArray;
    } else {
        foreach ($searchArray as $index => $value) {
            $orParts[$index] = array($value);
        }
    }
    // Don't allow duplicate error messages if one string is too short.
    if (isset($context['search_errors']['search_string_small_words'], $context['search_errors']['invalid_search_string'])) {
        unset($context['search_errors']['invalid_search_string']);
    }
    // Make sure the excluded words are in all or-branches.
    foreach ($orParts as $orIndex => $andParts) {
        foreach ($excludedWords as $word) {
            $orParts[$orIndex][] = $word;
        }
    }
    // Determine the or-branches and the fulltext search words.
    foreach ($orParts as $orIndex => $andParts) {
        $searchWords[$orIndex] = array('indexed_words' => array(), 'words' => array(), 'subject_words' => array(), 'all_words' => array());
        // Sort the indexed words (large words -> small words -> excluded words).
        if ($searchAPI->supportsMethod('searchSort')) {
            usort($orParts[$orIndex], 'searchSort');
        }
        foreach ($orParts[$orIndex] as $word) {
            $is_excluded = in_array($word, $excludedWords);
            $searchWords[$orIndex]['all_words'][] = $word;
            $subjectWords = text2words($word);
            if (!$is_excluded || count($subjectWords) === 1) {
                $searchWords[$orIndex]['subject_words'] = array_merge($searchWords[$orIndex]['subject_words'], $subjectWords);
                if ($is_excluded) {
                    $excludedSubjectWords = array_merge($excludedSubjectWords, $subjectWords);
                }
            } else {
                $excludedPhrases[] = $word;
            }
            // Have we got indexes to prepare?
            if ($searchAPI->supportsMethod('prepareIndexes')) {
                $searchAPI->prepareIndexes($word, $searchWords[$orIndex], $excludedIndexWords, $is_excluded);
            }
        }
        // Search_force_index requires all AND parts to have at least one fulltext word.
        if (!empty($modSettings['search_force_index']) && empty($searchWords[$orIndex]['indexed_words'])) {
            $context['search_errors']['query_not_specific_enough'] = true;
            break;
        } elseif ($search_params['subject_only'] && empty($searchWords[$orIndex]['subject_words']) && empty($excludedSubjectWords)) {
            $context['search_errors']['query_not_specific_enough'] = true;
            break;
        } else {
            $searchWords[$orIndex]['indexed_words'] = array_slice($searchWords[$orIndex]['indexed_words'], 0, 7);
            $searchWords[$orIndex]['subject_words'] = array_slice($searchWords[$orIndex]['subject_words'], 0, 7);
        }
    }
    // Let the user adjust the search query, should they wish?
    $context['search_params'] = $search_params;
    if (isset($context['search_params']['search'])) {
        $context['search_params']['search'] = commonAPI::htmlspecialchars($context['search_params']['search']);
    }
    if (isset($context['search_params']['userspec'])) {
        $context['search_params']['userspec'] = commonAPI::htmlspecialchars($context['search_params']['userspec']);
    }
    // Do we have captcha enabled?
    if ($user_info['is_guest'] && !empty($modSettings['search_enable_captcha']) && empty($_SESSION['ss_vv_passed']) && (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search'])) {
        // If we come from another search box tone down the error...
        if (!isset($_REQUEST['search_vv'])) {
            $context['search_errors']['need_verification_code'] = true;
        } else {
            require_once $sourcedir . '/lib/Subs-Editor.php';
            $verificationOptions = array('id' => 'search', 'skip_template' => true);
            $context['require_verification'] = create_control_verification($verificationOptions, true);
            if (is_array($context['require_verification'])) {
                foreach ($context['require_verification'] as $error) {
                    $context['search_errors'][$error] = true;
                }
            } else {
                $_SESSION['ss_vv_passed'] = true;
            }
        }
    }
    // *** Encode all search params
    // All search params have been checked, let's compile them to a single string... made less simple by PHP 4.3.9 and below.
    $temp_params = $search_params;
    if (isset($temp_params['brd'])) {
        $temp_params['brd'] = implode(',', $temp_params['brd']);
    }
    $context['params'] = array();
    foreach ($temp_params as $k => $v) {
        $context['params'][] = $k . '|\'|' . $v;
    }
    if (!empty($context['params'])) {
        // Due to old IE's 2083 character limit, we have to compress long search strings
        $params = @gzcompress(implode('|"|', $context['params']));
        // Gzcompress failed, use try non-gz
        if (empty($params)) {
            $params = implode('|"|', $context['params']);
        }
        // Base64 encode, then replace +/= with uri safe ones that can be reverted
        $context['params'] = str_replace(array('+', '/', '='), array('-', '_', '.'), base64_encode($params));
    }
    // ... and add the links to the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?action=search;params=' . $context['params'], 'name' => $txt['search']);
    $context['linktree'][] = array('url' => $scripturl . '?action=search2;params=' . $context['params'], 'name' => $txt['search_results']);
    // *** A last error check
    // One or more search errors? Go back to the first search screen.
    if (!empty($context['search_errors'])) {
        $_REQUEST['params'] = $context['params'];
        EoS_Smarty::resetTemplates();
        return PlushSearch1();
    }
    // Spam me not, Spam-a-lot?
    if (empty($_SESSION['last_ss']) || $_SESSION['last_ss'] != $search_params['search']) {
        spamProtection('search');
    }
    // Store the last search string to allow pages of results to be browsed.
    $_SESSION['last_ss'] = $search_params['search'];
    // *** Reserve an ID for caching the search results.
    $query_params = array_merge($search_params, array('min_msg_id' => isset($minMsgID) ? (int) $minMsgID : 0, 'max_msg_id' => isset($maxMsgID) ? (int) $maxMsgID : 0, 'memberlist' => !empty($memberlist) ? $memberlist : array()));
    // Can this search rely on the API given the parameters?
    if ($searchAPI->supportsMethod('searchQuery', $query_params)) {
        $participants = array();
        $searchArray = array();
        $num_results = $searchAPI->searchQuery($query_params, $searchWords, $excludedIndexWords, $participants, $searchArray);
    } else {
        log_error('update cache');
        $update_cache = empty($_SESSION['search_cache']) || $_SESSION['search_cache']['params'] != $context['params'];
        if ($update_cache) {
            // Increase the pointer...
            $modSettings['search_pointer'] = empty($modSettings['search_pointer']) ? 0 : (int) $modSettings['search_pointer'];
            // ...and store it right off.
            updateSettings(array('search_pointer' => $modSettings['search_pointer'] >= 255 ? 0 : $modSettings['search_pointer'] + 1));
            // As long as you don't change the parameters, the cache result is yours.
            $_SESSION['search_cache'] = array('id_search' => $modSettings['search_pointer'], 'num_results' => -1, 'params' => $context['params']);
            // Clear the previous cache of the final results cache.
            smf_db_query('
				DELETE FROM {db_prefix}log_search_results
				WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search']));
            if ($search_params['subject_only']) {
                // We do this to try and avoid duplicate keys on databases not supporting INSERT IGNORE.
                $inserts = array();
                foreach ($searchWords as $orIndex => $words) {
                    $subject_query_params = array();
                    $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array());
                    if ($modSettings['postmod_active']) {
                        $subject_query['where'][] = 't.approved = {int:is_approved}';
                    }
                    $numTables = 0;
                    $prev_join = 0;
                    $numSubjectResults = 0;
                    foreach ($words['subject_words'] as $subjectWord) {
                        $numTables++;
                        if (in_array($subjectWord, $excludedSubjectWords)) {
                            $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)';
                            $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)';
                        } else {
                            $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)';
                            $subject_query['where'][] = 'subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_words_' . $numTables . '_wild}' : '= {string:subject_words_' . $numTables . '}');
                            $prev_join = $numTables;
                        }
                        $subject_query_params['subject_words_' . $numTables] = $subjectWord;
                        $subject_query_params['subject_words_' . $numTables . '_wild'] = '%' . $subjectWord . '%';
                    }
                    if (!empty($userQuery)) {
                        if ($subject_query['from'] != '{db_prefix}messages AS m') {
                            $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_topic = t.id_topic)';
                        }
                        $subject_query['where'][] = $userQuery;
                    }
                    if (!empty($search_params['topic'])) {
                        $subject_query['where'][] = 't.id_topic = ' . $search_params['topic'];
                    }
                    if (!empty($minMsgID)) {
                        $subject_query['where'][] = 't.id_first_msg >= ' . $minMsgID;
                    }
                    if (!empty($maxMsgID)) {
                        $subject_query['where'][] = 't.id_last_msg <= ' . $maxMsgID;
                    }
                    if (!empty($boardQuery)) {
                        $subject_query['where'][] = 't.id_board ' . $boardQuery;
                    }
                    if (!empty($excludedPhrases)) {
                        if ($subject_query['from'] != '{db_prefix}messages AS m') {
                            $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                        }
                        $count = 0;
                        foreach ($excludedPhrases as $phrase) {
                            $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:excluded_phrases_' . $count . '}';
                            $subject_query_params['excluded_phrases_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]';
                        }
                    }
                    $ignoreRequest = smf_db_query((1 ? '
						INSERT IGNORE INTO {db_prefix}log_search_results
							(id_search, id_topic, relevance, id_msg, num_matches)' : '') . '
						SELECT
							{int:id_search},
							t.id_topic,
							1000 * (
								{int:weight_frequency} / (t.num_replies + 1) +
								{int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END +
								{int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END +
								{int:weight_subject} +
								{int:weight_sticky} * t.is_sticky
							) / {int:weight_total} AS relevance,
							' . (empty($userQuery) ? 't.id_first_msg' : 'm.id_msg') . ',
							1
						FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : '
							INNER JOIN ' . implode('
							INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : '
							LEFT JOIN ' . implode('
							LEFT JOIN ', $subject_query['left_join'])) . '
						WHERE ' . implode('
							AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), array_merge($subject_query_params, array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['length'], 'weight_sticky' => $weight['sticky'], 'weight_subject' => $weight['subject'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1)));
                    $numSubjectResults += smf_db_affected_rows();
                    if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                        break;
                    }
                }
                // If there's data to be inserted for non-IGNORE databases do it here!
                if (!empty($inserts)) {
                    smf_db_insert('', '{db_prefix}log_search_results', array('id_search' => 'int', 'id_topic' => 'int', 'relevance' => 'int', 'id_msg' => 'int', 'num_matches' => 'int'), $inserts, array('id_search', 'id_topic'));
                }
                $_SESSION['search_cache']['num_results'] = $numSubjectResults;
            } else {
                $main_query = array('select' => array('id_search' => $_SESSION['search_cache']['id_search'], 'relevance' => '0'), 'weights' => array(), 'from' => '{db_prefix}topics AS t', 'inner_join' => array('{db_prefix}messages AS m ON (m.id_topic = t.id_topic)'), 'left_join' => array(), 'where' => array(), 'group_by' => array(), 'parameters' => array('min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts, 'is_approved' => 1));
                if (empty($search_params['topic']) && empty($search_params['show_complete'])) {
                    $main_query['select']['id_topic'] = 't.id_topic';
                    $main_query['select']['id_msg'] = 'MAX(m.id_msg) AS id_msg';
                    $main_query['select']['num_matches'] = 'COUNT(*) AS num_matches';
                    $main_query['weights'] = array('frequency' => 'COUNT(*) / (MAX(t.num_replies) + 1)', 'age' => 'CASE WHEN MAX(m.id_msg) < {int:min_msg} THEN 0 ELSE (MAX(m.id_msg) - {int:min_msg}) / {int:recent_message} END', 'length' => 'CASE WHEN MAX(t.num_replies) < {int:huge_topic_posts} THEN MAX(t.num_replies) / {int:huge_topic_posts} ELSE 1 END', 'subject' => '0', 'first_message' => 'CASE WHEN MIN(m.id_msg) = MAX(t.id_first_msg) THEN 1 ELSE 0 END', 'sticky' => 'MAX(t.is_sticky)');
                    $main_query['group_by'][] = 't.id_topic';
                } else {
                    // This is outrageous!
                    $main_query['select']['id_topic'] = 'm.id_msg AS id_topic';
                    $main_query['select']['id_msg'] = 'm.id_msg';
                    $main_query['select']['num_matches'] = '1 AS num_matches';
                    $main_query['weights'] = array('age' => '((m.id_msg - t.id_first_msg) / CASE WHEN t.id_last_msg = t.id_first_msg THEN 1 ELSE t.id_last_msg - t.id_first_msg END)', 'first_message' => 'CASE WHEN m.id_msg = t.id_first_msg THEN 1 ELSE 0 END');
                    if (!empty($search_params['topic'])) {
                        $main_query['where'][] = 't.id_topic = {int:topic}';
                        $main_query['parameters']['topic'] = $search_params['topic'];
                    }
                    if (!empty($search_params['show_complete'])) {
                        $main_query['group_by'][] = 'm.id_msg, t.id_first_msg, t.id_last_msg';
                    }
                }
                // *** Get the subject results.
                $numSubjectResults = 0;
                if (empty($search_params['topic'])) {
                    $inserts = array();
                    // Create a temporary table to store some preliminary results in.
                    smf_db_query('
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_topics', array('db_error_skip' => true));
                    $createTemporary = smf_db_query('
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_topics (
							id_topic mediumint(8) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_topic)
						) TYPE=HEAP', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clean up some previous cache.
                    if (!$createTemporary) {
                        smf_db_query('
							DELETE FROM {db_prefix}log_search_topics
							WHERE id_search = {int:search_id}', array('search_id' => $_SESSION['search_cache']['id_search']));
                    }
                    foreach ($searchWords as $orIndex => $words) {
                        $subject_query = array('from' => '{db_prefix}topics AS t', 'inner_join' => array(), 'left_join' => array(), 'where' => array(), 'params' => array());
                        $numTables = 0;
                        $prev_join = 0;
                        $count = 0;
                        foreach ($words['subject_words'] as $subjectWord) {
                            $numTables++;
                            if (in_array($subjectWord, $excludedSubjectWords)) {
                                if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                    $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                                }
                                $subject_query['left_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.word ' . (empty($modSettings['search_match_words']) ? 'LIKE {string:subject_not_' . $count . '}' : '= {string:subject_not_' . $count . '}') . ' AND subj' . $numTables . '.id_topic = t.id_topic)';
                                $subject_query['params']['subject_not_' . $count] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord;
                                $subject_query['where'][] = '(subj' . $numTables . '.word IS NULL)';
                                $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:body_not_' . $count . '}';
                                $subject_query['params']['body_not_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($subjectWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $subjectWord), '\\\'') . '[[:>:]]';
                            } else {
                                $subject_query['inner_join'][] = '{db_prefix}log_search_subjects AS subj' . $numTables . ' ON (subj' . $numTables . '.id_topic = ' . ($prev_join === 0 ? 't' : 'subj' . $prev_join) . '.id_topic)';
                                $subject_query['where'][] = 'subj' . $numTables . '.word LIKE {string:subject_like_' . $count . '}';
                                $subject_query['params']['subject_like_' . $count++] = empty($modSettings['search_match_words']) ? '%' . $subjectWord . '%' : $subjectWord;
                                $prev_join = $numTables;
                            }
                        }
                        if (!empty($userQuery)) {
                            if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                            }
                            $subject_query['where'][] = '{raw:user_query}';
                            $subject_query['params']['user_query'] = $userQuery;
                        }
                        if (!empty($search_params['topic'])) {
                            $subject_query['where'][] = 't.id_topic = {int:topic}';
                            $subject_query['params']['topic'] = $search_params['topic'];
                        }
                        if (!empty($minMsgID)) {
                            $subject_query['where'][] = 't.id_first_msg >= {int:min_msg_id}';
                            $subject_query['params']['min_msg_id'] = $minMsgID;
                        }
                        if (!empty($maxMsgID)) {
                            $subject_query['where'][] = 't.id_last_msg <= {int:max_msg_id}';
                            $subject_query['params']['max_msg_id'] = $maxMsgID;
                        }
                        if (!empty($boardQuery)) {
                            $subject_query['where'][] = 't.id_board {raw:board_query}';
                            $subject_query['params']['board_query'] = $boardQuery;
                        }
                        if (!empty($excludedPhrases)) {
                            if ($subject_query['from'] != '{db_prefix}messages AS m') {
                                $subject_query['inner_join'][] = '{db_prefix}messages AS m ON (m.id_msg = t.id_first_msg)';
                            }
                            $count = 0;
                            foreach ($excludedPhrases as $phrase) {
                                $subject_query['where'][] = 'm.subject NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}';
                                $subject_query['where'][] = 'm.body NOT ' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:exclude_phrase_' . $count . '}';
                                $subject_query['params']['exclude_phrase_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($phrase, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $phrase), '\\\'') . '[[:>:]]';
                            }
                        }
                        // Nothing to search for?
                        if (empty($subject_query['where'])) {
                            continue;
                        }
                        $ignoreRequest = smf_db_query((1 ? '
							INSERT IGNORE INTO {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics
								(' . ($createTemporary ? '' : 'id_search, ') . 'id_topic)' : '') . '
							SELECT ' . ($createTemporary ? '' : $_SESSION['search_cache']['id_search'] . ', ') . 't.id_topic
							FROM ' . $subject_query['from'] . (empty($subject_query['inner_join']) ? '' : '
								INNER JOIN ' . implode('
								INNER JOIN ', $subject_query['inner_join'])) . (empty($subject_query['left_join']) ? '' : '
								LEFT JOIN ' . implode('
								LEFT JOIN ', $subject_query['left_join'])) . '
							WHERE ' . implode('
								AND ', $subject_query['where']) . (empty($modSettings['search_max_results']) ? '' : '
							LIMIT ' . ($modSettings['search_max_results'] - $numSubjectResults)), $subject_query['params']);
                        // Don't do INSERT IGNORE? Manually fix this up!
                        $numSubjectResults += smf_db_affected_rows();
                        if (!empty($modSettings['search_max_results']) && $numSubjectResults >= $modSettings['search_max_results']) {
                            break;
                        }
                    }
                    // Got some non-MySQL data to plonk in?
                    if (!empty($inserts)) {
                        smf_db_insert('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics', $createTemporary ? array('id_topic' => 'int') : array('id_search' => 'int', 'id_topic' => 'int'), $inserts, $createTemporary ? array('id_topic') : array('id_search', 'id_topic'));
                    }
                    if ($numSubjectResults !== 0) {
                        $main_query['weights']['subject'] = 'CASE WHEN MAX(lst.id_topic) IS NULL THEN 0 ELSE 1 END';
                        $main_query['left_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (' . ($createTemporary ? '' : 'lst.id_search = {int:id_search} AND ') . 'lst.id_topic = t.id_topic)';
                        if (!$createTemporary) {
                            $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search'];
                        }
                    }
                }
                $indexedResults = 0;
                // We building an index?
                if ($searchAPI->supportsMethod('indexedWordQuery', $query_params)) {
                    $inserts = array();
                    smf_db_query('
						DROP TABLE IF EXISTS {db_prefix}tmp_log_search_messages', array('db_error_skip' => true));
                    $createTemporary = smf_db_query('
						CREATE TEMPORARY TABLE {db_prefix}tmp_log_search_messages (
							id_msg int(10) unsigned NOT NULL default {string:string_zero},
							PRIMARY KEY (id_msg)
						) TYPE=HEAP', array('string_zero' => '0', 'db_error_skip' => true)) !== false;
                    // Clear, all clear!
                    if (!$createTemporary) {
                        smf_db_query('
							DELETE FROM {db_prefix}log_search_messages
							WHERE id_search = {int:id_search}', array('id_search' => $_SESSION['search_cache']['id_search']));
                    }
                    foreach ($searchWords as $orIndex => $words) {
                        // Search for this word, assuming we have some words!
                        if (!empty($words['indexed_words'])) {
                            // Variables required for the search.
                            $search_data = array('insert_into' => ($createTemporary ? 'tmp_' : '') . 'log_search_messages', 'no_regexp' => $no_regexp, 'max_results' => $maxMessageResults, 'indexed_results' => $indexedResults, 'params' => array('id_search' => !$createTemporary ? $_SESSION['search_cache']['id_search'] : 0, 'excluded_words' => $excludedWords, 'user_query' => !empty($userQuery) ? $userQuery : '', 'board_query' => !empty($boardQuery) ? $boardQuery : '', 'topic' => !empty($search_params['topic']) ? $search_params['topic'] : 0, 'min_msg_id' => !empty($minMsgID) ? $minMsgID : 0, 'max_msg_id' => !empty($maxMsgID) ? $maxMsgID : 0, 'excluded_phrases' => !empty($excludedPhrases) ? $excludedPhrases : array(), 'excluded_index_words' => !empty($excludedIndexWords) ? $excludedIndexWords : array(), 'excluded_subject_words' => !empty($excludedSubjectWords) ? $excludedSubjectWords : array()));
                            $ignoreRequest = $searchAPI->indexedWordQuery($words, $search_data);
                            $indexedResults += smf_db_affected_rows();
                            if (!empty($maxMessageResults) && $indexedResults >= $maxMessageResults) {
                                break;
                            }
                        }
                    }
                    // More non-MySQL stuff needed?
                    if (!empty($inserts)) {
                        smf_db_insert('', '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages', $createTemporary ? array('id_msg' => 'int') : array('id_msg' => 'int', 'id_search' => 'int'), $inserts, $createTemporary ? array('id_msg') : array('id_msg', 'id_search'));
                    }
                    if (empty($indexedResults) && empty($numSubjectResults) && !empty($modSettings['search_force_index'])) {
                        $context['search_errors']['query_not_specific_enough'] = true;
                        $_REQUEST['params'] = $context['params'];
                        EoS_Smarty::resetTemplates();
                        return PlushSearch1();
                    } elseif (!empty($indexedResults)) {
                        $main_query['inner_join'][] = '{db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_messages AS lsm ON (lsm.id_msg = m.id_msg)';
                        if (!$createTemporary) {
                            $main_query['where'][] = 'lsm.id_search = {int:id_search}';
                            $main_query['parameters']['id_search'] = $_SESSION['search_cache']['id_search'];
                        }
                    }
                } else {
                    $orWhere = array();
                    $count = 0;
                    foreach ($searchWords as $orIndex => $words) {
                        $where = array();
                        foreach ($words['all_words'] as $regularWord) {
                            $where[] = 'm.body' . (in_array($regularWord, $excludedWords) ? ' NOT' : '') . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}';
                            if (in_array($regularWord, $excludedWords)) {
                                $where[] = 'm.subject NOT' . (empty($modSettings['search_match_words']) || $no_regexp ? ' LIKE ' : ' RLIKE ') . '{string:all_word_body_' . $count . '}';
                            }
                            $main_query['parameters']['all_word_body_' . $count++] = empty($modSettings['search_match_words']) || $no_regexp ? '%' . strtr($regularWord, array('_' => '\\_', '%' => '\\%')) . '%' : '[[:<:]]' . addcslashes(preg_replace(array('/([\\[\\]$.+*?|{}()])/'), array('[$1]'), $regularWord), '\\\'') . '[[:>:]]';
                        }
                        if (!empty($where)) {
                            $orWhere[] = count($where) > 1 ? '(' . implode(' AND ', $where) . ')' : $where[0];
                        }
                    }
                    if (!empty($orWhere)) {
                        $main_query['where'][] = count($orWhere) > 1 ? '(' . implode(' OR ', $orWhere) . ')' : $orWhere[0];
                    }
                    if (!empty($userQuery)) {
                        $main_query['where'][] = '{raw:user_query}';
                        $main_query['parameters']['user_query'] = $userQuery;
                    }
                    if (!empty($search_params['topic'])) {
                        $main_query['where'][] = 'm.id_topic = {int:topic}';
                        $main_query['parameters']['topic'] = $search_params['topic'];
                    }
                    if (!empty($minMsgID)) {
                        $main_query['where'][] = 'm.id_msg >= {int:min_msg_id}';
                        $main_query['parameters']['min_msg_id'] = $minMsgID;
                    }
                    if (!empty($maxMsgID)) {
                        $main_query['where'][] = 'm.id_msg <= {int:max_msg_id}';
                        $main_query['parameters']['max_msg_id'] = $maxMsgID;
                    }
                    if (!empty($boardQuery)) {
                        $main_query['where'][] = 'm.id_board {raw:board_query}';
                        $main_query['parameters']['board_query'] = $boardQuery;
                    }
                }
                // Did we either get some indexed results, or otherwise did not do an indexed query?
                if (!empty($indexedResults) || !$searchAPI->supportsMethod('indexedWordQuery', $query_params)) {
                    $relevance = '1000 * (';
                    $new_weight_total = 0;
                    foreach ($main_query['weights'] as $type => $value) {
                        $relevance .= $weight[$type] . ' * ' . $value . ' + ';
                        $new_weight_total += $weight[$type];
                    }
                    $main_query['select']['relevance'] = substr($relevance, 0, -3) . ') / ' . $new_weight_total . ' AS relevance';
                    $ignoreRequest = smf_db_query((1 ? '
						INSERT IGNORE INTO ' . '{db_prefix}log_search_results
							(' . implode(', ', array_keys($main_query['select'])) . ')' : '') . '
						SELECT
							' . implode(',
							', $main_query['select']) . '
						FROM ' . $main_query['from'] . (empty($main_query['inner_join']) ? '' : '
							INNER JOIN ' . implode('
							INNER JOIN ', $main_query['inner_join'])) . (empty($main_query['left_join']) ? '' : '
							LEFT JOIN ' . implode('
							LEFT JOIN ', $main_query['left_join'])) . (!empty($main_query['where']) ? '
						WHERE ' : '') . implode('
							AND ', $main_query['where']) . (empty($main_query['group_by']) ? '' : '
						GROUP BY ' . implode(', ', $main_query['group_by'])) . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . $modSettings['search_max_results']), $main_query['parameters']);
                    $_SESSION['search_cache']['num_results'] = smf_db_affected_rows();
                }
                // Insert subject-only matches.
                if ($_SESSION['search_cache']['num_results'] < $modSettings['search_max_results'] && $numSubjectResults !== 0) {
                    $usedIDs = array_flip(empty($inserts) ? array() : array_keys($inserts));
                    $ignoreRequest = smf_db_query((1 ? '
						INSERT IGNORE INTO {db_prefix}log_search_results
							(id_search, id_topic, relevance, id_msg, num_matches)' : '') . '
						SELECT
							{int:id_search},
							t.id_topic,
							1000 * (
								{int:weight_frequency} / (t.num_replies + 1) +
								{int:weight_age} * CASE WHEN t.id_first_msg < {int:min_msg} THEN 0 ELSE (t.id_first_msg - {int:min_msg}) / {int:recent_message} END +
								{int:weight_length} * CASE WHEN t.num_replies < {int:huge_topic_posts} THEN t.num_replies / {int:huge_topic_posts} ELSE 1 END +
								{int:weight_subject} +
								{int:weight_sticky} * t.is_sticky
							) / {int:weight_total} AS relevance,
							t.id_first_msg,
							1
						FROM {db_prefix}topics AS t
							INNER JOIN {db_prefix}' . ($createTemporary ? 'tmp_' : '') . 'log_search_topics AS lst ON (lst.id_topic = t.id_topic)' . ($createTemporary ? '' : 'WHERE lst.id_search = {int:id_search}') . (empty($modSettings['search_max_results']) ? '' : '
						LIMIT ' . ($modSettings['search_max_results'] - $_SESSION['search_cache']['num_results'])), array('id_search' => $_SESSION['search_cache']['id_search'], 'weight_age' => $weight['age'], 'weight_frequency' => $weight['frequency'], 'weight_length' => $weight['frequency'], 'weight_sticky' => $weight['frequency'], 'weight_subject' => $weight['frequency'], 'weight_total' => $weight_total, 'min_msg' => $minMsg, 'recent_message' => $recentMsg, 'huge_topic_posts' => $humungousTopicPosts));
                    // Once again need to do the inserts if the database don't support ignore!
                    $_SESSION['search_cache']['num_results'] += smf_db_affected_rows();
                } else {
                    $_SESSION['search_cache']['num_results'] = 0;
                }
            }
        }
        // *** Retrieve the results to be shown on the page
        $participants = array();
        $request = smf_db_query('
			SELECT ' . (empty($search_params['topic']) ? 'lsr.id_topic' : $search_params['topic'] . ' AS id_topic') . ', lsr.id_msg, lsr.relevance, lsr.num_matches
			FROM {db_prefix}log_search_results AS lsr' . ($search_params['sort'] == 'num_replies' ? '
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = lsr.id_topic)' : '') . '
			WHERE lsr.id_search = {int:id_search}
			ORDER BY ' . $search_params['sort'] . ' ' . $search_params['sort_dir'] . '
			LIMIT ' . (int) $_REQUEST['start'] . ', ' . $modSettings['search_results_per_page'], array('id_search' => $_SESSION['search_cache']['id_search']));
        while ($row = mysql_fetch_assoc($request)) {
            $context['topics'][$row['id_msg']] = array('relevance' => round($row['relevance'] / 10, 1) . '%', 'num_matches' => $row['num_matches'], 'matches' => array());
            // By default they didn't participate in the topic!
            $participants[$row['id_topic']] = false;
        }
        mysql_free_result($request);
        $num_results = $_SESSION['search_cache']['num_results'];
    }
    if (!empty($context['topics'])) {
        // Create an array for the permissions.
        $boards_can = array('post_reply_own' => boardsAllowedTo('post_reply_own'), 'post_reply_any' => boardsAllowedTo('post_reply_any'), 'mark_any_notify' => boardsAllowedTo('mark_any_notify'));
        // How's about some quick moderation?
        if (!empty($options['display_quick_mod'])) {
            $boards_can['lock_any'] = boardsAllowedTo('lock_any');
            $boards_can['lock_own'] = boardsAllowedTo('lock_own');
            $boards_can['make_sticky'] = boardsAllowedTo('make_sticky');
            $boards_can['move_any'] = boardsAllowedTo('move_any');
            $boards_can['move_own'] = boardsAllowedTo('move_own');
            $boards_can['remove_any'] = boardsAllowedTo('remove_any');
            $boards_can['remove_own'] = boardsAllowedTo('remove_own');
            $boards_can['merge_any'] = boardsAllowedTo('merge_any');
            $context['can_lock'] = in_array(0, $boards_can['lock_any']);
            $context['can_sticky'] = in_array(0, $boards_can['make_sticky']) && !empty($modSettings['enableStickyTopics']);
            $context['can_move'] = in_array(0, $boards_can['move_any']);
            $context['can_remove'] = in_array(0, $boards_can['remove_any']);
            $context['can_merge'] = in_array(0, $boards_can['merge_any']);
        }
        // What messages are we using?
        $msg_list = array_keys($context['topics']);
        // Load the posters...
        $request = smf_db_query('
			SELECT id_member
			FROM {db_prefix}messages
			WHERE id_member != {int:no_member}
				AND id_msg IN ({array_int:message_list})
			LIMIT ' . count($context['topics']), array('message_list' => $msg_list, 'no_member' => 0));
        $posters = array();
        while ($row = mysql_fetch_assoc($request)) {
            $posters[] = $row['id_member'];
        }
        mysql_free_result($request);
        if (!empty($posters)) {
            loadMemberData(array_unique($posters));
        }
        // Get the messages out for the callback - select enough that it can be made to look just like Display.
        $messages_request = smf_db_query('
			SELECT
				m.id_msg, m.subject, m.poster_name, m.poster_email, m.poster_time, m.id_member,
				m.icon, m.poster_ip, m.body, m.smileys_enabled, m.modified_time, m.modified_name,
				first_m.id_msg AS first_msg, first_m.subject AS first_subject, first_m.icon AS first_icon, first_m.poster_time AS first_poster_time,
				first_mem.id_member AS first_member_id, IFNULL(first_mem.real_name, first_m.poster_name) AS first_member_name,
				last_m.id_msg AS last_msg, last_m.poster_time AS last_poster_time, last_mem.id_member AS last_member_id,
				IFNULL(last_mem.real_name, last_m.poster_name) AS last_member_name, last_m.icon AS last_icon, last_m.subject AS last_subject,
				t.id_topic, t.is_sticky, t.locked, t.id_poll, t.num_replies, t.num_views,
				b.id_board, b.name AS board_name, c.id_cat, c.name AS cat_name
			FROM {db_prefix}messages AS m
				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic)
				INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board)
				INNER JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat)
				INNER JOIN {db_prefix}messages AS first_m ON (first_m.id_msg = t.id_first_msg)
				INNER JOIN {db_prefix}messages AS last_m ON (last_m.id_msg = t.id_last_msg)
				LEFT JOIN {db_prefix}members AS first_mem ON (first_mem.id_member = first_m.id_member)
				LEFT JOIN {db_prefix}members AS last_mem ON (last_mem.id_member = first_m.id_member)
			WHERE m.id_msg IN ({array_int:message_list})' . ($modSettings['postmod_active'] ? '
				AND m.approved = {int:is_approved}' : '') . '
			ORDER BY FIND_IN_SET(m.id_msg, {string:message_list_in_set})
			LIMIT {int:limit}', array('message_list' => $msg_list, 'is_approved' => 1, 'message_list_in_set' => implode(',', $msg_list), 'limit' => count($context['topics'])));
        // If there are no results that means the things in the cache got deleted, so pretend we have no topics anymore.
        if (mysql_num_rows($messages_request) == 0) {
            $context['topics'] = array();
        }
        // If we want to know who participated in what then load this now.
        if (!empty($modSettings['enableParticipation']) && !$user_info['is_guest']) {
            $result = smf_db_query('
				SELECT id_topic
				FROM {db_prefix}messages
				WHERE id_topic IN ({array_int:topic_list})
					AND id_member = {int:current_member}
				GROUP BY id_topic
				LIMIT ' . count($participants), array('current_member' => $user_info['id'], 'topic_list' => array_keys($participants)));
            while ($row = mysql_fetch_assoc($result)) {
                $participants[$row['id_topic']] = true;
            }
            mysql_free_result($result);
        }
    }
    // Now that we know how many results to expect we can start calculating the page numbers.
    $context['page_index'] = constructPageIndex($scripturl . '?action=search2;params=' . $context['params'], $_REQUEST['start'], $num_results, $modSettings['search_results_per_page'], false);
    // Consider the search complete!
    if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
        CacheAPI::putCache('search_start:' . ($user_info['is_guest'] ? $user_info['ip'] : $user_info['id']), null, 90);
    }
    $context['key_words'] =& $searchArray;
    if (empty($context['compact'])) {
        $context['need_synhlt'] = 1;
    }
    $context['sub_template'] = 'results';
    $context['page_title'] = $txt['search_results'];
    $context['get_topics'] = 'prepareSearchContext';
    $context['can_send_pm'] = allowedTo('pm_send');
    $context['jump_to'] = array('label' => addslashes(un_htmlspecialchars($txt['jump_to'])), 'board_name' => addslashes(un_htmlspecialchars($txt['select_destination'])));
}
Ejemplo n.º 27
0
function deleteMembers($users, $check_not_admin = false)
{
    global $sourcedir, $modSettings, $user_info, $backend_subdir;
    // Try give us a while to sort this out...
    @set_time_limit(600);
    // Try to get some more memory.
    if (@ini_get('memory_limit') < 128) {
        @ini_set('memory_limit', '128M');
    }
    // If it's not an array, make it so!
    if (!is_array($users)) {
        $users = array($users);
    } else {
        $users = array_unique($users);
    }
    // Make sure there's no void user in here.
    $users = array_diff($users, array(0));
    // How many are they deleting?
    if (empty($users)) {
        return;
    } elseif (count($users) == 1) {
        list($user) = $users;
        if ($user == $user_info['id']) {
            isAllowedTo('profile_remove_own');
        } else {
            isAllowedTo('profile_remove_any');
        }
    } else {
        foreach ($users as $k => $v) {
            $users[$k] = (int) $v;
        }
        // Deleting more than one?  You can't have more than one account...
        isAllowedTo('profile_remove_any');
    }
    // Get their names for logging purposes.
    $request = smf_db_query('
		SELECT id_member, member_name, CASE WHEN id_group = {int:admin_group} OR FIND_IN_SET({int:admin_group}, additional_groups) != 0 THEN 1 ELSE 0 END AS is_admin
		FROM {db_prefix}members
		WHERE id_member IN ({array_int:user_list})
		LIMIT ' . count($users), array('user_list' => $users, 'admin_group' => 1));
    $admins = array();
    $user_log_details = array();
    while ($row = mysql_fetch_assoc($request)) {
        if ($row['is_admin']) {
            $admins[] = $row['id_member'];
        }
        $user_log_details[$row['id_member']] = array($row['id_member'], $row['member_name']);
    }
    mysql_free_result($request);
    if (empty($user_log_details)) {
        return;
    }
    // Make sure they aren't trying to delete administrators if they aren't one.  But don't bother checking if it's just themself.
    if (!empty($admins) && ($check_not_admin || !allowedTo('admin_forum') && (count($users) != 1 || $users[0] != $user_info['id']))) {
        $users = array_diff($users, $admins);
        foreach ($admins as $id) {
            unset($user_log_details[$id]);
        }
    }
    // No one left?
    if (empty($users)) {
        return;
    }
    // Log the action - regardless of who is deleting it.
    $log_inserts = array();
    foreach ($user_log_details as $user) {
        // Integration rocks!
        HookAPI::callHook('integrate_delete_member', array($user[0]));
        // Add it to the administration log for future reference.
        $log_inserts[] = array(time(), 3, $user_info['id'], $user_info['ip'], 'delete_member', 0, 0, 0, serialize(array('member' => $user[0], 'name' => $user[1], 'member_acted' => $user_info['name'])));
        // Remove any cached data if enabled.
        if (!empty($modSettings['cache_enable']) && $modSettings['cache_enable'] >= 2) {
            CacheAPI::putCache('user_settings-' . $user[0], null, 60);
        }
    }
    // Do the actual logging...
    if (!empty($log_inserts) && !empty($modSettings['modlog_enabled'])) {
        smf_db_insert('', '{db_prefix}log_actions', array('log_time' => 'int', 'id_log' => 'int', 'id_member' => 'int', 'ip' => 'string-16', 'action' => 'string', 'id_board' => 'int', 'id_topic' => 'int', 'id_msg' => 'int', 'extra' => 'string-65534'), $log_inserts, array('id_action'));
    }
    // Make these peoples' posts guest posts.
    smf_db_query('
		UPDATE {db_prefix}messages
		SET id_member = {int:guest_id}, poster_email = {string:blank_email}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'blank_email' => '', 'users' => $users));
    smf_db_query('
		UPDATE {db_prefix}polls
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // Make these peoples' posts guest first posts and last posts.
    smf_db_query('
		UPDATE {db_prefix}topics
		SET id_member_started = {int:guest_id}
		WHERE id_member_started IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    smf_db_query('
		UPDATE {db_prefix}topics
		SET id_member_updated = {int:guest_id}
		WHERE id_member_updated IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    smf_db_query('
		UPDATE {db_prefix}log_actions
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    smf_db_query('
		UPDATE {db_prefix}log_banned
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    smf_db_query('
		UPDATE {db_prefix}log_errors
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // Delete the member.
    smf_db_query('
		DELETE FROM {db_prefix}members
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Delete the logs...
    smf_db_query('
		DELETE FROM {db_prefix}log_actions
		WHERE id_log = {int:log_type}
			AND id_member IN ({array_int:users})', array('log_type' => 2, 'users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_boards
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_comments
		WHERE id_recipient IN ({array_int:users})
			AND comment_type = {string:warntpl}', array('users' => $users, 'warntpl' => 'warntpl'));
    smf_db_query('
		DELETE FROM {db_prefix}log_group_requests
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_karma
		WHERE id_target IN ({array_int:users})
			OR id_executor IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_mark_read
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_notify
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_online
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_subscribed
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}log_topics
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}collapsed_categories
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // delete activities and corresponding notifications
    smf_db_query('
		DELETE a.*, n.* FROM {db_prefix}log_activities AS a LEFT JOIN {db_prefix}log_notifications AS n ON (n.id_act = a.id_act)
		WHERE a.id_member IN ({array_int:users})', array('users' => $users));
    // Make their votes appear as guest votes - at least it keeps the totals right.
    //!!! Consider adding back in cookie protection.
    smf_db_query('
		UPDATE {db_prefix}log_polls
		SET id_member = {int:guest_id}
		WHERE id_member IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // Delete personal messages.
    require_once $sourcedir . '/PersonalMessage.php';
    deleteMessages(null, null, $users);
    smf_db_query('
		UPDATE {db_prefix}personal_messages
		SET id_member_from = {int:guest_id}
		WHERE id_member_from IN ({array_int:users})', array('guest_id' => 0, 'users' => $users));
    // They no longer exist, so we don't know who it was sent to.
    smf_db_query('
		DELETE FROM {db_prefix}pm_recipients
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}drafts WHERE id_member IN ({array_int:members})', array('members' => $users));
    // Delete avatar.
    require_once $sourcedir . '/lib/Subs-ManageAttachments.php';
    removeAttachments(array('id_member' => $users));
    // It's over, no more moderation for you.
    smf_db_query('
		DELETE FROM {db_prefix}moderators
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    smf_db_query('
		DELETE FROM {db_prefix}group_moderators
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // If you don't exist we can't ban you.
    smf_db_query('
		DELETE FROM {db_prefix}ban_items
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // Remove individual theme settings.
    smf_db_query('
		DELETE FROM {db_prefix}themes
		WHERE id_member IN ({array_int:users})', array('users' => $users));
    // These users are nobody's buddy nomore.
    $request = smf_db_query('
		SELECT id_member, pm_ignore_list, buddy_list
		FROM {db_prefix}members
		WHERE FIND_IN_SET({raw:pm_ignore_list}, pm_ignore_list) != 0 OR FIND_IN_SET({raw:buddy_list}, buddy_list) != 0', array('pm_ignore_list' => implode(', pm_ignore_list) != 0 OR FIND_IN_SET(', $users), 'buddy_list' => implode(', buddy_list) != 0 OR FIND_IN_SET(', $users)));
    while ($row = mysql_fetch_assoc($request)) {
        smf_db_query('
			UPDATE {db_prefix}members
			SET
				pm_ignore_list = {string:pm_ignore_list},
				buddy_list = {string:buddy_list}
			WHERE id_member = {int:id_member}', array('id_member' => $row['id_member'], 'pm_ignore_list' => implode(',', array_diff(explode(',', $row['pm_ignore_list']), $users)), 'buddy_list' => implode(',', array_diff(explode(',', $row['buddy_list']), $users))));
    }
    mysql_free_result($request);
    // Make sure no member's birthday is still sticking in the calendar...
    updateSettings(array('calendar_updated' => time()));
    updateStats('member');
}
Ejemplo n.º 28
0
function SetJavaScript()
{
    global $settings, $user_info, $smcFunc, $options;
    // Check the session id.
    checkSession('get');
    // This good-for-nothing pixel is being used to keep the session alive.
    if (empty($_GET['var']) || !isset($_GET['val'])) {
        redirectexit($settings['images_url'] . '/blank.gif');
    }
    // Sorry, guests can't go any further than this..
    if ($user_info['is_guest'] || $user_info['id'] == 0) {
        obExit(false);
    }
    $reservedVars = array('actual_theme_url', 'actual_images_url', 'base_theme_dir', 'base_theme_url', 'default_images_url', 'default_theme_dir', 'default_theme_url', 'default_template', 'images_url', 'number_recent_posts', 'smiley_sets_default', 'theme_dir', 'theme_id', 'theme_layers', 'theme_templates', 'theme_url', 'name');
    // Can't change reserved vars.
    if (in_array(strtolower($_GET['var']), $reservedVars)) {
        redirectexit($settings['images_url'] . '/blank.gif');
    }
    // Use a specific theme?
    if (isset($_GET['th']) || isset($_GET['id'])) {
        // Invalidate the current themes cache too.
        CacheAPI::putCache('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 60);
        $settings['theme_id'] = isset($_GET['th']) ? (int) $_GET['th'] : (int) $_GET['id'];
    }
    // If this is the admin preferences the passed value will just be an element of it.
    if ($_GET['var'] == 'admin_preferences') {
        $options['admin_preferences'] = !empty($options['admin_preferences']) ? unserialize($options['admin_preferences']) : array();
        // New thingy...
        if (isset($_GET['admin_key']) && strlen($_GET['admin_key']) < 5) {
            $options['admin_preferences'][$_GET['admin_key']] = $_GET['val'];
        }
        // Change the value to be something nice,
        $_GET['val'] = serialize($options['admin_preferences']);
    }
    // Update the option.
    smf_db_insert('replace', '{db_prefix}themes', array('id_theme' => 'int', 'id_member' => 'int', 'variable' => 'string-255', 'value' => 'string-65534'), array($settings['theme_id'], $user_info['id'], $_GET['var'], is_array($_GET['val']) ? implode(',', $_GET['val']) : $_GET['val']), array('id_theme', 'id_member', 'variable'));
    CacheAPI::putCache('theme_settings-' . $settings['theme_id'] . ':' . $user_info['id'], null, 60);
    // Don't output anything...
    redirectexit($settings['images_url'] . '/blank.gif');
}
Ejemplo n.º 29
0
function create_control_verification(&$verificationOptions, $do_test = false)
{
    global $txt, $modSettings, $options, $smcFunc;
    global $context, $settings, $user_info, $sourcedir, $scripturl;
    // First verification means we need to set up some bits...
    if (empty($context['controls']['verification'])) {
        // The template
        //if(!isset($verificationOptions['skip_template']))
        //	loadTemplate('GenericControls');
        // Some javascript ma'am?
        if (!empty($verificationOptions['override_visual']) || !empty($modSettings['visual_verification_type']) && !isset($verificationOptions['override_visual'])) {
            $context['html_headers'] .= '
		<script type="text/javascript" src="' . $settings['default_theme_url'] . '/scripts/captcha.js"></script>';
        }
        $context['use_graphic_library'] = in_array('gd', get_loaded_extensions());
        // Skip I, J, L, O, Q, S and Z.
        $context['standard_captcha_range'] = array_merge(range('A', 'H'), array('K', 'M', 'N', 'P', 'R'), range('T', 'Y'));
    }
    // Always have an ID.
    assert(isset($verificationOptions['id']));
    $isNew = !isset($context['controls']['verification'][$verificationOptions['id']]);
    // Log this into our collection.
    if ($isNew) {
        $context['controls']['verification'][$verificationOptions['id']] = array('id' => $verificationOptions['id'], 'show_visual' => !empty($verificationOptions['override_visual']) || !empty($modSettings['visual_verification_type']) && !isset($verificationOptions['override_visual']), 'number_questions' => isset($verificationOptions['override_qs']) ? $verificationOptions['override_qs'] : (!empty($modSettings['qa_verification_number']) ? $modSettings['qa_verification_number'] : 0), 'max_errors' => isset($verificationOptions['max_errors']) ? $verificationOptions['max_errors'] : 3, 'image_href' => $scripturl . '?action=verificationcode;vid=' . $verificationOptions['id'] . ';rand=' . md5(mt_rand()), 'text_value' => '', 'questions' => array());
    }
    $thisVerification =& $context['controls']['verification'][$verificationOptions['id']];
    // Add javascript for the object.
    if ($context['controls']['verification'][$verificationOptions['id']]['show_visual']) {
        $context['inline_footer_script'] .= '
			var verification' . $verificationOptions['id'] . 'Handle = new smfCaptcha("' . $thisVerification['image_href'] . '", "' . $verificationOptions['id'] . '", ' . ($context['use_graphic_library'] ? 1 : 0) . ');';
    }
    // Is there actually going to be anything?
    if (empty($thisVerification['show_visual']) && empty($thisVerification['number_questions'])) {
        return false;
    } elseif (!$isNew && !$do_test) {
        return true;
    }
    // If we want questions do we have a cache of all the IDs?
    if (!empty($thisVerification['number_questions']) && empty($modSettings['question_id_cache'])) {
        if (($modSettings['question_id_cache'] = CacheAPI::getCache('verificationQuestionIds', 300)) == null) {
            $request = smf_db_query('
				SELECT id_comment
				FROM {db_prefix}log_comments
				WHERE comment_type = {string:ver_test}', array('ver_test' => 'ver_test'));
            $modSettings['question_id_cache'] = array();
            while ($row = mysql_fetch_assoc($request)) {
                $modSettings['question_id_cache'][] = $row['id_comment'];
            }
            mysql_free_result($request);
            if (!empty($modSettings['cache_enable'])) {
                CacheAPI::putCache('verificationQuestionIds', $modSettings['question_id_cache'], 300);
            }
        }
    }
    if (!isset($_SESSION[$verificationOptions['id'] . '_vv'])) {
        $_SESSION[$verificationOptions['id'] . '_vv'] = array();
    }
    // Do we need to refresh the verification?
    if (!$do_test && (!empty($_SESSION[$verificationOptions['id'] . '_vv']['did_pass']) || empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) || $_SESSION[$verificationOptions['id'] . '_vv']['count'] > 3) && empty($verificationOptions['dont_refresh'])) {
        $force_refresh = true;
    } else {
        $force_refresh = false;
    }
    // This can also force a fresh, although unlikely.
    if ($thisVerification['show_visual'] && empty($_SESSION[$verificationOptions['id'] . '_vv']['code']) || $thisVerification['number_questions'] && empty($_SESSION[$verificationOptions['id'] . '_vv']['q'])) {
        $force_refresh = true;
    }
    $verification_errors = array();
    // Start with any testing.
    if ($do_test) {
        // This cannot happen!
        if (!isset($_SESSION[$verificationOptions['id'] . '_vv']['count'])) {
            fatal_lang_error('no_access', false);
        }
        // ... nor this!
        if ($thisVerification['number_questions'] && (!isset($_SESSION[$verificationOptions['id'] . '_vv']['q']) || !isset($_REQUEST[$verificationOptions['id'] . '_vv']['q']))) {
            fatal_lang_error('no_access', false);
        }
        if ($thisVerification['show_visual'] && (empty($_REQUEST[$verificationOptions['id'] . '_vv']['code']) || empty($_SESSION[$verificationOptions['id'] . '_vv']['code']) || strtoupper($_REQUEST[$verificationOptions['id'] . '_vv']['code']) !== $_SESSION[$verificationOptions['id'] . '_vv']['code'])) {
            $verification_errors[] = 'wrong_verification_code';
        }
        if ($thisVerification['number_questions']) {
            // Get the answers and see if they are all right!
            $request = smf_db_query('
				SELECT id_comment, recipient_name AS answer
				FROM {db_prefix}log_comments
				WHERE comment_type = {string:ver_test}
					AND id_comment IN ({array_int:comment_ids})', array('ver_test' => 'ver_test', 'comment_ids' => $_SESSION[$verificationOptions['id'] . '_vv']['q']));
            $incorrectQuestions = array();
            while ($row = mysql_fetch_assoc($request)) {
                if (empty($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) || trim(commonAPI::htmlspecialchars(strtolower($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]))) != strtolower($row['answer'])) {
                    $incorrectQuestions[] = $row['id_comment'];
                }
            }
            mysql_free_result($request);
            if (!empty($incorrectQuestions)) {
                $verification_errors[] = 'wrong_verification_answer';
            }
        }
    }
    // Any errors means we refresh potentially.
    if (!empty($verification_errors)) {
        if (empty($_SESSION[$verificationOptions['id'] . '_vv']['errors'])) {
            $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0;
        } elseif ($_SESSION[$verificationOptions['id'] . '_vv']['errors'] > $thisVerification['max_errors']) {
            $force_refresh = true;
        }
        // Keep a track of these.
        $_SESSION[$verificationOptions['id'] . '_vv']['errors']++;
    }
    // Are we refreshing then?
    if ($force_refresh) {
        // Assume nothing went before.
        $_SESSION[$verificationOptions['id'] . '_vv']['count'] = 0;
        $_SESSION[$verificationOptions['id'] . '_vv']['errors'] = 0;
        $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = false;
        $_SESSION[$verificationOptions['id'] . '_vv']['q'] = array();
        $_SESSION[$verificationOptions['id'] . '_vv']['code'] = '';
        // Generating a new image.
        if ($thisVerification['show_visual']) {
            // Are we overriding the range?
            $character_range = !empty($verificationOptions['override_range']) ? $verificationOptions['override_range'] : $context['standard_captcha_range'];
            for ($i = 0; $i < 6; $i++) {
                $_SESSION[$verificationOptions['id'] . '_vv']['code'] .= $character_range[array_rand($character_range)];
            }
        }
        // Getting some new questions?
        if ($thisVerification['number_questions']) {
            // Pick some random IDs
            $questionIDs = array();
            if ($thisVerification['number_questions'] == 1) {
                $questionIDs[] = $modSettings['question_id_cache'][array_rand($modSettings['question_id_cache'], $thisVerification['number_questions'])];
            } else {
                foreach (array_rand($modSettings['question_id_cache'], $thisVerification['number_questions']) as $index) {
                    $questionIDs[] = $modSettings['question_id_cache'][$index];
                }
            }
        }
    } else {
        // Same questions as before.
        $questionIDs = !empty($_SESSION[$verificationOptions['id'] . '_vv']['q']) ? $_SESSION[$verificationOptions['id'] . '_vv']['q'] : array();
        $thisVerification['text_value'] = !empty($_REQUEST[$verificationOptions['id'] . '_vv']['code']) ? commonAPI::htmlspecialchars($_REQUEST[$verificationOptions['id'] . '_vv']['code']) : '';
    }
    // Have we got some questions to load?
    if (!empty($questionIDs)) {
        $request = smf_db_query('
			SELECT id_comment, body AS question
			FROM {db_prefix}log_comments
			WHERE comment_type = {string:ver_test}
				AND id_comment IN ({array_int:comment_ids})', array('ver_test' => 'ver_test', 'comment_ids' => $questionIDs));
        $_SESSION[$verificationOptions['id'] . '_vv']['q'] = array();
        while ($row = mysql_fetch_assoc($request)) {
            $thisVerification['questions'][] = array('id' => $row['id_comment'], 'q' => parse_bbc($row['question']), 'is_error' => !empty($incorrectQuestions) && in_array($row['id_comment'], $incorrectQuestions), 'a' => isset($_REQUEST[$verificationOptions['id'] . '_vv'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) ? commonAPI::htmlspecialchars($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) : '');
            $_SESSION[$verificationOptions['id'] . '_vv']['q'][] = $row['id_comment'];
        }
        mysql_free_result($request);
    }
    $_SESSION[$verificationOptions['id'] . '_vv']['count'] = empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) ? 1 : $_SESSION[$verificationOptions['id'] . '_vv']['count'] + 1;
    // Return errors if we have them.
    if (!empty($verification_errors)) {
        return $verification_errors;
    } elseif ($do_test) {
        $_SESSION[$verificationOptions['id'] . '_vv']['did_pass'] = true;
    }
    // Say that everything went well chaps.
    return true;
}
Ejemplo n.º 30
0
function ModifyProfile($post_errors = array())
{
    global $txt, $scripturl, $user_info, $context, $sourcedir, $user_profile, $cur_profile;
    global $modSettings, $memberContext, $profile_vars, $post_errors, $user_settings;
    $boards = boardsAllowedTo('moderate_board');
    $is_mod = !empty($boards) || $user_info['is_admin'] || allowedTo('moderate_forum');
    EoS_Smarty::setActive();
    // Don't reload this as we may have processed error strings.
    if (empty($post_errors)) {
        loadLanguage('Profile');
    }
    EoS_Smarty::getConfigInstance()->registerHookTemplate('sidemenu_top', 'profile/menu_top_content');
    //$context['sef_full_rewrite'] = true;
    require_once $sourcedir . '/lib/Subs-Menu.php';
    // Did we get the user by name...
    if (isset($_REQUEST['user'])) {
        $memberResult = loadMemberData($_REQUEST['user'], true, 'profile');
    } elseif (!empty($_REQUEST['u'])) {
        $memberResult = loadMemberData((int) $_REQUEST['u'], false, 'profile');
    } else {
        $memberResult = loadMemberData($user_info['id'], false, 'profile');
    }
    // Check if loadMemberData() has returned a valid result.
    if (!is_array($memberResult)) {
        fatal_lang_error('not_a_user', false);
    }
    // If all went well, we have a valid member ID!
    list($memID) = $memberResult;
    $context['id_member'] = $memID;
    $cur_profile = $user_profile[$memID];
    // Let's have some information about this member ready, too.
    loadMemberContext($memID);
    $context['member'] = $memberContext[$memID];
    // Is this the profile of the user himself or herself?
    $context['user']['is_owner'] = $memID == $user_info['id'];
    /* Define all the sections within the profile area!
    		We start by defining the permission required - then SMF takes this and turns it into the relevant context ;)
    		Possible fields:
    			For Section:
    				string $title:		Section title.
    				array $areas:		Array of areas within this section.
    
    			For Areas:
    				string $label:		Text string that will be used to show the area in the menu.
    				string $file:		Optional text string that may contain a file name that's needed for inclusion in order to display the area properly.
    				string $custom_url:	Optional href for area.
    				string $function:	Function to execute for this section.
    				bool $enabled:		Should area be shown?
    				string $sc:		Session check validation to do on save - note without this save will get unset - if set.
    				bool $hidden:		Does this not actually appear on the menu?
    				bool $password:		Whether to require the user's password in order to save the data in the area.
    				array $subsections:	Array of subsections, in order of appearance.
    				array $permission:	Array of permissions to determine who can access this area. Should contain arrays $own and $any.
    	*/
    $profile_areas = array('info' => array('title' => $txt['profileInfo'], 'areas' => array('summary' => array('label' => $txt['summary'], 'file' => 'Profile-View.php', 'function' => 'summary', 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'statistics' => array('label' => $txt['statPanel'], 'file' => 'Profile-View.php', 'function' => 'statPanel', 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'showposts' => array('label' => $txt['showPosts'], 'file' => 'Profile-View.php', 'function' => 'showPosts', 'subsections' => array('messages' => array($txt['showMessages'], array('profile_view_own', 'profile_view_any')), 'topics' => array($txt['showTopics'], array('profile_view_own', 'profile_view_any')), 'attach' => array($txt['showAttachments'], array('profile_view_own', 'profile_view_any')), 'likes' => array($txt['showLikes'], array('profile_view_own', 'profile_view_any')), 'likesout' => array($txt['showLikesGiven'], array('profile_view_own', 'profile_view_any'))), 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'activities' => array('label' => $txt['showActivitiesMenu'], 'file' => 'Activities.php', 'function' => 'showActivitiesProfile', 'subsections' => array('activities' => array($txt['showActivities'], array('profile_view_own', 'profile_view_any')), 'notifications' => array($txt['showNotifications'], array('profile_view_own', 'profile_view_any')), 'settings' => array($txt['astreamSettings'], array('profile_view_own', 'profile_view_any'))), 'permission' => array('own' => 'profile_view_own', 'any' => 'profile_view_any')), 'permissions' => array('label' => $txt['showPermissions'], 'file' => 'Profile-View.php', 'function' => 'showPermissions', 'permission' => array('own' => 'manage_permissions', 'any' => 'manage_permissions')), 'tracking' => array('label' => $txt['trackUser'], 'file' => 'Profile-View.php', 'function' => 'tracking', 'subsections' => array('activity' => array($txt['trackActivity'], 'moderate_forum'), 'ip' => array($txt['trackIP'], 'moderate_forum'), 'edits' => array($txt['trackEdits'], 'moderate_forum')), 'permission' => array('own' => 'moderate_forum', 'any' => 'moderate_forum')), 'viewwarning' => array('label' => $txt['profile_view_warnings'], 'enabled' => in_array('w', $context['admin_features']) && $modSettings['warning_settings'][0] == 1 && $cur_profile['warning'] && $context['user']['is_owner'] && !empty($modSettings['warning_show']), 'file' => 'Profile-View.php', 'function' => 'viewWarning', 'permission' => array('own' => 'profile_view_own', 'any' => 'issue_warning')), 'view_topicbans' => array('label' => $txt['profile_view_topicbans'], 'enabled' => $is_mod, 'file' => 'Profile.php', 'function' => 'viewTopicBans', 'permission' => array('own' => 'profile_view_any', 'any' => 'profile_view_any')))), 'edit_profile' => array('title' => $txt['profileEdit'], 'areas' => array('account' => array('label' => $txt['account'], 'file' => 'Profile-Modify.php', 'function' => 'account', 'enabled' => $context['user']['is_admin'] || $cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups'])), 'sc' => 'post', 'password' => true, 'permission' => array('own' => array('profile_identity_any', 'profile_identity_own', 'manage_membergroups'), 'any' => array('profile_identity_any', 'manage_membergroups'))), 'forumprofile' => array('label' => $txt['forumprofile'], 'file' => 'Profile-Modify.php', 'function' => 'forumProfile', 'sc' => 'post', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own', 'profile_title_own', 'profile_title_any'), 'any' => array('profile_extra_any', 'profile_title_any'))), 'theme' => array('label' => $txt['theme'], 'file' => 'Profile-Modify.php', 'function' => 'theme', 'sc' => 'post', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'authentication' => array('label' => $txt['authentication'], 'file' => 'Profile-Modify.php', 'function' => 'authentication', 'enabled' => !empty($modSettings['enableOpenID']) || !empty($cur_profile['openid_uri']), 'sc' => 'post', 'hidden' => empty($modSettings['enableOpenID']) && empty($cur_profile['openid_uri']), 'password' => true, 'permission' => array('own' => array('profile_identity_any', 'profile_identity_own'), 'any' => array('profile_identity_any'))), 'notification' => array('label' => $txt['notification'], 'file' => 'Profile-Modify.php', 'function' => 'notification', 'sc' => 'post', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'pmprefs' => array('label' => $txt['pmprefs'], 'file' => 'Profile-Modify.php', 'function' => 'pmprefs', 'enabled' => allowedTo(array('profile_extra_own', 'profile_extra_any')), 'sc' => 'post', 'permission' => array('own' => array('pm_read'), 'any' => array('profile_extra_any'))), 'ignoreboards' => array('label' => $txt['ignoreboards'], 'file' => 'Profile-Modify.php', 'function' => 'ignoreboards', 'enabled' => !empty($modSettings['allow_ignore_boards']), 'sc' => 'post', 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array('profile_extra_any'))), 'lists' => array('label' => $txt['editBuddyIgnoreLists'], 'file' => 'Profile-Modify.php', 'function' => 'editBuddyIgnoreLists', 'enabled' => !empty($modSettings['enable_buddylist']) && $context['user']['is_owner'], 'sc' => 'post', 'subsections' => array('buddies' => array($txt['editBuddies']), 'ignore' => array($txt['editIgnoreList'])), 'permission' => array('own' => array('profile_extra_any', 'profile_extra_own'), 'any' => array())), 'groupmembership' => array('label' => $txt['groupmembership'], 'file' => 'Profile-Modify.php', 'function' => 'groupMembership', 'enabled' => !empty($modSettings['show_group_membership']) && $context['user']['is_owner'], 'sc' => 'request', 'permission' => array('own' => array('profile_view_own'), 'any' => array('manage_membergroups'))), 'boardnews' => array('label' => $txt['menu_boardnews'], 'file' => 'Profile-Modify.php', 'function' => 'profileManageBoardNews', 'enabled' => $context['user']['is_owner'], 'sc' => 'post', 'permission' => array('own' => array('profile_view_own'), 'any' => array())))), 'profile_action' => array('title' => $txt['profileAction'], 'areas' => array('sendpm' => array('label' => $txt['profileSendIm'], 'custom_url' => $scripturl . '?action=pm;sa=send', 'permission' => array('own' => array(), 'any' => array('pm_send'))), 'issuewarning' => array('label' => $txt['profile_issue_warning'], 'enabled' => in_array('w', $context['admin_features']) && $modSettings['warning_settings'][0] == 1 && (!$context['user']['is_owner'] || $context['user']['is_admin']), 'file' => 'Profile-Actions.php', 'function' => 'issueWarning', 'permission' => array('own' => array('issue_warning'), 'any' => array('issue_warning'))), 'banuser' => array('label' => $txt['profileBanUser'], 'custom_url' => $scripturl . '?action=admin;area=ban;sa=add', 'enabled' => $cur_profile['id_group'] != 1 && !in_array(1, explode(',', $cur_profile['additional_groups'])), 'permission' => array('own' => array(), 'any' => array('manage_bans'))), 'subscriptions' => array('label' => $txt['subscriptions'], 'file' => 'Profile-Actions.php', 'function' => 'subscriptions', 'enabled' => !empty($modSettings['paid_enabled']), 'permission' => array('own' => array('profile_view_own'), 'any' => array('moderate_forum'))), 'deleteaccount' => array('label' => $txt['deleteAccount'], 'file' => 'Profile-Actions.php', 'function' => 'deleteAccount', 'sc' => 'post', 'password' => true, 'permission' => array('own' => array('profile_remove_any', 'profile_remove_own'), 'any' => array('profile_remove_any'))), 'activateaccount' => array('file' => 'Profile-Actions.php', 'function' => 'activateAccount', 'sc' => 'get', 'select' => 'summary', 'permission' => array('own' => array(), 'any' => array('moderate_forum'))))));
    //if(!$context['user']['is_owner'] || !in_array('dr', $context['admin_features'])) todo: drafts -> plugin
    unset($profile_areas['info']['areas']['drafts']);
    if (!in_array('as', $context['admin_features'])) {
        unset($profile_areas['info']['areas']['activities']);
    }
    if (!$user_info['is_admin'] && !$context['user']['is_owner'] && isset($profile_areas['info']['areas']['activities'])) {
        unset($profile_areas['info']['areas']['activities']['subsections']['notifications']);
        unset($profile_areas['info']['areas']['activities']['subsections']['settings']);
    }
    if (!$context['user']['is_owner'] && !allowedTo('can_view_ratings') || empty($modSettings['karmaMode'])) {
        unset($profile_areas['info']['areas']['showposts']['subsections']['likes']);
        unset($profile_areas['info']['areas']['showposts']['subsections']['likesout']);
    }
    // Let them modify profile areas easily.
    HookAPI::callHook('profile_areas', array(&$profile_areas));
    // Do some cleaning ready for the menu function.
    $context['password_areas'] = array();
    $current_area = isset($_REQUEST['area']) ? $_REQUEST['area'] : '';
    foreach ($profile_areas as $section_id => $section) {
        // Do a bit of spring cleaning so to speak.
        foreach ($section['areas'] as $area_id => $area) {
            // If it said no permissions that meant it wasn't valid!
            if (empty($area['permission'][$context['user']['is_owner'] ? 'own' : 'any'])) {
                $profile_areas[$section_id]['areas'][$area_id]['enabled'] = false;
            } else {
                $profile_areas[$section_id]['areas'][$area_id]['permission'] = $area['permission'][$context['user']['is_owner'] ? 'own' : 'any'];
            }
            // Password required - only if not on OpenID.
            if (!empty($area['password'])) {
                $context['password_areas'][] = $area_id;
            }
        }
    }
    // Is there an updated message to show?
    if (isset($_GET['updated'])) {
        $context['profile_updated'] = $txt['profile_updated_own'];
    }
    // Set a few options for the menu.
    $menuOptions = array('disable_url_session_check' => true, 'current_area' => $current_area, 'extra_url_parameters' => array('u' => $context['id_member']));
    // Actually create the menu!
    $profile_include_data = createMenu($profile_areas, $menuOptions);
    // No menu means no access.
    if (!$profile_include_data && (!$user_info['is_guest'] || validateSession())) {
        fatal_lang_error('no_access', false);
    }
    // Make a note of the Unique ID for this menu.
    $context['profile_menu_id'] = $context['max_menu_id'];
    $context['profile_menu_name'] = 'menu_data_' . $context['profile_menu_id'];
    // Set the selected item - now it's been validated.
    $current_area = $profile_include_data['current_area'];
    $context['menu_item_selected'] = $current_area;
    // Before we go any further, let's work on the area we've said is valid. Note this is done here just in case we every compromise the menu function in error!
    $context['completed_save'] = false;
    $security_checks = array();
    $found_area = false;
    foreach ($profile_areas as $section_id => $section) {
        // Do a bit of spring cleaning so to speak.
        foreach ($section['areas'] as $area_id => $area) {
            // Is this our area?
            if ($current_area == $area_id) {
                // This can't happen - but is a security check.
                if (isset($section['enabled']) && $section['enabled'] == false || isset($area['enabled']) && $area['enabled'] == false) {
                    fatal_lang_error('no_access', false);
                }
                // Are we saving data in a valid area?
                if (isset($area['sc']) && isset($_REQUEST['save'])) {
                    $security_checks['session'] = $area['sc'];
                    $context['completed_save'] = true;
                }
                // Does this require session validating?
                if (!empty($area['validate'])) {
                    $security_checks['validate'] = true;
                }
                // Permissions for good measure.
                if (!empty($profile_include_data['permission'])) {
                    $security_checks['permission'] = $profile_include_data['permission'];
                }
                // Either way got something.
                $found_area = true;
            }
        }
    }
    // Oh dear, some serious security lapse is going on here... we'll put a stop to that!
    if (!$found_area) {
        fatal_lang_error('no_access', false);
    }
    // Release this now.
    unset($profile_areas);
    // Now the context is setup have we got any security checks to carry out additional to that above?
    if (isset($security_checks['session'])) {
        checkSession($security_checks['session']);
    }
    if (isset($security_checks['validate'])) {
        validateSession();
    }
    if (isset($security_checks['permission'])) {
        isAllowedTo($security_checks['permission']);
    }
    // File to include?
    if (isset($profile_include_data['file'])) {
        require_once $sourcedir . '/' . $profile_include_data['file'];
    }
    // Make sure that the area function does exist!
    if (!isset($profile_include_data['function']) || !function_exists($profile_include_data['function'])) {
        destroyMenu();
        fatal_lang_error('no_access', false);
    }
    // Build the link tree.
    $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : ''), 'name' => sprintf($txt['profile_of_username'], $context['member']['name']));
    if (!empty($profile_include_data['label'])) {
        $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'], 'name' => $profile_include_data['label']);
    }
    if (!empty($profile_include_data['current_subsection']) && $profile_include_data['subsections'][$profile_include_data['current_subsection']][0] != $profile_include_data['label']) {
        $context['linktree'][] = array('url' => $scripturl . '?action=profile' . ($memID != $user_info['id'] ? ';u=' . $memID : '') . ';area=' . $profile_include_data['current_area'] . ';sa=' . $profile_include_data['current_subsection'], 'name' => $profile_include_data['subsections'][$profile_include_data['current_subsection']][0]);
    }
    // Set the template for this area and add the profile layer.
    $context['sub_template'] = $profile_include_data['function'];
    $context['template_layers'][] = 'profile';
    // All the subactions that require a user password in order to validate.
    $check_password = $context['user']['is_owner'] && in_array($profile_include_data['current_area'], $context['password_areas']);
    $context['require_password'] = $check_password && empty($user_settings['openid_uri']);
    // These will get populated soon!
    $post_errors = array();
    $profile_vars = array();
    // Right - are we saving - if so let's save the old data first.
    if ($context['completed_save']) {
        // If it's someone elses profile then validate the session.
        if (!$context['user']['is_owner']) {
            validateSession();
        }
        // Clean up the POST variables.
        $_POST = htmltrim__recursive($_POST);
        $_POST = htmlspecialchars__recursive($_POST);
        if ($check_password) {
            // If we're using OpenID try to revalidate.
            if (!empty($user_settings['openid_uri'])) {
                require_once $sourcedir . '/lib/Subs-OpenID.php';
                smf_openID_revalidate();
            } else {
                // You didn't even enter a password!
                if (trim($_POST['oldpasswrd']) == '') {
                    $post_errors[] = 'no_password';
                }
                // Since the password got modified due to all the $_POST cleaning, lets undo it so we can get the correct password
                $_POST['oldpasswrd'] = un_htmlspecialchars($_POST['oldpasswrd']);
                // Does the integration want to check passwords?
                $good_password = in_array(true, HookAPI::callHook('integrate_verify_password', array($cur_profile['member_name'], $_POST['oldpasswrd'], false)), true);
                // Bad password!!!
                if (!$good_password && $user_info['passwd'] != sha1(strtolower($cur_profile['member_name']) . $_POST['oldpasswrd'])) {
                    $post_errors[] = 'bad_password';
                }
                // Warn other elements not to jump the gun and do custom changes!
                if (in_array('bad_password', $post_errors)) {
                    $context['password_auth_failed'] = true;
                }
            }
        }
        // Change the IP address in the database.
        if ($context['user']['is_owner']) {
            $profile_vars['member_ip'] = $user_info['ip'];
        }
        // Now call the sub-action function...
        if ($current_area == 'activateaccount') {
            if (empty($post_errors)) {
                activateAccount($memID);
            }
        } elseif ($current_area == 'deleteaccount') {
            if (empty($post_errors)) {
                deleteAccount2($profile_vars, $post_errors, $memID);
                redirectexit();
            }
        } elseif ($current_area == 'groupmembership' && empty($post_errors)) {
            $msg = groupMembership2($profile_vars, $post_errors, $memID);
            // Whatever we've done, we have nothing else to do here...
            redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=groupmembership' . (!empty($msg) ? ';msg=' . $msg : ''));
        } elseif ($current_area == 'authentication') {
            authentication($memID, true);
        } elseif (in_array($current_area, array('account', 'forumprofile', 'theme', 'pmprefs'))) {
            saveProfileFields();
        } else {
            $force_redirect = true;
            // Ensure we include this.
            require_once $sourcedir . '/Profile-Modify.php';
            saveProfileChanges($profile_vars, $post_errors, $memID);
        }
        // There was a problem, let them try to re-enter.
        if (!empty($post_errors)) {
            // Load the language file so we can give a nice explanation of the errors.
            loadLanguage('Errors');
            $context['post_errors'] = $post_errors;
        } elseif (!empty($profile_vars)) {
            // If we've changed the password, notify any integration that may be listening in.
            if (isset($profile_vars['passwd'])) {
                HookAPI::callHook('integrate_reset_pass', array($cur_profile['member_name'], $cur_profile['member_name'], $_POST['passwrd2']));
            }
            updateMemberData($memID, $profile_vars);
            // What if this is the newest member?
            if ($modSettings['latestMember'] == $memID) {
                updateStats('member');
            } elseif (isset($profile_vars['real_name'])) {
                updateSettings(array('memberlist_updated' => time()));
            }
            // If the member changed his/her birthdate, update calendar statistics.
            if (isset($profile_vars['birthdate']) || isset($profile_vars['real_name'])) {
                updateSettings(array('calendar_updated' => time()));
            }
            // Anything worth logging?
            if (!empty($context['log_changes']) && !empty($modSettings['modlog_enabled'])) {
                $log_changes = array();
                foreach ($context['log_changes'] as $k => $v) {
                    $log_changes[] = array('action' => $k, 'id_log' => 2, 'log_time' => time(), 'id_member' => $memID, 'ip' => $user_info['ip'], 'extra' => serialize(array_merge($v, array('applicator' => $user_info['id']))));
                }
                smf_db_insert('', '{db_prefix}log_actions', array('action' => 'string', 'id_log' => 'int', 'log_time' => 'int', 'id_member' => 'int', 'ip' => 'string-16', 'extra' => 'string-65534'), $log_changes, array('id_action'));
            }
            // Have we got any post save functions to execute?
            if (!empty($context['profile_execute_on_save'])) {
                foreach ($context['profile_execute_on_save'] as $saveFunc) {
                    $saveFunc();
                }
            }
            // Let them know it worked!
            $context['profile_updated'] = $context['user']['is_owner'] ? $txt['profile_updated_own'] : sprintf($txt['profile_updated_else'], $cur_profile['member_name']);
            // Invalidate any cached data.
            CacheAPI::putCache('member_data-profile-' . $memID, null, 0);
        }
    }
    // Have some errors for some reason?
    if (!empty($post_errors)) {
        // Set all the errors so the template knows what went wrong.
        foreach ($post_errors as $error_type) {
            $context['modify_error'][$error_type] = true;
        }
    } elseif (!empty($profile_vars) && $context['user']['is_owner']) {
        redirectexit('action=profile;area=' . $current_area . ';updated');
    } elseif (!empty($force_redirect)) {
        redirectexit('action=profile' . ($context['user']['is_owner'] ? '' : ';u=' . $memID) . ';area=' . $current_area);
    }
    // Call the appropriate subaction function.
    $profile_include_data['function']($memID);
    // Set the page title if it's not already set...
    if (!isset($context['page_title'])) {
        $context['page_title'] = $txt['profile'] . (isset($txt[$current_area]) ? ' - ' . $txt[$current_area] : '');
    }
}