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']) . ' ' : ''; $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'] .= ' <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('&' => '&'))), '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); }
function UnapprovedAttachments() { global $txt, $scripturl, $context, $user_info, $sourcedir, $backend_subdir; $context['page_title'] = $txt['mc_unapproved_attachments']; // Once again, permissions are king! $approve_boards = boardsAllowedTo('approve_posts'); if ($approve_boards == array(0)) { $approve_query = ''; } elseif (!empty($approve_boards)) { $approve_query = ' AND m.id_board IN (' . implode(',', $approve_boards) . ')'; } else { $approve_query = ' AND 0'; } // Get together the array of things to act on, if any. $attachments = array(); if (isset($_GET['approve'])) { $attachments[] = (int) $_GET['approve']; } elseif (isset($_GET['delete'])) { $attachments[] = (int) $_GET['delete']; } elseif (isset($_POST['item'])) { foreach ($_POST['item'] as $item) { $attachments[] = (int) $item; } } // Are we approving or deleting? if (isset($_GET['approve']) || isset($_POST['do']) && $_POST['do'] == 'approve') { $curAction = 'approve'; } elseif (isset($_GET['delete']) || isset($_POST['do']) && $_POST['do'] == 'delete') { $curAction = 'delete'; } // Something to do, let's do it! if (!empty($attachments) && isset($curAction)) { checkSession('request'); // This will be handy. require_once $sourcedir . '/lib/Subs-ManageAttachments.php'; // Confirm the attachments are eligible for changing! $request = smf_db_query(' SELECT a.id_attach FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) LEFT JOIN {db_prefix}boards AS b ON (m.id_board = b.id_board) WHERE a.id_attach IN ({array_int:attachments}) AND a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query, array('attachments' => $attachments, 'not_approved' => 0, 'attachment_type' => 0)); $attachments = array(); while ($row = mysql_fetch_assoc($request)) { $attachments[] = $row['id_attach']; } mysql_free_result($request); // Assuming it wasn't all like, proper illegal, we can do the approving. if (!empty($attachments)) { if ($curAction == 'approve') { ApproveAttachments($attachments); } else { removeAttachments(array('id_attach' => $attachments)); } } } // How many unapproved attachments in total? $request = smf_db_query(' SELECT COUNT(*) FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) WHERE a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query, array('not_approved' => 0, 'attachment_type' => 0)); list($context['total_unapproved_attachments']) = mysql_fetch_row($request); mysql_free_result($request); $context['page_index'] = constructPageIndex($scripturl . '?action=moderate;area=attachmod;sa=attachments', $_GET['start'], $context['total_unapproved_attachments'], 10); $context['start'] = $_GET['start']; // Get all unapproved attachments. $request = smf_db_query(' SELECT a.id_attach, a.filename, a.size, m.id_msg, m.id_topic, m.id_board, m.subject, m.body, m.id_member, IFNULL(mem.real_name, m.poster_name) AS poster_name, m.poster_time, t.id_member_started, t.id_first_msg, b.name AS board_name, c.id_cat, c.name AS cat_name FROM {db_prefix}attachments AS a INNER JOIN {db_prefix}messages AS m ON (m.id_msg = a.id_msg) 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 = m.id_board) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) LEFT JOIN {db_prefix}categories AS c ON (c.id_cat = b.id_cat) WHERE a.approved = {int:not_approved} AND a.attachment_type = {int:attachment_type} AND {query_see_board} ' . $approve_query . ' LIMIT ' . $context['start'] . ', 10', array('not_approved' => 0, 'attachment_type' => 0)); $context['unapproved_items'] = array(); for ($i = 1; $row = mysql_fetch_assoc($request); $i++) { $context['unapproved_items'][] = array('id' => $row['id_attach'], 'alternate' => $i % 2, 'filename' => $row['filename'], 'size' => round($row['size'] / 1024, 2), 'time' => timeformat($row['poster_time']), 'poster' => array('id' => $row['id_member'], 'name' => $row['poster_name'], 'link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['poster_name'] . '</a>' : $row['poster_name'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member']), 'message' => array('id' => $row['id_msg'], 'subject' => $row['subject'], 'body' => parse_bbc($row['body']), 'time' => timeformat($row['poster_time']), 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg']), 'topic' => array('id' => $row['id_topic']), 'board' => array('id' => $row['id_board'], 'name' => $row['board_name']), 'category' => array('id' => $row['id_cat'], 'name' => $row['cat_name'])); } mysql_free_result($request); EoS_Smarty::loadTemplate('modcenter/modcenter_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/unapproved_attachments'); // The ever popular approve button, with the massively unpopular delete. $context['approve_button'] = create_button('approve', 'approve'); $context['remove_button'] = create_button('remove_message', 'remove'); }
function db_debug_junk() { global $context, $scripturl, $boarddir, $modSettings, $boarddir; global $db_cache, $db_count, $db_show_debug, $cache_count, $cache_hits, $txt; // Add to Settings.php if you want to show the debugging information. if (!isset($db_show_debug) || $db_show_debug !== true || isset($_GET['action']) && $_GET['action'] == 'viewquery' || WIRELESS) { return; } if (empty($_SESSION['view_queries'])) { $_SESSION['view_queries'] = 0; } if (empty($context['debug']['language_files'])) { $context['debug']['language_files'] = array(); } if (empty($context['debug']['sheets'])) { $context['debug']['sheets'] = array(); } $files = get_included_files(); $total_size = 0; for ($i = 0, $n = count($files); $i < $n; $i++) { if (file_exists($files[$i])) { $total_size += filesize($files[$i]); } $files[$i] = strtr($files[$i], array($boarddir => '.')); } $warnings = 0; if (!empty($db_cache)) { foreach ($db_cache as $q => $qq) { if (!empty($qq['w'])) { $warnings += count($qq['w']); } } $_SESSION['debug'] =& $db_cache; } // Gotta have valid HTML ;). $temp = ob_get_contents(); if (function_exists('ob_clean')) { ob_clean(); } else { ob_end_clean(); ob_start('ob_sessrewrite'); } if (EoS_Smarty::isActive()) { $_t = EoS_Smarty::getSmartyInstance()->getTemplateDir(); $smarty_template_dirs = is_array($_t) ? implode(', ', $_t) : $_t; $_t = EoS_Smarty::getTemplates(); $smarty_templates = is_array($_t) ? implode(', ', $_t) : $_t; $smarty_debug_info = '<h1 class="bigheader secondary borderless">Smarty debug info</h1><span style="font-size:1.1em;color:red;"><strong>Template directories:</strong></span> ' . $smarty_template_dirs . '</br><span style="font-size:1.1em;color:red;"><strong>Templates:</strong></span> ' . $smarty_templates . '<br>' . EoS_Smarty::getConfigInstance()->getHookDebugInfo() . '<br>'; } else { $smarty_debug_info = ''; } echo preg_replace('~</body>\\s*</html>~', '', $temp), ' <div class="smalltext" style="text-align: left; margin: 1ex;"> ', isset($context['debug']['templates']) ? $txt['debug_templates'] . count($context['debug']['templates']) . ': <em>' . implode('</em>, <em>', $context['debug']['templates']) . '</em>.<br />' : '', ' ', isset($context['debug']['sub_templates']) ? $txt['debug_subtemplates'] . count($context['debug']['sub_templates']) . ': <em>' . implode('</em>, <em>', $context['debug']['sub_templates']) . '</em>.<br />' : '', ' ', $txt['debug_language_files'], count($context['debug']['language_files']), ': <em>', implode('</em>, <em>', $context['debug']['language_files']), '</em>.<br /> ', $txt['debug_stylesheets'], count($context['debug']['sheets']), ': <em>', implode('</em>, <em>', $context['debug']['sheets']), '</em>.<br /> ', $txt['debug_files_included'], count($files), ' - ', round($total_size / 1024), $txt['debug_kb'], ' (<a href="javascript:void(0);" onclick="document.getElementById(\'debug_include_info\').style.display = \'inline\'; this.style.display = \'none\'; return false;">', $txt['debug_show'], '</a><span id="debug_include_info" style="display: none;"><em>', implode('</em>, <em>', $files), '</em></span>)<br />', $smarty_debug_info; if (!empty($modSettings['cache_enable']) && !empty($cache_hits)) { $entries = array(); $total_t = 0; $total_s = 0; foreach ($cache_hits as $cache_hit) { $entries[] = $cache_hit['d'] . ' ' . $cache_hit['k'] . ': ' . sprintf($txt['debug_cache_seconds_bytes'], comma_format($cache_hit['t'], 5), $cache_hit['s']); $total_t += $cache_hit['t']; $total_s += $cache_hit['s']; } echo ' ', $txt['debug_cache_hits'], $cache_count, ': ', sprintf($txt['debug_cache_seconds_bytes_total'], comma_format($total_t, 5), comma_format($total_s)), ' (<a href="javascript:void(0);" onclick="document.getElementById(\'debug_cache_info\').style.display = \'inline\'; this.style.display = \'none\'; return false;">', $txt['debug_show'], '</a><span id="debug_cache_info" style="display: none;"><em>', implode('</em>, <em>', $entries), '</em></span>)<br />'; } echo ' <a href="', $scripturl, '?action=viewquery" target="_blank" class="new_win">', $warnings == 0 ? sprintf($txt['debug_queries_used'], (int) $db_count) : sprintf($txt['debug_queries_used_and_warnings'], (int) $db_count, $warnings), '</a><br /> <br />'; if ($_SESSION['view_queries'] == 1 && !empty($db_cache)) { foreach ($db_cache as $q => $qq) { $is_select = substr(trim($qq['q']), 0, 6) == 'SELECT' || preg_match('~^INSERT(?: IGNORE)? INTO \\w+(?:\\s+\\([^)]+\\))?\\s+SELECT .+$~s', trim($qq['q'])) != 0; // Temporary tables created in earlier queries are not explainable. if ($is_select) { foreach (array('log_topics_unread', 'topics_posted_in', 'tmp_log_search_topics', 'tmp_log_search_messages') as $tmp) { if (strpos(trim($qq['q']), $tmp) !== false) { $is_select = false; break; } } } elseif (preg_match('~^CREATE TEMPORARY TABLE .+?SELECT .+$~s', trim($qq['q'])) != 0) { $is_select = true; } // Make the filenames look a bit better. if (isset($qq['f'])) { $qq['f'] = preg_replace('~^' . preg_quote($boarddir, '~') . '~', '...', $qq['f']); } echo ' <strong>', $is_select ? '<a href="' . $scripturl . '?action=viewquery;qq=' . ($q + 1) . '#qq' . $q . '" target="_blank" class="new_win" style="text-decoration: none;">' : '', nl2br(str_replace("\t", ' ', htmlspecialchars(ltrim($qq['q'], "\n\r")))) . ($is_select ? '</a></strong>' : '</strong>') . '<br /> '; if (!empty($qq['f']) && !empty($qq['l'])) { echo sprintf($txt['debug_query_in_line'], $qq['f'], $qq['l']); } if (isset($qq['s'], $qq['t']) && isset($txt['debug_query_which_took_at'])) { echo sprintf($txt['debug_query_which_took_at'], round($qq['t'], 8), round($qq['s'], 8)) . '<br />'; } elseif (isset($qq['t'])) { echo sprintf($txt['debug_query_which_took'], round($qq['t'], 8)) . '<br />'; } echo ' <br />'; } } echo ' <a href="' . $scripturl . '?action=viewquery;sa=hide">', $txt['debug_' . (empty($_SESSION['view_queries']) ? 'show' : 'hide') . '_queries'], '</a> </div></body></html>'; }
function GroupRequests() { global $txt, $context, $scripturl, $user_info, $sourcedir, $smcFunc, $modSettings, $language; //if(isset($_REQUEST['action']) && $_REQUEST['action'] === 'moderate') EoS_Smarty::loadTemplate('modcenter/modcenter_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/list_groups'); // Set up the template stuff... $context['page_title'] = $txt['mc_group_requests']; //$context['sub_template'] = 'show_list'; // Verify we can be here. if ($user_info['mod_cache']['gq'] == '0=1') { isAllowedTo('manage_membergroups'); } // Normally, we act normally... $where = $user_info['mod_cache']['gq'] == '1=1' || $user_info['mod_cache']['gq'] == '0=1' ? $user_info['mod_cache']['gq'] : 'lgr.' . $user_info['mod_cache']['gq']; $where_parameters = array(); // We've submitted? if (isset($_POST[$context['session_var']]) && !empty($_POST['groupr']) && !empty($_POST['req_action'])) { checkSession('post'); // Clean the values. foreach ($_POST['groupr'] as $k => $request) { $_POST['groupr'][$k] = (int) $request; } // If we are giving a reason (And why shouldn't we?), then we don't actually do much. if ($_POST['req_action'] == 'reason') { // Different sub template... $context['sub_template'] = 'group_request_reason'; // And a limitation. We don't care that the page number bit makes no sense, as we don't need it! $where .= ' AND lgr.id_request IN ({array_int:request_ids})'; $where_parameters['request_ids'] = $_POST['groupr']; $context['group_requests'] = list_getGroupRequests(0, $modSettings['defaultMaxMessages'], 'lgr.id_request', $where, $where_parameters); // Let obExit etc sort things out. obExit(); } else { // Get the details of all the members concerned... $request = smf_db_query(' SELECT lgr.id_request, lgr.id_member, lgr.id_group, mem.email_address, mem.id_group AS primary_group, mem.additional_groups AS additional_groups, mem.lngfile, mem.member_name, mem.notify_types, mg.hidden, mg.group_name FROM {db_prefix}log_group_requests AS lgr INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member) INNER JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group) WHERE ' . $where . ' AND lgr.id_request IN ({array_int:request_list}) ORDER BY mem.lngfile', array('request_list' => $_POST['groupr'])); $email_details = array(); $group_changes = array(); while ($row = mysql_fetch_assoc($request)) { $row['lngfile'] = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']; // If we are approving work out what their new group is. if ($_POST['req_action'] == 'approve') { // For people with more than one request at once. if (isset($group_changes[$row['id_member']])) { $row['additional_groups'] = $group_changes[$row['id_member']]['add']; $row['primary_group'] = $group_changes[$row['id_member']]['primary']; } else { $row['additional_groups'] = explode(',', $row['additional_groups']); } // Don't have it already? if ($row['primary_group'] == $row['id_group'] || in_array($row['id_group'], $row['additional_groups'])) { continue; } // Should it become their primary? if ($row['primary_group'] == 0 && $row['hidden'] == 0) { $row['primary_group'] = $row['id_group']; } else { $row['additional_groups'][] = $row['id_group']; } // Add them to the group master list. $group_changes[$row['id_member']] = array('primary' => $row['primary_group'], 'add' => $row['additional_groups']); } // Add required information to email them. if ($row['notify_types'] != 4) { $email_details[] = array('rid' => $row['id_request'], 'member_id' => $row['id_member'], 'member_name' => $row['member_name'], 'group_id' => $row['id_group'], 'group_name' => $row['group_name'], 'email' => $row['email_address'], 'language' => $row['lngfile']); } } mysql_free_result($request); // Remove the evidence... smf_db_query(' DELETE FROM {db_prefix}log_group_requests WHERE id_request IN ({array_int:request_list})', array('request_list' => $_POST['groupr'])); // Ensure everyone who is online gets their changes right away. updateSettings(array('settings_updated' => time())); if (!empty($email_details)) { require_once $sourcedir . '/lib/Subs-Post.php'; // They are being approved? if ($_POST['req_action'] == 'approve') { // Make the group changes. foreach ($group_changes as $id => $groups) { // Sanity check! foreach ($groups['add'] as $key => $value) { if ($value == 0 || trim($value) == '') { unset($groups['add'][$key]); } } smf_db_query(' UPDATE {db_prefix}members SET id_group = {int:primary_group}, additional_groups = {string:additional_groups} WHERE id_member = {int:selected_member}', array('primary_group' => $groups['primary'], 'selected_member' => $id, 'additional_groups' => implode(',', $groups['add']))); } $lastLng = $user_info['language']; foreach ($email_details as $email) { $replacements = array('USERNAME' => $email['member_name'], 'GROUPNAME' => $email['group_name']); $emaildata = loadEmailTemplate('mc_group_approve', $replacements, $email['language']); sendmail($email['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 2); } } else { // Same as for approving, kind of. $lastLng = $user_info['language']; foreach ($email_details as $email) { $custom_reason = isset($_POST['groupreason']) && isset($_POST['groupreason'][$email['rid']]) ? $_POST['groupreason'][$email['rid']] : ''; $replacements = array('USERNAME' => $email['member_name'], 'GROUPNAME' => $email['group_name']); if (!empty($custom_reason)) { $replacements['REASON'] = $custom_reason; } $emaildata = loadEmailTemplate(empty($custom_reason) ? 'mc_group_reject' : 'mc_group_reject_reason', $replacements, $email['language']); sendmail($email['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 2); } } } // Restore the current language. loadLanguage('ModerationCenter'); } } // We're going to want this for making our list. require_once $sourcedir . '/lib/Subs-List.php'; // This is all the information required for a group listing. $listOptions = array('id' => 'group_request_list', 'title' => $txt['mc_group_requests'], 'width' => '100%', 'items_per_page' => $modSettings['defaultMaxMessages'], 'no_items_label' => $txt['mc_groupr_none_found'], 'base_href' => $scripturl . '?action=groups;sa=requests', 'default_sort_col' => 'member', 'get_items' => array('function' => 'list_getGroupRequests', 'params' => array($where, $where_parameters)), 'get_count' => array('function' => 'list_getGroupRequestCount', 'params' => array($where, $where_parameters)), 'columns' => array('member' => array('header' => array('value' => $txt['mc_groupr_member']), 'data' => array('db' => 'member_link'), 'sort' => array('default' => 'mem.member_name', 'reverse' => 'mem.member_name DESC')), 'group' => array('header' => array('value' => $txt['mc_groupr_group']), 'data' => array('db' => 'group_link'), 'sort' => array('default' => 'mg.group_name', 'reverse' => 'mg.group_name DESC')), 'reason' => array('header' => array('value' => $txt['mc_groupr_reason']), 'data' => array('db' => 'reason')), 'action' => array('header' => array('value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />', 'style' => 'width: 4%;'), 'data' => array('sprintf' => array('format' => '<input type="checkbox" name="groupr[]" value="%1$d" class="input_check" />', 'params' => array('id' => false)), 'style' => 'text-align: center;'))), 'form' => array('href' => $scripturl . '?action=groups;sa=requests', 'include_sort' => true, 'include_start' => true, 'hidden_fields' => array($context['session_var'] => $context['session_id'])), 'additional_rows' => array(array('position' => 'bottom_of_list', 'value' => ' <select name="req_action" onchange="if (this.value != 0 && (this.value == \'reason\' || confirm(\'' . $txt['mc_groupr_warning'] . '\'))) this.form.submit();"> <option value="0">' . $txt['with_selected'] . ':</option> <option value="0">---------------------</option> <option value="approve">' . $txt['mc_groupr_approve'] . '</option> <option value="reject">' . $txt['mc_groupr_reject'] . '</option> <option value="reason">' . $txt['mc_groupr_reject_w_reason'] . '</option> </select> <input type="submit" name="go" value="' . $txt['go'] . '" onclick="var sel = document.getElementById(\'req_action\'); if (sel.value != 0 && sel.value != \'reason\' && !confirm(\'' . $txt['mc_groupr_warning'] . '\')) return false;" class="button_submit" />', 'align' => 'right'))); // Create the request list. createList($listOptions); $context['default_list'] = 'group_request_list'; }
function BoardNotify() { global $scripturl, $txt, $board, $user_info, $context, $smcFunc; // Permissions are an important part of anything ;). is_not_guest(); isAllowedTo('mark_notify'); // You have to specify a board to turn notifications on! if (empty($board)) { fatal_lang_error('no_board', false); } // No subaction: find out what to do. if (empty($_GET['sa'])) { // We're gonna need the notify template... Eos_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'notify/notify_board'); // Find out if they have notification set for this topic already. $request = smf_db_query(' SELECT id_member FROM {db_prefix}log_notify WHERE id_member = {int:current_member} AND id_board = {int:current_board} LIMIT 1', array('current_board' => $board, 'current_member' => $user_info['id'])); $context['notification_set'] = mysql_num_rows($request) != 0; mysql_free_result($request); // Set the template variables... $context['board_href'] = $scripturl . '?board=' . $board . '.' . $_REQUEST['start']; $context['start'] = $_REQUEST['start']; $context['page_title'] = $txt['notification']; return; } elseif ($_GET['sa'] == 'on') { checkSession('get'); // Turn notification on. (note this just blows smoke if it's already on.) smf_db_insert('ignore', '{db_prefix}log_notify', array('id_member' => 'int', 'id_board' => 'int'), array($user_info['id'], $board), array('id_member', 'id_board')); } else { checkSession('get'); // Turn notification off for this board. smf_db_query(' DELETE FROM {db_prefix}log_notify WHERE id_member = {int:current_member} AND id_board = {int:current_board}', array('current_board' => $board, 'current_member' => $user_info['id'])); } // Back to the board! redirectexit('board=' . $board . '.' . $_REQUEST['start']); }
function ViewModlog() { global $txt, $modSettings, $context, $scripturl, $sourcedir, $user_info, $smcFunc, $settings; // Are we looking at the moderation log or the administration log. $context['log_type'] = isset($_REQUEST['sa']) && $_REQUEST['sa'] == 'adminlog' ? 3 : 1; if ($context['log_type'] == 3) { isAllowedTo('admin_forum'); } // These change dependant on whether we are viewing the moderation or admin log. if ($context['log_type'] == 3 || $_REQUEST['action'] == 'admin') { $context['url_start'] = '?action=admin;area=logs;sa=' . ($context['log_type'] == 3 ? 'adminlog' : 'modlog') . ';type=' . $context['log_type']; } else { $context['url_start'] = '?action=moderate;area=modlog;type=' . $context['log_type']; } $context['can_delete'] = allowedTo('admin_forum'); loadLanguage('Modlog'); $context['page_title'] = $context['log_type'] == 3 ? $txt['modlog_admin_log'] : $txt['modlog_view']; // The number of entries to show per page of log file. $context['displaypage'] = 30; // Amount of hours that must pass before allowed to delete file. $context['hoursdisable'] = 24; // Handle deletion... if (isset($_POST['removeall']) && $context['can_delete']) { checkSession(); smf_db_query(' DELETE FROM {db_prefix}log_actions WHERE id_log = {int:moderate_log} AND log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => time() - $context['hoursdisable'] * 3600, 'moderate_log' => $context['log_type'])); } elseif (!empty($_POST['remove']) && isset($_POST['delete']) && $context['can_delete']) { checkSession(); smf_db_query(' DELETE FROM {db_prefix}log_actions WHERE id_log = {int:moderate_log} AND id_action IN ({array_string:delete_actions}) AND log_time < {int:twenty_four_hours_wait}', array('twenty_four_hours_wait' => time() - $context['hoursdisable'] * 3600, 'delete_actions' => array_unique($_POST['delete']), 'moderate_log' => $context['log_type'])); } // Do the column stuff! $sort_types = array('action' => 'lm.action', 'time' => 'lm.log_time', 'member' => 'mem.real_name', 'group' => 'mg.group_name', 'ip' => 'lm.ip'); // Setup the direction stuff... $context['order'] = isset($_REQUEST['sort']) && isset($sort_types[$_REQUEST['sort']]) ? $_REQUEST['sort'] : 'time'; // If we're coming from a search, get the variables. if (!empty($_REQUEST['params']) && empty($_REQUEST['is_search'])) { $search_params = base64_decode(strtr($_REQUEST['params'], array(' ' => '+'))); $search_params = @unserialize($search_params); } // This array houses all the valid search types. $searchTypes = array('action' => array('sql' => 'lm.action', 'label' => $txt['modlog_action']), 'member' => array('sql' => 'mem.real_name', 'label' => $txt['modlog_member']), 'group' => array('sql' => 'mg.group_name', 'label' => $txt['modlog_position']), 'ip' => array('sql' => 'lm.ip', 'label' => $txt['modlog_ip'])); if (!isset($search_params['string']) || !empty($_REQUEST['search']) && $search_params['string'] != $_REQUEST['search']) { $search_params_string = empty($_REQUEST['search']) ? '' : $_REQUEST['search']; } else { $search_params_string = $search_params['string']; } if (isset($_REQUEST['search_type']) || empty($search_params['type']) || !isset($searchTypes[$search_params['type']])) { $search_params_type = isset($_REQUEST['search_type']) && isset($searchTypes[$_REQUEST['search_type']]) ? $_REQUEST['search_type'] : (isset($searchTypes[$context['order']]) ? $context['order'] : 'member'); } else { $search_params_type = $search_params['type']; } $search_params_column = $searchTypes[$search_params_type]['sql']; $search_params = array('string' => $search_params_string, 'type' => $search_params_type); // Setup the search context. $context['search_params'] = empty($search_params['string']) ? '' : base64_encode(serialize($search_params)); $context['search'] = array('string' => htmlspecialchars($search_params['string']), 'type' => $search_params['type'], 'label' => $searchTypes[$search_params_type]['label']); // If they are searching by action, then we must do some manual intervention to search in their language! if ($search_params['type'] == 'action' && !empty($search_params['string'])) { // For the moment they can only search for ONE action! foreach ($txt as $key => $text) { if (substr($key, 0, 10) == 'modlog_ac_' && strpos($text, $search_params['string']) !== false) { $search_params['string'] = substr($key, 10); break; } } } require_once $sourcedir . '/lib/Subs-List.php'; // This is all the information required for a watched user listing. $listOptions = array('id' => 'moderation_log_list', 'title' => '<a href="' . $scripturl . '?action=helpadmin;help=' . ($context['log_type'] == 3 ? 'adminlog' : 'modlog') . '" onclick="return reqWin(this.href);" class="help"><strong>[' . $txt['help'] . '] </strong></a> ' . $txt['modlog_' . ($context['log_type'] == 3 ? 'admin' : 'moderation') . '_log'], 'width' => '100%', 'items_per_page' => $context['displaypage'], 'no_items_label' => $txt['modlog_' . ($context['log_type'] == 3 ? 'admin_log_' : '') . 'no_entries_found'], 'base_href' => $scripturl . $context['url_start'] . (!empty($context['search_params']) ? ';params=' . $context['search_params'] : ''), 'default_sort_col' => 'time', 'get_items' => array('function' => 'list_getModLogEntries', 'params' => array(!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : '', array('sql_type' => $search_params_column, 'search_string' => $search_params['string']), $context['log_type'])), 'get_count' => array('function' => 'list_getModLogEntryCount', 'params' => array(!empty($search_params['string']) ? ' INSTR({raw:sql_type}, {string:search_string})' : '', array('sql_type' => $search_params_column, 'search_string' => $search_params['string']), $context['log_type'])), 'columns' => array('action' => array('header' => array('value' => $txt['modlog_action'], 'class' => 'lefttext first_th'), 'data' => array('db' => 'action_text', 'class' => 'smalltext'), 'sort' => array('default' => 'lm.action', 'reverse' => 'lm.action DESC')), 'time' => array('header' => array('value' => $txt['modlog_date'], 'class' => 'lefttext'), 'data' => array('db' => 'time', 'class' => 'smalltext'), 'sort' => array('default' => 'lm.log_time DESC', 'reverse' => 'lm.log_time')), 'moderator' => array('header' => array('value' => $txt['modlog_member'], 'class' => 'lefttext'), 'data' => array('db' => 'moderator_link', 'class' => 'smalltext'), 'sort' => array('default' => 'mem.real_name', 'reverse' => 'mem.real_name DESC')), 'position' => array('header' => array('value' => $txt['modlog_position'], 'class' => 'lefttext'), 'data' => array('db' => 'position', 'class' => 'smalltext'), 'sort' => array('default' => 'mg.group_name', 'reverse' => 'mg.group_name DESC')), 'ip' => array('header' => array('value' => $txt['modlog_ip'], 'class' => 'lefttext'), 'data' => array('db' => 'ip', 'class' => 'smalltext'), 'sort' => array('default' => 'lm.ip', 'reverse' => 'lm.ip DESC')), 'delete' => array('header' => array('value' => '<input type="checkbox" name="all" class="input_check" onclick="invertAll(this, this.form);" />'), 'data' => array('function' => create_function('$entry', ' return \'<input type="checkbox" class="input_check" name="delete[]" value="\' . $entry[\'id\'] . \'"\' . ($entry[\'editable\'] ? \'\' : \' disabled="disabled"\') . \' />\'; '), 'style' => 'text-align: center;'))), 'form' => array('href' => $scripturl . $context['url_start'], 'include_sort' => true, 'include_start' => true, 'hidden_fields' => array($context['session_var'] => $context['session_id'], 'params' => $context['search_params'])), 'additional_rows' => array(array('position' => 'after_title', 'value' => $txt['modlog_' . ($context['log_type'] == 3 ? 'admin' : 'moderation') . '_log_desc'], 'class' => 'smalltext', 'style' => 'padding: 2ex;'), array('position' => 'below_table_data', 'value' => ' ' . $txt['modlog_search'] . ' (' . $txt['modlog_by'] . ': ' . $context['search']['label'] . '): <input type="text" name="search" size="18" value="' . $context['search']['string'] . '" class="input_text" /> <input type="submit" name="is_search" value="' . $txt['modlog_go'] . '" class="button_submit" /> ' . ($context['can_delete'] ? ' | <input type="submit" name="remove" value="' . $txt['modlog_remove'] . '" class="button_submit" /> <input type="submit" name="removeall" value="' . $txt['modlog_removeall'] . '" class="button_submit" />' : '')))); EoS_Smarty::loadTemplate('modcenter/modcenter_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/modlog'); // Create the watched user list. createList($listOptions); //$context['sub_template'] = 'show_list'; $context['default_list'] = 'moderation_log_list'; }
function is_not_guest($message = '') { global $user_info, $txt, $context, $scripturl; // Luckily, this person isn't a guest. if (!$user_info['is_guest']) { return; } // People always worry when they see people doing things they aren't actually doing... $_GET['action'] = ''; $_GET['board'] = ''; $_GET['topic'] = ''; writeLog(true); // Just die. if (isset($_REQUEST['xml'])) { obExit(false); } // Attempt to detect if they came from dlattach. if (SMF != 'SSI' && empty($context['theme_loaded'])) { loadTheme(); } // Never redirect to an attachment if (strpos($_SERVER['REQUEST_URL'], 'dlattach') === false) { $_SESSION['login_url'] = $_SERVER['REQUEST_URL']; } // Load the Login template and language file. loadLanguage('Login'); // Apparently we're not in a position to handle this now. Let's go to a safer location for now. if (empty($context['template_layers'])) { $_SESSION['login_url'] = $scripturl . '?' . $_SERVER['QUERY_STRING']; redirectexit('action=login'); } else { EoS_Smarty::resetTemplates(); EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/login'); $context['is_kick_guest'] = true; $context['robot_no_index'] = true; } // Use the kick_guest sub template... $context['kick_message'] = $message; $context['page_title'] = $txt['login']; obExit(); // We should never get to this point, but if we did we wouldn't know the user isn't a guest. trigger_error('Hacking attempt...', E_USER_ERROR); }
function adminLogin() { global $context, $scripturl, $txt, $user_info, $user_settings; loadLanguage('Admin'); EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/adminlogin'); // They used a wrong password, log it and unset that. if (isset($_POST['admin_hash_pass']) || isset($_POST['admin_pass'])) { $txt['security_wrong'] = sprintf($txt['security_wrong'], isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : $txt['unknown'], $_SERVER['HTTP_USER_AGENT'], $user_info['ip']); log_error($txt['security_wrong'], 'critical'); if (isset($_POST['admin_hash_pass'])) { unset($_POST['admin_hash_pass']); } if (isset($_POST['admin_pass'])) { unset($_POST['admin_pass']); } $context['incorrect_password'] = true; } // Figure out the get data and post data. $context['get_data'] = '?' . construct_query_string($_GET); $context['post_data'] = ''; // Now go through $_POST. Make sure the session hash is sent. $_POST[$context['session_var']] = $context['session_id']; foreach ($_POST as $k => $v) { $context['post_data'] .= adminLogin_outputPostVars($k, $v); } // And title the page something like "Login". if (!isset($context['page_title'])) { $context['page_title'] = $txt['login']; } obExit(); // We MUST exit at this point, because otherwise we CANNOT KNOW that the user is privileged. trigger_error('Hacking attempt...', E_USER_ERROR); }
function ManageRules() { global $txt, $context, $user_info, $scripturl, $smcFunc; // The link tree - gotta have this :o $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manrules', 'name' => $txt['pm_manage_rules']); $_ctx = new PMContext(); $context['page_title'] = $txt['pm_manage_rules']; EoS_Smarty::loadTemplate('pm/base'); // Load them... load them!! LoadRules(); // Likely to need all the groups! $request = smf_db_query(' SELECT mg.id_group, mg.group_name, IFNULL(gm.id_member, 0) AS can_moderate, mg.hidden FROM {db_prefix}membergroups AS mg LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member}) WHERE mg.min_posts = {int:min_posts} AND mg.id_group != {int:moderator_group} AND mg.hidden = {int:not_hidden} ORDER BY mg.group_name', array('current_member' => $user_info['id'], 'min_posts' => -1, 'moderator_group' => 3, 'not_hidden' => 0)); $context['groups'] = array(); while ($row = mysql_fetch_assoc($request)) { // Hide hidden groups! if ($row['hidden'] && !$row['can_moderate'] && !allowedTo('manage_membergroups')) { continue; } $context['groups'][$row['id_group']] = $row['group_name']; } mysql_free_result($request); // Applying all rules? if (isset($_GET['apply'])) { checkSession('get'); ApplyRules(true); redirectexit('action=pm;sa=manrules'); } // Editing a specific one? if (isset($_GET['add'])) { $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; EoS_Smarty::getConfigInstance()->registerHookTemplate('pm_content_area', 'pm/add_rule'); // Current rule information... if ($context['rid']) { $context['rule'] = $context['rules'][$context['rid']]; $members = array(); // Need to get member names! foreach ($context['rule']['criteria'] as $k => $criteria) { if ($criteria['t'] == 'mid' && !empty($criteria['v'])) { $members[(int) $criteria['v']] = $k; } } if (!empty($members)) { $request = smf_db_query(' SELECT id_member, member_name FROM {db_prefix}members WHERE id_member IN ({array_int:member_list})', array('member_list' => array_keys($members))); while ($row = mysql_fetch_assoc($request)) { $context['rule']['criteria'][$members[$row['id_member']]]['v'] = $row['member_name']; } mysql_free_result($request); } } else { $context['rule'] = array('id' => '', 'name' => '', 'criteria' => array(), 'actions' => array(), 'logic' => 'and'); } $context['rule']['criteria'][] = array('t' => '', 'v' => ''); $context['rule']['actions'][] = array('t' => '', 'v' => ''); } elseif (isset($_GET['save'])) { checkSession('post'); $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; // Name is easy! $ruleName = commonAPI::htmlspecialchars(trim($_POST['rule_name'])); if (empty($ruleName)) { fatal_lang_error('pm_rule_no_name', false); } // Sanity check... if (empty($_POST['ruletype']) || empty($_POST['acttype'])) { fatal_lang_error('pm_rule_no_criteria', false); } // Let's do the criteria first - it's also hardest! $criteria = array(); foreach ($_POST['ruletype'] as $ind => $type) { // Check everything is here... if ($type == 'gid' && (!isset($_POST['ruledefgroup'][$ind]) || !isset($context['groups'][$_POST['ruledefgroup'][$ind]]))) { continue; } elseif ($type != 'bud' && !isset($_POST['ruledef'][$ind])) { continue; } // Members need to be found. if ($type == 'mid') { $name = trim($_POST['ruledef'][$ind]); $request = smf_db_query(' SELECT id_member FROM {db_prefix}members WHERE real_name = {string:member_name} OR member_name = {string:member_name}', array('member_name' => $name)); if (mysql_num_rows($request) == 0) { continue; } list($memID) = mysql_fetch_row($request); mysql_free_result($request); $criteria[] = array('t' => 'mid', 'v' => $memID); } elseif ($type == 'bud') { $criteria[] = array('t' => 'bud', 'v' => 1); } elseif ($type == 'gid') { $criteria[] = array('t' => 'gid', 'v' => (int) $_POST['ruledefgroup'][$ind]); } elseif (in_array($type, array('sub', 'msg')) && trim($_POST['ruledef'][$ind]) != '') { $criteria[] = array('t' => $type, 'v' => commonAPI::htmlspecialchars(trim($_POST['ruledef'][$ind]))); } } // Also do the actions! $actions = array(); $doDelete = 0; $isOr = $_POST['rule_logic'] == 'or' ? 1 : 0; foreach ($_POST['acttype'] as $ind => $type) { // Picking a valid label? if ($type == 'lab' && (!isset($_POST['labdef'][$ind]) || !isset($context['labels'][$_POST['labdef'][$ind] - 1]))) { continue; } // Record what we're doing. if ($type == 'del') { $doDelete = 1; } elseif ($type == 'lab') { $actions[] = array('t' => 'lab', 'v' => (int) $_POST['labdef'][$ind] - 1); } } if (empty($criteria) || empty($actions) && !$doDelete) { fatal_lang_error('pm_rule_no_criteria', false); } // What are we storing? $criteria = serialize($criteria); $actions = serialize($actions); // Create the rule? if (empty($context['rid'])) { smf_db_insert('', '{db_prefix}pm_rules', array('id_member' => 'int', 'rule_name' => 'string', 'criteria' => 'string', 'actions' => 'string', 'delete_pm' => 'int', 'is_or' => 'int'), array($user_info['id'], $ruleName, $criteria, $actions, $doDelete, $isOr), array('id_rule')); } else { smf_db_query(' UPDATE {db_prefix}pm_rules SET rule_name = {string:rule_name}, criteria = {string:criteria}, actions = {string:actions}, delete_pm = {int:delete_pm}, is_or = {int:is_or} WHERE id_rule = {int:id_rule} AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'delete_pm' => $doDelete, 'is_or' => $isOr, 'id_rule' => $context['rid'], 'rule_name' => $ruleName, 'criteria' => $criteria, 'actions' => $actions)); } redirectexit('action=pm;sa=manrules'); } elseif (isset($_POST['delselected']) && !empty($_POST['delrule'])) { checkSession('post'); $toDelete = array(); foreach ($_POST['delrule'] as $k => $v) { $toDelete[] = (int) $k; } if (!empty($toDelete)) { smf_db_query(' DELETE FROM {db_prefix}pm_rules WHERE id_rule IN ({array_int:delete_list}) AND id_member = {int:current_member}', array('current_member' => $user_info['id'], 'delete_list' => $toDelete)); } redirectexit('action=pm;sa=manrules'); } EoS_Smarty::getConfigInstance()->registerHookTemplate('pm_content_area', 'pm/manage_rules'); }
function SecretAnswer2() { global $txt, $context, $modSettings, $smcFunc, $sourcedir; checkSession(); // Hacker? How did you get this far without an email or username? if (empty($_REQUEST['uid'])) { fatal_lang_error('username_no_exist', false); } loadLanguage('Login'); // Get the information from the database. $request = smf_db_query(' SELECT id_member, real_name, member_name, secret_answer, secret_question, openid_uri, email_address FROM {db_prefix}members WHERE id_member = {int:id_member} LIMIT 1', array('id_member' => $_REQUEST['uid'])); if (mysql_num_rows($request) == 0) { fatal_lang_error('username_no_exist', false); } $row = mysql_fetch_assoc($request); mysql_free_result($request); // Check if the secret answer is correct. if ($row['secret_question'] == '' || $row['secret_answer'] == '' || md5($_POST['secret_answer']) != $row['secret_answer']) { log_error(sprintf($txt['reminder_error'], $row['member_name']), 'user'); fatal_lang_error('incorrect_answer', false); } // If it's OpenID this is where the music ends. if (!empty($row['openid_uri'])) { $context['sub_template'] = 'sent'; $context['description'] = sprintf($txt['reminder_openid_is'], $row['openid_uri']); return; } // You can't use a blank one! if (strlen(trim($_POST['passwrd1'])) === 0) { fatal_lang_error('no_password', false); } // They have to be the same too. if ($_POST['passwrd1'] != $_POST['passwrd2']) { fatal_lang_error('passwords_dont_match', false); } // Make sure they have a strong enough password. require_once $sourcedir . '/lib/Subs-Auth.php'; $passwordError = validatePassword($_POST['passwrd1'], $row['member_name'], array($row['email_address'])); // Invalid? if ($passwordError != null) { fatal_lang_error('profile_error_password_' . $passwordError, false); } // Alright, so long as 'yer sure. updateMemberData($row['id_member'], array('passwd' => sha1(strtolower($row['member_name']) . $_POST['passwrd1']))); HookAPI::callHook('integrate_reset_pass', array($row['member_name'], $row['member_name'], $_POST['passwrd1'])); // Tell them it went fine. EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/login'); $context += array('page_title' => $txt['reminder_password_set'], 'default_username' => $row['member_name'], 'default_password' => $_POST['passwrd1'], 'never_expire' => false, 'description' => $txt['reminder_password_set']); }
function TopicBans() { global $context, $board_info, $topic, $txt, $memberContext, $user_info; EoS_Smarty::loadTemplate('modcenter/modcenter_base'); if (isset($_REQUEST['sa']) && ($_REQUEST['sa'] === 'unban' || $_REQUEST['sa'] === 'ban')) { $is_ban = $_REQUEST['sa'] === 'ban' ? 1 : 0; $context['page_title'] = $is_ban ? $txt['mc_issue_topic_ban'] : $txt['mc_lift_topic_ban']; EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/topicban_issue_or_lift'); $context['op_errors'] = array(); $member = isset($_REQUEST['m']) ? (int) $_REQUEST['m'] : 0; if (!isset($topic) || empty($topic) || !isset($board_info) || empty($board_info) || 0 == $member) { $context['op_errors'][] = $txt['mc_lift_topic_ban_missing_data']; } if (!allowedTo('moderate_board')) { $context['op_errors'][] = $txt['mc_lift_topic_ban_not_allowed']; } if (loadMemberData($member) != false) { loadMemberContext($member); $context['banned_member'] =& $memberContext[$member]; } else { $context['op_errors'][] = $txt['mc_lift_topic_ban_invalid_member']; } // defaults $context['ban_data'] = array('expire' => 0, 'reason' => ''); if (isset($_REQUEST['save'])) { $context['ban_data']['expire'] = !empty($_POST['mc_expire']) ? (int) $_POST['mc_expire'] : 0; $context['ban_data']['reason'] = !empty($_POST['mc_reason']) ? htmlspecialchars($_POST['mc_reason']) : ''; } $context['ban_row'] = array(); // do not check this for admins - they can do whatever they want and even ban a moderator in his own board. Yes, admins are >> all :) if ($is_ban && !$user_info['is_admin']) { if (isUserAllowedTo('moderate_forum', 0, $member) || isUserAllowedTo('moderate_board', $board_info['id'], $member)) { $context['op_errors'][] = $txt['mc_topicban_not_bannable']; } } $request = smf_db_query('SELECT t.id_topic, ba.id_member, ba.updated, ba.reason, m.subject FROM {db_prefix}topics AS t LEFT JOIN {db_prefix}topicbans AS ba ON (ba.id_topic = t.id_topic AND ba.id_member = {int:member}) LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = t.id_first_msg) WHERE t.id_topic = {int:topic}', array('topic' => $topic, 'member' => $member)); if (mysql_num_rows($request) > 0) { $row = mysql_fetch_assoc($request); if (!empty($row['reason']) && strpos($row['reason'], '|')) { list($msg, $reason) = explode('|', $row['reason']); } else { $msg = 0; $reason = ''; } $context['ban_row'] = array('id_member' => $row['id_member'], 'id_topic' => $row['id_topic'], 'subject' => $row['subject'], 'ban_time' => timeformat($row['updated']), 'href' => URL::topic($topic, $row['subject']), 'is_banned' => $row['id_member'], 'msg' => $msg, 'reason' => $reason); if ($_REQUEST['sa'] == 'ban' && $context['ban_row']['is_banned']) { $context['op_errors'][] = $txt['mc_topicban_duplicate']; } elseif ($_REQUEST['sa'] == 'unban' && $context['ban_row']['is_banned'] == 0) { $context['op_errors'][] = $txt['mc_lift_ban_not_found']; } } else { $context['op_errors'][] = $txt['mc_lift_ban_not_found']; } mysql_free_result($request); $mid = isset($_REQUEST['mid']) ? (int) $_REQUEST['mid'] : 0; // save it $back_to_topic = URL::topic($topic, $context['ban_row']['subject'], 0, false, '.msg' . (int) $_REQUEST['mid'], '#msg' . (int) $_REQUEST['mid']); if (empty($context['op_errors'])) { if (isset($_REQUEST['save']) && $is_ban && empty($_POST['mc_reason'])) { $context['op_errors'][] = $txt['mc_topicban_missing_reason']; } if (isset($_REQUEST['save']) && empty($context['op_errors'])) { checkSession(); $context['success'] = 'Success'; $context['back_url'] = $back_to_topic; $context['back_label'] = $txt['mc_lift_ban_backtotopic']; if ($is_ban) { $ban_expire = isset($_REQUEST['mc_expire']) && !empty($_REQUEST['mc_expire']) ? (int) $_REQUEST['mc_expire'] * 86400 : 0; $ban_reason = (isset($_REQUEST['mid']) && !empty($_REQUEST['mid']) ? (int) $_REQUEST['mid'] : 0) . '|' . htmlspecialchars($_POST['mc_reason']); smf_db_insert('', '{db_prefix}topicbans', array('id_topic' => 'int', 'id_member' => 'int', 'updated' => 'int', 'expires' => 'int', 'reason' => 'string-255'), array($topic, $member, $context['time_now'], $ban_expire ? $context['time_now'] + $ban_expire : 0, $ban_reason), array('id')); } else { smf_db_query('DELETE FROM {db_prefix}topicbans WHERE id_topic = {int:topic} AND id_member = {int:member}', array('topic' => $topic, 'member' => $member)); } } else { $context['submit_url'] = URL::parse('?action=moderate;area=topicbans;sa=' . ($is_ban ? 'ban' : 'unban') . ';topic=' . $topic . ';m=' . $member . ';save' . ';mid=' . $mid); $context['back_url'] = $back_to_topic; $context['back_label'] = $txt['mc_lift_ban_backtotopic']; $context['submit_label'] = $is_ban ? $txt['mc_issue_ban'] : $txt['mc_lift_ban']; $context['topicban_message'] = $is_ban ? sprintf($txt['mc_topicban_message'], $context['banned_member']['link'], $context['ban_row']['href'], $context['ban_row']['subject']) : sprintf($txt['mc_lift_ban_message'], $context['banned_member']['link'], $context['ban_row']['href'], $context['ban_row']['subject'], $context['ban_row']['ban_time']); $context['submit'] = true; $context['is_ban'] = $is_ban; } } else { $context['back_url'] = $back_to_topic; $context['back_label'] = $txt['mc_lift_ban_backtotopic']; } } else { global $user_info, $context; $boards = array(); if ($user_info['is_admin'] || allowedTo('moderate_forum')) { // admins and global moderator can see all topic bans $board_query = '1=1'; } else { $boards = boardsAllowedTo('moderate_board'); if (empty($boards)) { fatal_lang_error('no_access', true); } // we cannot moderate any board, so we have no business in being here $board_query = 'b.id_board IN ({array_int:boards})'; } $member = isset($_REQUEST['m']) ? (int) $_REQUEST['m'] : 0; $topic = isset($_REQUEST['t']) ? (int) $_REQUEST['t'] : 0; $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; $mode = isset($_REQUEST['sa']) ? $_REQUEST['sa'] : 'all'; $perpage = 25; if ($mode !== 'bymember' && $mode !== 'bytopic' && $mode !== 'all') { $mode = 'all'; } $base_query = '1=1'; if ($mode === 'bymember') { $base_query = $member ? 'ba.id_member = {int:member}' : $base_query; } else { $base_query = $topic ? 'ba.id_topic = {int:topic}' : $base_query; } EoS_Smarty::getConfigInstance()->registerHookTemplate('modcenter_content_area', 'modcenter/topicbans_list'); $context['page_title'] = $txt['mc_topicbans_view']; $context[$context['moderation_menu_name']]['tab_data'] = array('title' => $txt['mc_topicbans_view'], 'description' => $txt['mc_topicbans_view_desc']); $context['topicban_view_desc'] = $txt['mc_view_topicbans_all']; if ($mode === 'bytopic' && $topic == 0) { $context['error'] = $txt['mc_topicbans_notopic']; return; } else { if ($mode === 'bymember' && $member == 0) { $context['error'] = $txt['mc_topicbans_nomember']; return; } } $request = smf_db_query('SELECT COUNT(ba.id_topic) FROM {db_prefix}topicbans AS ba LEFT JOIN {db_prefix}topics AS t ON(t.id_topic = ba.id_topic) LEFT JOIN {db_prefix}boards AS b ON(b.id_board = t.id_board) WHERE ' . $base_query . ' AND ' . $board_query, array('member' => $member, 'topic' => $topic, 'boards' => $boards)); list($context['total_items']) = mysql_fetch_row($request); mysql_free_result($request); $pages_base = URL::parse('?action=moderate;area=topicbans;sa=' . $mode); $pages_base = URL::addParam($pages_base, 'start=%1$d', true); $context['pages'] = $context['total_items'] ? constructPageIndex($pages_base, $start, $context['total_items'], $perpage, true) : ''; $request = smf_db_query('SELECT ba.*, mem.real_name, m.subject FROM {db_prefix}topicbans AS ba LEFT JOIN {db_prefix}topics AS t ON(t.id_topic = ba.id_topic) LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = ba.id_member) LEFT JOIN {db_prefix}messages AS m ON(m.id_msg = t.id_first_msg) LEFT JOIN {db_prefix}boards AS b ON(b.id_board = t.id_board) WHERE ' . $base_query . ' AND ' . $board_query . ' LIMIT {int:start}, {int:perpage}', array('member' => $member, 'topic' => $topic, 'boards' => $boards, 'start' => $start, 'perpage' => $perpage)); $desc_done = 0; while ($row = mysql_fetch_assoc($request)) { if (!$desc_done) { switch ($mode) { case 'bymember': $link = '<a href="' . URL::user($member, $row['real_name']) . '" onclick="getMcard(' . $member . ');return(false)">' . $row['real_name'] . '</a>'; $context['topicban_view_desc'] = sprintf($txt['mc_view_topicbans_bymember'], $link); break; case 'bytopic': $link = '<a href="' . URL::topic($topic, $row['subject'], 0, false) . '">' . $row['subject'] . '</a>'; $context['topicban_view_desc'] = sprintf($txt['mc_view_topicbans_bytopic'], $link); break; } $desc_done = true; } $m_href = URL::user($row['id_member'], $row['real_name']); $t_href = URL::topic($row['id_topic'], $row['subject'], 0, false); if (!empty($row['reason']) && strpos($row['reason'], '|')) { list($msg, $reason) = explode('|', $row['reason']); } else { $reason = ''; } $timediff = $row['expires'] - $context['time_now']; $context['topicbans'][] = array('id' => $row['id'], 'id_member' => $row['id_member'], 'member' => array('id' => $row['id_member'], 'name' => $row['real_name'], 'href' => $m_href, 'link' => '<a href="' . $m_href . '" onclick="getMcard(' . $row['id_member'] . ');return(false)">' . $row['real_name'] . '</a>'), 'topic' => array('href' => $t_href, 'subject' => $row['subject'], 'id' => $row['id_topic'], 'link' => '<a href="' . $t_href . '">' . $row['subject'] . '</a>'), 'reason' => $txt['mc_topicban_reason'] . ': ' . $reason . ' (<a href="' . URL::parse('?msg=' . trim($msg) . ';perma') . '">' . $txt['mc_topicban_reason_see'] . '</a>)', 'issue_time' => timeformat($row['updated']), 'expires' => empty($row['expires']) ? $txt['mc_topicban_is_perma'] : ($timediff > 0 ? (int) ($timediff / 3600) . ' ' . $txt['mc_topicban_hours_left'] : $txt['mc_topicban_expires'])); } mysql_free_result($request); } }
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] : ''); } }
function showPermissions($memID) { global $txt, $board; global $user_profile, $context, $sourcedir, $backend_subdir; // Verify if the user has sufficient permissions. isAllowedTo('manage_permissions'); loadLanguage('ManagePermissions'); loadLanguage('Admin'); //loadAdminTemplate('ManageMembers'); EoS_Smarty::loadTemplate('profile/profile_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_content_area', 'profile/permissions'); // Load all the permission profiles. require_once $sourcedir . '/' . $backend_subdir . '/ManagePermissions.php'; loadPermissionProfiles(); $context['member']['id'] = $memID; $context['member']['name'] = $user_profile[$memID]['real_name']; $context['page_title'] = $txt['showPermissions']; $board = empty($board) ? 0 : (int) $board; $context['board'] = $board; // Determine which groups this user is in. if (empty($user_profile[$memID]['additional_groups'])) { $curGroups = array(); } else { $curGroups = explode(',', $user_profile[$memID]['additional_groups']); } $curGroups[] = $user_profile[$memID]['id_group']; $curGroups[] = $user_profile[$memID]['id_post_group']; // Load a list of boards for the jump box - except the defaults. $request = smf_db_query(' SELECT b.id_board, b.name, b.id_profile, b.member_groups, IFNULL(mods.id_member, 0) AS is_mod FROM {db_prefix}boards AS b LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = b.id_board AND mods.id_member = {int:current_member}) WHERE {query_see_board}', array('current_member' => $memID)); $context['boards'] = array(); $context['no_access_boards'] = array(); while ($row = mysql_fetch_assoc($request)) { if (count(array_intersect($curGroups, explode(',', $row['member_groups']))) === 0 && !$row['is_mod']) { $context['no_access_boards'][] = array('id' => $row['id_board'], 'name' => $row['name'], 'is_last' => false); } elseif ($row['id_profile'] != 1 || $row['is_mod']) { $context['boards'][$row['id_board']] = array('id' => $row['id_board'], 'name' => $row['name'], 'selected' => $board == $row['id_board'], 'profile' => $row['id_profile'], 'profile_name' => $context['profiles'][$row['id_profile']]['name']); } } mysql_free_result($request); if (!empty($context['no_access_boards'])) { $context['no_access_boards'][count($context['no_access_boards']) - 1]['is_last'] = true; } $context['member']['permissions'] = array('general' => array(), 'board' => array()); // If you're an admin we know you can do everything, we might as well leave. $context['member']['has_all_permissions'] = in_array(1, $curGroups); if ($context['member']['has_all_permissions']) { return; } $denied = array(); // Get all general permissions. $result = smf_db_query(' SELECT p.permission, p.add_deny, mg.group_name, p.id_group FROM {db_prefix}permissions AS p LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = p.id_group) WHERE p.id_group IN ({array_int:group_list}) ORDER BY p.add_deny DESC, p.permission, mg.min_posts, CASE WHEN mg.id_group < {int:newbie_group} THEN mg.id_group ELSE 4 END, mg.group_name', array('group_list' => $curGroups, 'newbie_group' => 4)); while ($row = mysql_fetch_assoc($result)) { // We don't know about this permission, it doesn't exist :P. if (!isset($txt['permissionname_' . $row['permission']])) { continue; } if (empty($row['add_deny'])) { $denied[] = $row['permission']; } // Permissions that end with _own or _any consist of two parts. if (in_array(substr($row['permission'], -4), array('_own', '_any')) && isset($txt['permissionname_' . substr($row['permission'], 0, -4)])) { $name = $txt['permissionname_' . substr($row['permission'], 0, -4)] . ' - ' . $txt['permissionname_' . $row['permission']]; } else { $name = $txt['permissionname_' . $row['permission']]; } // Add this permission if it doesn't exist yet. if (!isset($context['member']['permissions']['general'][$row['permission']])) { $context['member']['permissions']['general'][$row['permission']] = array('id' => $row['permission'], 'groups' => array('allowed' => array(), 'denied' => array()), 'name' => $name, 'is_denied' => false, 'is_global' => true); } // Add the membergroup to either the denied or the allowed groups. $context['member']['permissions']['general'][$row['permission']]['groups'][empty($row['add_deny']) ? 'denied' : 'allowed'][] = $row['id_group'] == 0 ? $txt['membergroups_members'] : $row['group_name']; // Once denied is always denied. $context['member']['permissions']['general'][$row['permission']]['is_denied'] |= empty($row['add_deny']); } mysql_free_result($result); $request = smf_db_query(' SELECT bp.add_deny, bp.permission, bp.id_group, mg.group_name' . (empty($board) ? '' : ', b.id_profile, CASE WHEN mods.id_member IS NULL THEN 0 ELSE 1 END AS is_moderator') . ' FROM {db_prefix}board_permissions AS bp' . (empty($board) ? '' : ' INNER JOIN {db_prefix}boards AS b ON (b.id_board = {int:current_board}) LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = b.id_board AND mods.id_member = {int:current_member})') . ' LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = bp.id_group) WHERE bp.id_profile = {raw:current_profile} AND bp.id_group IN ({array_int:group_list}' . (empty($board) ? ')' : ', {int:moderator_group}) AND (mods.id_member IS NOT NULL OR bp.id_group != {int:moderator_group})'), array('current_board' => $board, 'group_list' => $curGroups, 'current_member' => $memID, 'current_profile' => empty($board) ? '1' : 'b.id_profile', 'moderator_group' => 3)); while ($row = mysql_fetch_assoc($request)) { // We don't know about this permission, it doesn't exist :P. if (!isset($txt['permissionname_' . $row['permission']])) { continue; } // The name of the permission using the format 'permission name' - 'own/any topic/event/etc.'. if (in_array(substr($row['permission'], -4), array('_own', '_any')) && isset($txt['permissionname_' . substr($row['permission'], 0, -4)])) { $name = $txt['permissionname_' . substr($row['permission'], 0, -4)] . ' - ' . $txt['permissionname_' . $row['permission']]; } else { $name = $txt['permissionname_' . $row['permission']]; } // Create the structure for this permission. if (!isset($context['member']['permissions']['board'][$row['permission']])) { $context['member']['permissions']['board'][$row['permission']] = array('id' => $row['permission'], 'groups' => array('allowed' => array(), 'denied' => array()), 'name' => $name, 'is_denied' => false, 'is_global' => empty($board)); } $context['member']['permissions']['board'][$row['permission']]['groups'][empty($row['add_deny']) ? 'denied' : 'allowed'][$row['id_group']] = $row['id_group'] == 0 ? $txt['membergroups_members'] : $row['group_name']; $context['member']['permissions']['board'][$row['permission']]['is_denied'] |= empty($row['add_deny']); } mysql_free_result($request); }
function deleteAccount($memID) { global $txt, $context, $user_info, $modSettings, $cur_profile, $smcFunc; if (!$context['user']['is_owner']) { isAllowedTo('profile_remove_any'); } elseif (!allowedTo('profile_remove_any')) { isAllowedTo('profile_remove_own'); } // Permissions for removing stuff... $context['can_delete_posts'] = !$context['user']['is_owner'] && allowedTo('moderate_forum'); // Can they do this, or will they need approval? $context['needs_approval'] = $context['user']['is_owner'] && !empty($modSettings['approveAccountDeletion']) && !allowedTo('moderate_forum'); $context['page_title'] = $txt['deleteAccount'] . ': ' . $cur_profile['real_name']; EoS_Smarty::loadTemplate('profile/profile_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_content_area', 'profile/delete_account'); }
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('"' => '"')); $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']))); }
function ReportToModerator() { global $txt, $topic, $sourcedir, $modSettings, $user_info, $context, $smcFunc; $context['robot_no_index'] = true; // You can't use this if it's off or you are not allowed to do it. isAllowedTo('report_any'); // If they're posting, it should be processed by ReportToModerator2. if ((isset($_POST[$context['session_var']]) || isset($_POST['submit'])) && empty($context['post_errors'])) { ReportToModerator2(); } // We need a message ID to check! if (empty($_REQUEST['msg']) && empty($_REQUEST['mid'])) { fatal_lang_error('no_access', false); } // For compatibility, accept mid, but we should be using msg. (not the flavor kind!) $_REQUEST['msg'] = empty($_REQUEST['msg']) ? (int) $_REQUEST['mid'] : (int) $_REQUEST['msg']; // Check the message's ID - don't want anyone reporting a post they can't even see! $result = smf_db_query(' SELECT m.id_msg, m.id_member, t.id_member_started FROM {db_prefix}messages AS m INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic}) WHERE m.id_msg = {int:id_msg} AND m.id_topic = {int:current_topic} LIMIT 1', array('current_topic' => $topic, 'id_msg' => $_REQUEST['msg'])); if (mysql_num_rows($result) == 0) { fatal_lang_error('no_board', false); } list($_REQUEST['msg'], $member, $starter) = mysql_fetch_row($result); mysql_free_result($result); // Do we need to show the visual verification image? $context['require_verification'] = $user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha']); if ($context['require_verification']) { require_once $sourcedir . '/lib/Subs-Editor.php'; $verificationOptions = array('id' => 'report'); $context['require_verification'] = create_control_verification($verificationOptions); $context['visual_verification_id'] = $verificationOptions['id']; } // Show the inputs for the comment, etc. loadLanguage('Post'); EoS_Smarty::loadTemplate('topic/send_or_report'); EoS_Smarty::getConfigInstance()->registerHookTemplate('send_report_content_area', 'topic/reporttm'); $context['comment_body'] = !isset($_POST['comment']) ? '' : trim($_POST['comment']); $context['email_address'] = !isset($_POST['email']) ? '' : trim($_POST['email']); // This is here so that the user could, in theory, be redirected back to the topic. $context['start'] = $_REQUEST['start']; $context['message_id'] = $_REQUEST['msg']; $context['page_title'] = $txt['report_to_mod']; $context['sub_template'] = 'report'; }
public static function profile_summary(&$memID, &$user_profile) { global $context, $user_info, $txt; // only show this to either admins or profile owners if ($user_info['is_admin'] || $memID == $user_info['id']) { $txt['geoip_profile_summary_label'] = 'GeoIP location info:'; $context['region_info'] = self::getLocationRecord($user_profile[$memID]['member_ip']); EoS_Smarty::addTemplateDir(dirname(__FILE__)); EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_summary_extend_basic', 'geoip_profile_summary'); } }
function Login2() { global $txt, $scripturl, $user_info, $user_settings, $smcFunc; global $cookiename, $maintenance, $modSettings, $context, $sc, $sourcedir; // Load cookie authentication stuff. require_once $sourcedir . '/lib/Subs-Auth.php'; if (isset($_GET['sa']) && $_GET['sa'] == 'salt' && !$user_info['is_guest']) { if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\\{i:0;(i:\\d{1,6}|s:[1-8]:"\\d{1,8}");i:1;s:(0|40):"([a-fA-F0-9]{40})?";i:2;[id]:\\d{1,14};(i:3;i:\\d;)?\\}$~', $_COOKIE[$cookiename]) === 1) { list(, , $timeout) = @unserialize($_COOKIE[$cookiename]); } elseif (isset($_SESSION['login_' . $cookiename])) { list(, , $timeout) = @unserialize($_SESSION['login_' . $cookiename]); } else { trigger_error('Login2(): Cannot be logged in without a session or cookie', E_USER_ERROR); } $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_info['id'], array('password_salt' => $user_settings['password_salt'])); setLoginCookie($timeout - time(), $user_info['id'], sha1($user_settings['passwd'] . $user_settings['password_salt'])); redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']); } elseif (isset($_GET['sa']) && $_GET['sa'] == 'check') { // Strike! You're outta there! if ($_GET['member'] != $user_info['id']) { fatal_lang_error('login_cookie_error', false); } // Some whitelisting for login_url... if (empty($_SESSION['login_url'])) { redirectexit(); } else { // Best not to clutter the session data too much... $temp = $_SESSION['login_url']; unset($_SESSION['login_url']); redirectexit($temp); } } // Beyond this point you are assumed to be a guest trying to login. if (!$user_info['is_guest']) { redirectexit(); } // Are you guessing with a script? spamProtection('login'); // Set the login_url if it's not already set (but careful not to send us to an attachment). if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0) { $_SESSION['login_url'] = $_SESSION['old_url']; } // Been guessing a lot, haven't we? if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3) { fatal_lang_error('login_threshold_fail', 'critical'); } // Set up the cookie length. (if it's invalid, just fall through and use the default.) if (isset($_POST['cookieneverexp']) || !empty($_POST['cookielength']) && $_POST['cookielength'] == -1) { $modSettings['cookieTime'] = 3153600; } elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600)) { $modSettings['cookieTime'] = (int) $_POST['cookielength']; } loadLanguage('Login'); EoS_Smarty::loadTemplate('generic_skeleton'); EoS_Smarty::getConfigInstance()->registerHookTemplate('generic_content_area', 'loginout/login'); // Set up the default/fallback stuff. $context['default_username'] = isset($_POST['user']) ? preg_replace('~&#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_POST['user'])) : ''; $context['default_password'] = ''; $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600; $context['login_errors'] = array($txt['error_occured']); $context['page_title'] = $txt['login']; // Add the login chain to the link tree. $context['linktree'][] = array('url' => $scripturl . '?action=login', 'name' => $txt['login']); if (!empty($_POST['openid_identifier']) && !empty($modSettings['enableOpenID'])) { require_once $sourcedir . '/lib/Subs-OpenID.php'; if (($open_id = smf_openID_validate($_POST['openid_identifier'])) !== 'no_data') { return $open_id; } } // You forgot to type your username, dummy! if (!isset($_POST['user']) || $_POST['user'] == '') { $context['login_errors'] = array($txt['need_username']); return; } // Hmm... maybe 'admin' will login with no password. Uhh... NO! if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_POST['hash_passwrd']) || strlen($_POST['hash_passwrd']) != 40)) { $context['login_errors'] = array($txt['no_password']); return; } // No funky symbols either. if (preg_match('~[<>&"\'=\\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_POST['user'])) != 0) { $context['login_errors'] = array($txt['error_invalid_characters_username']); return; } // Are we using any sort of integration to validate the login? if (in_array('retry', HookAPI::callHook('integrate_validate_login', array($_POST['user'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime'])), true)) { $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; return; } // Load the data up! $request = smf_db_query(' SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri, passwd_flood FROM {db_prefix}members WHERE ' . 'member_name = {string:user_name}' . ' LIMIT 1', array('user_name' => $_POST['user'])); // Probably mistyped or their email, try it as an email address. (member_name first, though!) if (mysql_num_rows($request) == 0) { mysql_free_result($request); $request = smf_db_query(' SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri, passwd_flood FROM {db_prefix}members WHERE email_address = {string:user_name} LIMIT 1', array('user_name' => $_POST['user'])); // Let them try again, it didn't match anything... if (mysql_num_rows($request) == 0) { $context['login_errors'] = array($txt['username_no_exist']); return; } } $user_settings = mysql_fetch_assoc($request); mysql_free_result($request); // Figure out the password using SMF's encryption - if what they typed is right. if (isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40) { // Needs upgrading? if (strlen($user_settings['passwd']) != 40) { $context['login_errors'] = array($txt['login_hash_error']); $context['disable_login_hashing'] = true; unset($user_settings); return; } elseif ($_POST['hash_passwrd'] == sha1($user_settings['passwd'] . $sc)) { $sha_passwd = $user_settings['passwd']; } else { // Don't allow this! validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1; if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); $context['disable_login_hashing'] = true; $context['login_errors'] = array($txt['incorrect_password']); unset($user_settings); return; } } } else { $sha_passwd = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); } // Bad password! Thought you could fool the database?! if ($user_settings['passwd'] != $sha_passwd) { // Let's be cautious, no hacking please. thanx. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']); // Maybe we were too hasty... let's try some other authentication methods. $other_passwords = array(); // None of the below cases will be used most of the time (because the salt is normally set.) if ($user_settings['password_salt'] == '') { // YaBB SE, Discus, MD5 (used a lot), SHA-1 (used some), SMF 1.0.x, IkonBoard, and none at all. $other_passwords[] = crypt($_POST['passwrd'], substr($_POST['passwrd'], 0, 2)); $other_passwords[] = crypt($_POST['passwrd'], substr($user_settings['passwd'], 0, 2)); $other_passwords[] = md5($_POST['passwrd']); $other_passwords[] = sha1($_POST['passwrd']); $other_passwords[] = md5_hmac($_POST['passwrd'], strtolower($user_settings['member_name'])); $other_passwords[] = md5($_POST['passwrd'] . strtolower($user_settings['member_name'])); $other_passwords[] = md5(md5($_POST['passwrd'])); $other_passwords[] = $_POST['passwrd']; // This one is a strange one... MyPHP, crypt() on the MD5 hash. $other_passwords[] = crypt(md5($_POST['passwrd']), md5($_POST['passwrd'])); // Snitz style - SHA-256. Technically, this is a downgrade, but most PHP configurations don't support sha256 anyway. if (strlen($user_settings['passwd']) == 64 && function_exists('mhash') && defined('MHASH_SHA256')) { $other_passwords[] = bin2hex(mhash(MHASH_SHA256, $_POST['passwrd'])); } // phpBB3 users new hashing. We now support it as well ;). $other_passwords[] = phpBB3_password_check($_POST['passwrd'], $user_settings['passwd']); // APBoard 2 Login Method. $other_passwords[] = md5(crypt($_POST['passwrd'], 'CRYPT_MD5')); } elseif (strlen($user_settings['passwd']) == 32) { // vBulletin 3 style hashing? Let's welcome them with open arms \o/. $other_passwords[] = md5(md5($_POST['passwrd']) . $user_settings['password_salt']); // Hmm.. p'raps it's Invision 2 style? $other_passwords[] = md5(md5($user_settings['password_salt']) . md5($_POST['passwrd'])); // Some common md5 ones. $other_passwords[] = md5($user_settings['password_salt'] . $_POST['passwrd']); $other_passwords[] = md5($_POST['passwrd'] . $user_settings['password_salt']); } elseif (strlen($user_settings['passwd']) == 40) { // Maybe they are using a hash from before the password fix. $other_passwords[] = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); // BurningBoard3 style of hashing. $other_passwords[] = sha1($user_settings['password_salt'] . sha1($user_settings['password_salt'] . sha1($_POST['passwrd']))); // Perhaps we converted to UTF-8 and have a valid password being hashed differently. if ($context['character_set'] == 'utf8' && !empty($modSettings['previousCharacterSet']) && $modSettings['previousCharacterSet'] != 'utf8') { // Try iconv first, for no particular reason. if (function_exists('iconv')) { $other_passwords['iconv'] = sha1(strtolower(iconv('UTF-8', $modSettings['previousCharacterSet'], $user_settings['member_name'])) . un_htmlspecialchars(iconv('UTF-8', $modSettings['previousCharacterSet'], $_POST['passwrd']))); } // Say it aint so, iconv failed! if (empty($other_passwords['iconv']) && function_exists('mb_convert_encoding')) { $other_passwords[] = sha1(strtolower(mb_convert_encoding($user_settings['member_name'], 'UTF-8', $modSettings['previousCharacterSet'])) . un_htmlspecialchars(mb_convert_encoding($_POST['passwrd'], 'UTF-8', $modSettings['previousCharacterSet']))); } } } // SMF's sha1 function can give a funny result on Linux (Not our fault!). If we've now got the real one let the old one be valid! if (strpos(strtolower(PHP_OS), 'win') !== 0) { require_once $sourcedir . '/lib/Subs-Compat.php'; $other_passwords[] = sha1_smf(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd'])); } // Whichever encryption it was using, let's make it use SMF's now ;). if (in_array($user_settings['passwd'], $other_passwords)) { $user_settings['passwd'] = $sha_passwd; $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); // Update the password and set up the hash. updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'], 'passwd_flood' => '')); } else { // They've messed up again - keep a count to see if they need a hand. $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1; // Hmm... don't remember it, do you? Here, try the password reminder ;). if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold']) { redirectexit('action=reminder'); } else { // Log an error so we know that it didn't go well in the error log. log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user'); $context['login_errors'] = array($txt['incorrect_password']); return; } } } elseif (!empty($user_settings['passwd_flood'])) { // Let's be sure they weren't a little hacker. validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true); // If we got here then we can reset the flood counter. updateMemberData($user_settings['id_member'], array('passwd_flood' => '')); } // Correct password, but they've got no salt; fix it! if ($user_settings['password_salt'] == '') { $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4); updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt'])); } // Check their activation status. if (!checkActivation()) { return; } DoLogin(); }
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'; } }
function CoppaForm() { global $context, $modSettings, $txt; loadLanguage('Login'); EoS_Smarty::loadTemplate('register/base'); // No User ID?? if (!isset($_GET['member'])) { fatal_lang_error('no_access', false); } // Get the user details... $request = smf_db_query(' SELECT member_name FROM {db_prefix}members WHERE id_member = {int:id_member} AND is_activated = {int:is_coppa}', array('id_member' => (int) $_GET['member'], 'is_coppa' => 5)); if (mysql_num_rows($request) == 0) { fatal_lang_error('no_access', false); } list($username) = mysql_fetch_row($request); mysql_free_result($request); if (isset($_GET['form'])) { // Some simple contact stuff for the forum. $context['forum_contacts'] = (!empty($modSettings['coppaPost']) ? $modSettings['coppaPost'] . '<br /><br />' : '') . (!empty($modSettings['coppaFax']) ? $modSettings['coppaFax'] . '<br />' : ''); $context['forum_contacts'] = !empty($context['forum_contacts']) ? $context['forum_name_html_safe'] . '<br />' . $context['forum_contacts'] : ''; // Showing template? if (!isset($_GET['dl'])) { // Shortcut for producing underlines. $context['ul'] = '<u> </u>'; $context['template_layers'] = array(); EoS_Smarty::getConfigInstance()->registerHookTemplate('register_content_area', 'register/coppa_form'); $context['page_title'] = $txt['coppa_form_title']; $context['coppa_body'] = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'), array($context['ul'], $context['ul'], $username), $txt['coppa_form_body']); } else { // The data. $ul = ' '; $crlf = "\r\n"; $data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . $txt['coppa_form_body']; $data = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br>', '<br />'), array($ul, $ul, $username, $crlf, $crlf), $data); // Send the headers. header('Connection: close'); header('Content-Disposition: attachment; filename="approval.txt"'); header('Content-Type: ' . ($context['browser']['is_ie'] || $context['browser']['is_opera'] ? 'application/octetstream' : 'application/octet-stream')); header('Content-Length: ' . count($data)); echo $data; obExit(false); } } else { $context += array('page_title' => $txt['coppa_title']); EoS_Smarty::getConfigInstance()->registerHookTemplate('register_content_area', 'register/coppa_info'); $context['coppa'] = array('body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], $txt['coppa_after_registration']), 'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']), 'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'], 'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'], 'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']), 'id' => $_GET['member']); } }
/** * @param $memID int member's ID * * grab a list of news items that were dismissed previously. Dismissed news item ids are * stored in the member's meta array. * * TODO: implement paging(?) - are we ever going to have that many board notices? */ function profileManageBoardNews($memID) { global $context, $user_info, $scripturl, $txt; EoS_Smarty::loadTemplate('profile/profile_base'); EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_content_area', 'profile/manage_news'); $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; if (isset($_REQUEST['sa']) && $_REQUEST['sa'] === 'reactivateall' && $user_info['id'] == $memID) { unset($user_info['meta']['dismissed_news_items']); updateMemberData($memID, array('meta' => @serialize($user_info['meta']))); redirectexit('action=profile;area=boardnews;u=' . $memID); } $context['items_per_page'] = commonAPI::getMessagesPerPage(); $context['dismissed_items'] = array(); if (!isset($user_info['meta']['dismissed_news_items'])) { $user_info['meta']['dismissed_news_items'] = array(); } if (count($user_info['meta']['dismissed_news_items'])) { $request = smf_db_query('SELECT * FROM {db_prefix}news WHERE id_news IN({array_int:ids}) LIMIT {int:start}, {int:perpage}', array('ids' => $user_info['meta']['dismissed_news_items'], 'start' => $start, 'perpage' => $context['items_per_page'])); while ($row = mysql_fetch_assoc($request)) { $groups_allowed = explode(',', $row['groups']); if (!empty($groups_allowed[0]) && !in_array($user_info['groups'], $groups_allowed)) { continue; } $context['dismissed_items'][$row['id_news']] = array('id' => $row['id_news'], 'teaser' => !empty($row['teaser']) ? parse_bbc($row['teaser']) : '', 'body' => parse_bbc($row['body']), 'groups' => explode(',', $row['groups']), 'on_index' => $row['on_index'] ? true : false, 'can_dismiss' => $row['can_dismiss'], 'topics' => explode(',', $row['topics']), 'boards' => explode(',', $row['boards'])); } mysql_free_result($request); } $context['have_items'] = count($context['dismissed_items']); $context['reactivate_link'] = $context['have_items'] ? '<a class="active" href="' . $scripturl . '?action=profile;area=boardnews;sa=reactivateall;u=' . $memID . '">' . $txt['news_items_reactivate'] . '</a>' : ''; }
/** * @param $memID int id_member * * fetch all likes received by the given user and display them * part of the profile -> show content area. */ function LikesByUser($memID) { global $context, $user_info, $scripturl, $memberContext, $txt, $modSettings, $options; if ($memID != $user_info['id']) { isAllowedTo('can_view_ratings'); } // let us use the same value as for topics per page here. $perpage = empty($modSettings['disableCustomPerPage']) && !empty($options['topics_per_page']) ? $options['topics_per_page'] : $modSettings['defaultMaxTopics']; $out = $_GET['sa'] === 'likesout'; // display likes *given* instead of received ones $is_owner = $user_info['id'] == $memID; // we are the owner of this profile, this is important for proper formatting (you/yours etc.) $boards_like_see = boardsAllowedTo('like_see'); // respect permissions $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; if (!($user_info['is_admin'] || allowedTo('moderate_forum'))) { // admins and global mods can see everything $bq = ' AND b.id_board IN({array_int:boards})'; } else { $bq = ''; } $q = $out ? 'l.id_user = {int:id_user}' : 'l.id_receiver = {int:id_user}'; $request = smf_db_query('SELECT count(l.id_msg) FROM {db_prefix}likes AS l INNER JOIN {db_prefix}messages AS m ON (m.id_msg = l.id_msg) INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE ' . $q . ' AND {query_see_board}' . $bq, array('id_user' => $memID, 'boards' => $boards_like_see)); list($context['total_likes']) = mysql_fetch_row($request); mysql_free_result($request); $request = smf_db_query('SELECT m.subject, m.id_topic, l.id_user, l.id_receiver, l.updated, l.id_msg, l.rtype, mfirst.subject AS first_subject, SUBSTRING(m.body, 1, 150) AS body FROM {db_prefix}likes AS l INNER JOIN {db_prefix}messages AS m ON (m.id_msg = l.id_msg) INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic) INNER JOIN {db_prefix}messages AS mfirst ON (mfirst.id_msg = t.id_first_msg) INNER JOIN {db_prefix}boards AS b ON (b.id_board = t.id_board) WHERE ' . $q . ' AND {query_see_board} ' . $bq . ' ORDER BY l.id_like DESC LIMIT {int:startwith}, {int:perpage}', array('id_user' => $memID, 'startwith' => $start, 'perpage' => $perpage, 'boards' => $boards_like_see)); $context['results_count'] = 0; $context['likes'] = array(); $context['displaymode'] = $out ? true : false; $context['pages'] = ''; if ($context['total_likes'] > $perpage) { $context['pages'] = constructPageIndex($scripturl . '?action=profile;area=showposts;sa=' . $_GET['sa'] . ';u=' . trim($memID), $start, $context['total_likes'], $perpage); } $users = array(); while ($row = mysql_fetch_assoc($request)) { $context['results_count']++; $thref = URL::topic($row['id_topic'], $row['first_subject'], 0); $phref = URL::topic($row['id_topic'], $row['subject'], 0, false, '.msg' . $row['id_msg'], '#msg' . $row['id_msg']); $users[] = $out ? $row['id_receiver'] : $row['id_user']; $context['likes'][] = array('id_user' => $out ? $row['id_receiver'] : $row['id_user'], 'time' => timeformat($row['updated']), 'topic' => array('href' => $thref, 'link' => '<a href="' . $thref . '">' . $row['first_subject'] . '</a>', 'subject' => $row['first_subject']), 'post' => array('href' => $phref, 'link' => '<a href="' . $phref . '">' . $row['subject'] . '</a>', 'subject' => $row['subject'], 'id' => $row['id_msg']), 'rtype' => $row['rtype'], 'teaser' => strip_tags(preg_replace('~[[\\/\\!]*?[^\\[\\]]*?]~si', '', $row['body'])) . '...', 'morelink' => URL::parse('?msg=' . $row['id_msg'] . ';perma')); } loadMemberData(array_unique($users)); foreach ($context['likes'] as &$like) { loadMemberContext($like['id_user']); $like['member'] =& $memberContext[$like['id_user']]; $like['text'] = $out ? $is_owner ? sprintf($txt['liked_a_post'], $is_owner ? $txt['you_liker'] : $memberContext[$memID]['name'], $memberContext[$like['id_user']]['link'], $like['post']['href'], $like['topic']['link'], $modSettings['ratings'][$like['rtype']]['text']) : sprintf($txt['liked_a_post'], $is_owner ? $txt['you_liker'] : $memberContext[$memID]['name'], $memberContext[$like['id_user']]['link'], $like['post']['href'], $like['topic']['link'], $modSettings['ratings'][$like['rtype']]['text']) : ($is_owner ? sprintf($txt['liked_your_post'], $like['id_user'] == $user_info['id'] ? $txt['you_liker'] : $like['member']['link'], $like['post']['href'], $like['topic']['link'], $modSettings['ratings'][$like['rtype']]['text']) : sprintf($txt['liked_a_post'], $like['id_user'] == $user_info['id'] ? $txt['you_liker'] : $like['member']['link'], $memberContext[$memID]['name'], $like['post']['href'], $like['topic']['link'], $modSettings['ratings'][$like['rtype']]['text'])); } mysql_free_result($request); EoS_Smarty::getConfigInstance()->registerHookTemplate('profile_content_area', 'ratings/profile_display'); }
public static function messageindex(&$board_info) { global $context, $txt, $sourcedir, $user_info; loadLanguage('Activities'); // add our plugin directory to the list of directories to search for templates. EoS_Smarty::addTemplateDir(dirname(__FILE__)); // register two hook templates for the side bar top and bottom areas EoS_Smarty::getConfigInstance()->registerHookTemplate('sidebar_top', 'testplugin_sidebar_top'); EoS_Smarty::getConfigInstance()->registerHookTemplate('sidebar_bottom', 'testplugin_sidebar_bottom'); // register some global variable (that's optional though, it would be totally ok to use $context) // You should always assignByRef(), because it's faster and doesn't create a copy // of the variable EoS_Smarty::getSmartyInstance()->assignByRef('MYDATA', self::$mydata); // enable side bar in the message index display if ($user_info['is_admin'] && $board_info['allow_topics']) { $context['show_sidebar'] = true; $context['sidebar_template'] = 'sidebars/sidebar_on_messageindex.tpl'; $context['sidebar_class'] = 'messageindex'; GetSidebarVisibility('messageindex'); } else { $context['show_sidebar'] = false; } $ignoreusers = !empty($user_info['ignoreusers']) ? $user_info['ignoreusers'] : array(0); // .. and set the name of the template self::$mydata['testvalue'] = 'Foo'; @(require_once $sourcedir . '/lib/Subs-Activities.php'); $context['act_global'] = false; $request = smf_db_query('SELECT a.*, t.*, b.name AS board_name FROM {db_prefix}log_activities AS a LEFT JOIN {db_prefix}activity_types AS t ON (t.id_type = a.id_type) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = a.id_board) WHERE a.id_board = {int:id_board} AND a.id_member NOT IN({array_int:ignoredusers}) ORDER BY a.id_act DESC LIMIT 5', array('id_board' => $context['current_board'], 'ignoredusers' => $ignoreusers)); aStreamOutput($request, false, true); /* if(isset($context['activities'])) { usort($context['activities'], function($a, $b) { if ($a['updated'] == $b['updated']) return 0; return ($a['updated'] < $b['updated']) ? -1 : 1; }); }*/ $request = smf_db_query('SELECT m.* FROM {db_prefix}messages AS m WHERE m.id_board = {int:id_board} AND m.id_member NOT IN ({array_int:ignoredusers}) ORDER BY m.id_msg DESC LIMIT 10', array('id_board' => $context['current_board'], 'ignoredusers' => $ignoreusers)); mysql_free_result($request); }