// we should not redirect to the listpage for moderators. // Else a moderator can never read an unapproved message. if (isset($PHORUM["postingargs"]["as_include"])) { if ($PHORUM["DATA"]["MODERATOR"]) { $PHORUM["DATA"]["OKMSG"] = $PHORUM["DATA"]["LANG"]["UnapprovedMessage"]; return; } } // In other cases, redirect users that are replying to // unapproved messages to the message list. phorum_api_redirect(PHORUM_LIST_URL); } // closed topic, show a message if ($top_parent["closed"]) { $PHORUM["DATA"]["OKMSG"] = $PHORUM["DATA"]["LANG"]["ThreadClosed"]; $PHORUM["posting_template"] = "message"; return; } } // Do permission checks for editing messages. if ($mode == "edit") { // Check if the user is allowed to edit this post. $timelim = $PHORUM["user_edit_timelimit"]; $useredit = $message["user_id"] == $PHORUM["user"]["user_id"] && phorum_api_user_check_access(PHORUM_USER_ALLOW_EDIT) && !empty($top_parent) && !$top_parent["closed"] && (!$timelim || $message["datestamp"] + $timelim * 60 >= time()); // Moderators are allowed to edit messages. $moderatoredit = $PHORUM["DATA"]["MODERATOR"] && $message["forum_id"] == $PHORUM["forum_id"]; if (!$useredit && !$moderatoredit) { $PHORUM["DATA"]["ERROR"] = $PHORUM["DATA"]["LANG"]["EditPostForbidden"]; return; } }
/** * This function can be used to build a tree structure for the available * folders and forums. * * @param mixed $vroot * The vroot for which to build the forums tree (0 (zero) to * use the main root folder) or NULL to use the current (v)root. * * @param int $flags * If the {@link PHORUM_FLAG_INCLUDE_INACTIVE} flag is set, then * inactive forums and folders will be included in the tree. * If the {@link PHORUM_FLAG_INCLUDE_EMPTY_FOLDERS} flag is set, then * empty folders will be included in the tree. By default, empty folders * will be taken out of the tree. * * @return array * An array containing arrays that describe nodes in the tree. * The nodes are in the order in which they would appear in an expanded * tree, moving from top to bottom. An "indent" field is added to each * node array to tell at what indention level the node lives. */ function phorum_api_forums_tree($vroot = NULL, $flags = 0) { global $PHORUM; if ($vroot === NULL) { $vroot = isset($PHORUM['vroot']) ? $PHORUM['vroot'] : 0; } else { settype($vroot, 'int'); } // Get the information for the root. $root = phorum_api_forums_by_forum_id($vroot, $flags); if (!$root) { trigger_error("phorum_api_forums_tree(): vroot {$vroot} does not exist", E_USER_ERROR); return NULL; } if ($root['vroot'] != $root['forum_id']) { trigger_error("phorum_api_forums_tree(): vroot {$vroot} is not a vroot folder", E_USER_ERROR); return NULL; } // Temporarily witch to the vroot for which we are building a tree. $orig_vroot = isset($PHORUM['vroot']) ? $PHORUM['vroot'] : 0; $PHORUM['vroot'] = $vroot; // Check what forums the current user can read in that vroot. $allowed_forums = phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, PHORUM_ACCESS_LIST); // Load the data for those forums. $forums = phorum_api_forums_by_forum_id($allowed_forums, $flags); // Sort the forums in a tree structure. // First pass: build a parent / child relationship structure. $tmp_forums = array(); foreach ($forums as $forum_id => $forum) { $tmp_forums[$forum_id]['forum_id'] = $forum_id; $tmp_forums[$forum_id]['parent'] = $forum['parent_id']; if (empty($forums[$forum["parent_id"]]["childcount"])) { $tmp_forums[$forum["parent_id"]]["children"] = array($forum_id); $forums[$forum["parent_id"]]["childcount"] = 1; } else { $tmp_forums[$forum["parent_id"]]["children"][] = $forum_id; $forums[$forum["parent_id"]]["childcount"]++; } } // Second pass: sort the folders and forums in their tree order. $order = array(); $stack = array(); $seen = array(); $curr_id = $vroot; while (count($tmp_forums)) { // Add the current element to the tree order array. Do not add it // in case we've already seen it (we move down and back up the tree // during processing, so we could see an element twice // while doing that). if ($curr_id != 0 && empty($seen[$curr_id])) { $order[$curr_id] = $forums[$curr_id]; $seen[$curr_id] = true; } // Push the current element on the tree walking stack // to move down the tree. array_push($stack, $curr_id); // Get the current element's data. $data = $tmp_forums[$curr_id]; // If there are no children (anymore), then move back up the the tree. if (empty($data["children"])) { unset($tmp_forums[$curr_id]); array_pop($stack); $curr_id = array_pop($stack); } else { $curr_id = array_shift($tmp_forums[$curr_id]["children"]); } if (!is_numeric($curr_id)) { break; } } $tree = array(); foreach ($order as $forum) { if ($forum["folder_flag"]) { // Skip empty folders, if we didn't request them if (empty($forums[$forum['forum_id']]['childcount']) && !($flags & PHORUM_FLAG_INCLUDE_EMPTY_FOLDERS)) { continue; } $url = phorum_api_url(PHORUM_INDEX_URL, $forum["forum_id"]); } else { $url = phorum_api_url(PHORUM_LIST_URL, $forum["forum_id"]); } // Add the indent level for the node. $indent = count($forum["forum_path"]) - 2; if ($indent < 0) { $indent = 0; } $forum['indent'] = $indent; // Some entries that are added to the forum array to be backward // compatible with the deprecated phorum_build_forum_list() function. $forum['stripped_name'] = strip_tags($forum['name']); $forum['indent_spaces'] = str_repeat(' ', $indent); $forum['url'] = $url; $forum['path'] = $forum['forum_path']; $tree[$forum["forum_id"]] = $forum; } return $tree; }
} // Loop over all the folders (flat view sections) that we will show and get // their child forums and folders. foreach ($folders as $folder_id => $dummy) { // These folders are level zero folders. To the child forums and folders, // level 1 will be assigned. The level value can be used in the template // to see where a new top level folder starts. $forums[$folder_id]['level'] = 0; // Retrieve the children for the current folder. For the (v)root folder, // we only retrieve the contained forums, since its folders will be shown // as separate sections in the flat index view instead. $children = phorum_api_forums_get(NULL, $folder_id, NULL, $PHORUM['vroot'], $PHORUM['vroot'] == $folder_id ? PHORUM_FLAG_FORUMS : 0); foreach ($children as $child_forum_id => $child_forum) { // If inaccessible forums should be hidden on the index, then check // if the current user has rights to access the current forum. if (!$child_forum['folder_flag'] && $PHORUM['hide_forums'] && !phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, $child_forum_id)) { continue; } // These are level one forums and folders. $child_forum['level'] = 1; // Remember the data. $forums[$child_forum_id] = $child_forum; // Add the forum or folder to the child list for the current folder. $folders[$folder_id][$child_forum_id] = $child_forum_id; } } // -------------------------------------------------------------------- // Setup the template data and display the template // -------------------------------------------------------------------- // Format the data for the forums and folders that we gathered. $forums = phorum_api_format_forums($forums, PHORUM_FLAG_ADD_UNREAD_INFO);
function phorum_build_forum_list() { $PHORUM = $GLOBALS["PHORUM"]; // Check what forums the current user can read. $allowed_forums = phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, PHORUM_ACCESS_LIST); $forum_picker = array(); // build forum drop down data require_once './include/api/forums.php'; $forums = phorum_api_forums_get($allowed_forums); foreach ($forums as $forum) { $tmp_forums[$forum["forum_id"]]["forum_id"] = $forum["forum_id"]; $tmp_forums[$forum["forum_id"]]["parent"] = $forum["parent_id"]; $tmp_forums[$forum["parent_id"]]["children"][] = $forum["forum_id"]; if (empty($forums[$forum["parent_id"]]["childcount"])) { $forums[$forum["parent_id"]]["childcount"] = 1; } else { $forums[$forum["parent_id"]]["childcount"]++; } } $order = array(); $stack = array(); $curr_id = $PHORUM['vroot']; while (count($tmp_forums)) { if (empty($seen[$curr_id])) { if ($curr_id != $PHORUM['vroot']) { if ($forums[$curr_id]["active"]) { $order[$curr_id] = $forums[$curr_id]; } $seen[$curr_id] = true; } } array_unshift($stack, $curr_id); $data = $tmp_forums[$curr_id]; if (isset($data["children"])) { if (count($data["children"])) { $curr_id = array_shift($tmp_forums[$curr_id]["children"]); } else { unset($tmp_forums[$curr_id]); array_shift($stack); $curr_id = array_shift($stack); } } else { unset($tmp_forums[$curr_id]); array_shift($stack); $curr_id = array_shift($stack); } if (!is_numeric($curr_id)) { break; } } foreach ($order as $forum) { if ($forum["folder_flag"]) { // Skip empty folders. if (empty($forums[$forum['forum_id']]['childcount'])) { continue; } $url = phorum_get_url(PHORUM_INDEX_URL, $forum["forum_id"]); } else { $url = phorum_get_url(PHORUM_LIST_URL, $forum["forum_id"]); } $indent = count($forum["forum_path"]) - 2; if ($indent < 0) { $indent = 0; } $forum_picker[$forum["forum_id"]] = array("forum_id" => $forum["forum_id"], "parent_id" => $forum["parent_id"], "folder_flag" => $forum["folder_flag"], "name" => $forum["name"], "stripped_name" => strip_tags($forum["name"]), "indent" => $indent, "indent_spaces" => str_repeat(" ", $indent), "url" => $url, "path" => $forum["forum_path"]); } return $forum_picker; }
$forums = phorum_db_get_forums(0, $parent_id); $PHORUM["DATA"]["FORUMS"] = array(); $forums_shown = false; $new_checks = array(); if ($PHORUM["DATA"]["LOGGEDIN"] && !empty($forums)) { if ($PHORUM["show_new_on_index"] == 2) { $new_checks = phorum_db_newflag_check(array_keys($forums)); } elseif ($PHORUM["show_new_on_index"] == 1) { $new_counts = phorum_db_newflag_count(array_keys($forums)); } } foreach ($forums as $forum) { if ($forum["folder_flag"]) { $forum["URL"]["LIST"] = phorum_get_url(PHORUM_INDEX_URL, $forum["forum_id"]); } else { if ($PHORUM["hide_forums"] && !phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, $forum["forum_id"])) { continue; } $forum["url"] = phorum_get_url(PHORUM_LIST_URL, $forum["forum_id"]); // if there is only one forum in Phorum, redirect to it. if ($parent_id == 0 && count($forums) < 2) { phorum_redirect_by_url($forum['url']); exit; } if ($forum["message_count"] > 0) { $forum["raw_last_post"] = $forum["last_post_time"]; $forum["last_post"] = phorum_date($PHORUM["long_date_time"], $forum["last_post_time"]); } else { $forum["last_post"] = " "; } $forum["URL"]["LIST"] = phorum_get_url(PHORUM_LIST_URL, $forum["forum_id"]);
} elseif (isset($PHORUM['args']['onlyunapproved']) && !empty($PHORUM["args"]['onlyunapproved']) && is_numeric($PHORUM["args"]['onlyunapproved'])) { $showwaiting = (int) $PHORUM['args']['onlyunapproved']; } else { $showwaiting = phorum_api_user_get_setting('cc_messages_onlyunapproved'); } if (empty($showwaiting)) { $showwaiting = 0; } $PHORUM['DATA']['SELECTED'] = $moddays; $PHORUM['DATA']['SELECTED_2'] = $showwaiting ? true : false; // Store current selection for the user. phorum_api_user_save_settings(array("cc_messages_moddays" => $moddays, "cc_messages_onlyunapproved" => $showwaiting)); // some needed vars $numunapproved = 0; $oldforum = $PHORUM['forum_id']; $mod_forums = phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES, PHORUM_ACCESS_LIST); $gotforums = count($mod_forums) > 0; if ($gotforums && isset($_POST['deleteids']) && count($_POST['deleteids'])) { //print_var($_POST['deleteids']); $deleteids = $_POST['deleteids']; foreach ($deleteids as $did => $did_var) { $deleteids[$did] = (int) $did_var; } $delete_messages = phorum_db_get_message(array_keys($deleteids), 'message_id', true); //print_var($delete_messages); foreach ($deleteids as $msgthd_id => $doit) { // A hook to allow modules to implement extra or different // delete functionality. if ($doit && isset($mod_forums[$delete_messages[$msgthd_id]['forum_id']])) { $delete_handled = 0; if (isset($PHORUM["hooks"]["before_delete"])) {
/** * Retrieve the closest neighbour thread. What "neighbour" is, depends on the * float to top setting. If float to top is enabled, then the * modifystamp is used for comparison (so the time at which the last * message was posted to a thread). Otherwise, the thread id is used * (so the time at which a thread was started). * * @param integer $key * The key value of the message for which the neighbour must be returned. * The key value is either the modifystamp (if float to top is enabled) * or the thread id. * * @param string $direction * Either "older" or "newer". * * @return integer * The thread id for the requested neigbour thread or 0 (zero) if there * is no neighbour available. */ public function get_neighbour_thread($key, $direction) { global $PHORUM; settype($key, 'int'); $keyfield = $PHORUM['float_to_top'] ? 'modifystamp' : 'datestamp'; $compare = ""; $orderdir = ""; switch ($direction) { case 'newer': $compare = '>'; $orderdir = 'ASC'; break; case 'older': $compare = '<'; $orderdir = 'DESC'; break; default: trigger_error(__METHOD__ . ': Illegal direction ' . '"' . htmlspecialchars($direction) . '"', E_USER_ERROR); } // If the active Phorum user is not a moderator for the forum, then // the neighbour message should be approved. $approvedval = ''; if (!phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES)) { $approvedval = 'AND status = ' . PHORUM_STATUS_APPROVED; } // Select the neighbour from the database. $thread = $this->interact(DB_RETURN_VALUE, "SELECT thread\n FROM {$this->message_table}\n WHERE forum_id = {$PHORUM['forum_id']} AND\n parent_id = 0\n {$approvedval} AND\n {$keyfield} {$compare} {$key}\n ORDER BY {$keyfield} {$orderdir}", NULL, 0, 1); return $thread; }
// Retrieve the recent messages. $recent = $PHORUM['DB']->get_recent_messages($count, 0, $forum_id, $thread_id, $threads_only); unset($recent["users"]); // Add newflag info to the messages. if ($PHORUM["DATA"]["LOGGEDIN"]) { $type = $threads_only ? PHORUM_NEWFLAGS_BY_THREAD : PHORUM_NEWFLAGS_BY_MESSAGE; $recent = phorum_api_newflags_apply_to_messages($recent, $type); } // Format the messages. $recent = phorum_api_format_messages($recent); // Apply the list hook to the messages. if (isset($PHORUM["hooks"]["list"])) { $recent = phorum_api_hook("list", $recent); } // Retrieve information about the forums for the active user. $allowed_forums = phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, PHORUM_ACCESS_LIST); $forums = $PHORUM['DB']->get_forums($allowed_forums); foreach ($forums as $id => $forum) { $forums[$id]['url'] = phorum_get_url(PHORUM_LIST_URL, $forum['forum_id']); } // Add forum info to the messages and clean up data. foreach ($recent as $id => $message) { $recent[$id]['foruminfo'] = array('id' => $message['forum_id'], 'name' => $forums[$message['forum_id']]['name'], 'url' => $forums[$message['forum_id']]['url']); // Strip fields that the caller should not see in the return data. unset($recent[$id]['email']); unset($recent[$id]['ip']); unset($recent[$id]['meta']); unset($recent[$id]['msgid']); } // Return the results. phorum_ajax_return(array_values($recent));
$PHORUM['DATA']['URL']['CC3'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_USERINFO); $PHORUM['DATA']['URL']['CC4'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_SIGNATURE); $PHORUM['DATA']['URL']['CC5'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_MAIL); $PHORUM['DATA']['URL']['CC6'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_BOARD); $PHORUM['DATA']['URL']['CC7'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_PASSWORD); $PHORUM['DATA']['URL']['CC8'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_UNAPPROVED); $PHORUM['DATA']['URL']['CC9'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_FILES); $PHORUM['DATA']['URL']['CC10'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_USERS); $PHORUM['DATA']['URL']['CC14'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_PRIVACY); $PHORUM['DATA']['URL']['CC15'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_GROUP_MODERATION); $PHORUM['DATA']['URL']['CC16'] = phorum_get_url(PHORUM_CONTROLCENTER_URL, "panel=" . PHORUM_CC_GROUP_MEMBERSHIP); // Determine if the user files functionality is available. $PHORUM["DATA"]["MYFILES"] = $PHORUM["file_uploads"] || $PHORUM["user"]["admin"]; // Determine if the user is a moderator. $PHORUM["DATA"]["MESSAGE_MODERATOR"] = phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES, PHORUM_ACCESS_ANY); $PHORUM["DATA"]["USER_MODERATOR"] = phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_USERS, PHORUM_ACCESS_ANY); $PHORUM["DATA"]["GROUP_MODERATOR"] = phorum_api_user_check_group_access(PHORUM_USER_GROUP_MODERATOR, PHORUM_ACCESS_ANY); $PHORUM["DATA"]["MODERATOR"] = $PHORUM["DATA"]["USER_MODERATOR"] + $PHORUM["DATA"]["MESSAGE_MODERATOR"] + $PHORUM["DATA"]["GROUP_MODERATOR"] > 0; // If global email hiding is not enabled, then give the user a chance // to choose for hiding himself. $PHORUM['DATA']['SHOW_EMAIL_HIDE'] = empty($PHORUM['hide_email_addr']) ? 1 : 0; // If pm email notifications are enabled, then give the user a chance // to disable it. $PHORUM['DATA']['SHOW_PM_EMAIL_NOTIFY'] = !empty($PHORUM["allow_pm_email_notify"]); // The form action for the common form. $PHORUM["DATA"]["URL"]["ACTION"] = phorum_get_url(PHORUM_CONTROLCENTER_ACTION_URL); // fill the breadcrumbs-info $PHORUM['DATA']['BREADCRUMBS'][] = array('URL' => $PHORUM['DATA']['URL']['REGISTERPROFILE'], 'TEXT' => $PHORUM['DATA']['LANG']['MyProfile'], 'TYPE' => 'control'); $user = $PHORUM['user']; // Security messures. unset($user["password"]);
/** * This function handles preparing message data for use in the templates. * * @param array $messages * An array of messages that have to be formatted. * Each message is an array on its own, containing the message data. * * @param array $author_specs * By default, the formatting function will create author info * data, based on the fields "user_id", "author" and "email". * This will create $messages["URL"]["PROFILE"] if needed (either pointing * to a user profile for registered users or the email address of * anonymous users that left an email address in the forum) and will * do formatting on the "author" field. * * By providing extra $author_specs, this formatting can be done on * more author fields. This argument should be an array, containing * arrays with five fields: * * - the name of the field that contains a user_id * - the name of the field that contains the name of the author * - the name of the field that contains the email address * (can be NULL if none available) * - the name of the field to store the author name in * - the name of the URL field to store the profile/email link in * * For the default author field handling like described above, * this array would be: * * array("user_id", "author", "email", "author", "PROFILE"); * * @return data - The formatted messages. */ function phorum_api_format_messages($messages, $author_specs = NULL) { global $PHORUM; // Prepare author specs. if ($author_specs === NULL) { $author_specs = array(); } $author_specs[] = array("user_id", "author", "email", "author", "PROFILE"); // Prepare censoring replacements. list($censor_search, $censor_replace) = phorum_api_format_censor_compile(); // Prepare the profile URL template. This is used to prevent // having to call the phorum_api_url() function over and over again. $profile_url_template = phorum_api_url(PHORUM_PROFILE_URL, '%spec_data%'); // A special <br> tag to keep track of breaks that are added by phorum. $phorum_br = '<phorum break>'; // Apply Phorum's formatting rules to all messages. foreach ($messages as $id => $message) { // Normally, the message_id must be set, since we should be handling // message data. It might not be set however, because sometimes // the message formatting is called using some fake message data // for formatting something else than a message. if (!isset($message['message_id'])) { $messages[$id]['message_id'] = $message['message_id'] = $id; } // ----------------------------------------------------------------- // Message body // ----------------------------------------------------------------- if (isset($message['body']) && $message['body'] != '') { $body = $message["body"]; // Convert legacy <...> URLs into bare URLs. $body = preg_replace("/<(\n (?:http|https|ftp):\\/\\/\n [a-z0-9;\\/\\?:@=\\&\$\\-_\\.\\+!*'\\(\\),~%]+?\n )>/xi", "\$1", $body); // Escape special HTML characters. $escaped_body = htmlspecialchars($body, ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); // When there is a charset mismatch between the database // and the language file, then bodies might get crippled // because of the htmlspecialchars() call. Here we try to // correct this issue. It's not perfect, but we do what // we can ... if ($escaped_body == '') { if (function_exists("iconv")) { // We are gonna guess and see if we get lucky. $escaped_body = iconv("ISO-8859-1", $PHORUM["DATA"]["HCHARSET"], $body); } else { // We let htmlspecialchars use its defaults. $escaped_body = htmlspecialchars($body); } } $body = $escaped_body; // Replace newlines with $phorum_br temporarily. // This way the mods know what breaks were added by // Phorum and what breaks by the user. $body = str_replace("\n", "{$phorum_br}\n", $body); // Censor bad words in the body. if ($censor_search !== NULL) { $body = preg_replace($censor_search, $censor_replace, $body); } $messages[$id]['body'] = $body; } // ----------------------------------------------------------------- // Message subject // ----------------------------------------------------------------- // Censor bad words in the subject. if (isset($message['subject']) && $censor_search !== NULL) { $messages[$id]['subject'] = preg_replace($censor_search, $censor_replace, $message['subject']); } // Escape special HTML characters. if (isset($message['subject'])) { $messages[$id]['subject'] = htmlspecialchars($messages[$id]['subject'], ENT_COMPAT, $PHORUM['DATA']['HCHARSET']); } // ----------------------------------------------------------------- // Message author // ----------------------------------------------------------------- // Escape special HTML characters in the email address. if (isset($message['email'])) { $messages[$id]['email'] = htmlspecialchars($message['email'], ENT_COMPAT, $PHORUM['DATA']['HCHARSET']); } // Do author formatting for all provided author fields. foreach ($author_specs as $spec) { // Use "Anonymous user" as the author name if there's no author // name available for some reason. if (!isset($message[$spec[1]]) || $message[$spec[1]] == '') { $messages[$id][$spec[3]] = $PHORUM["DATA"]["LANG"]["AnonymousUser"]; } elseif (!empty($message[$spec[0]])) { $url = str_replace('%spec_data%', $message[$spec[0]], $profile_url_template); $messages[$id]["URL"][$spec[4]] = $url; $messages[$id][$spec[3]] = empty($PHORUM["custom_display_name"]) ? htmlspecialchars($message[$spec[1]], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]) : $message[$spec[1]]; } elseif ($spec[2] !== NULL && !empty($message[$spec[2]]) && (empty($PHORUM['hide_email_addr']) || !empty($PHORUM["user"]["admin"]) || phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES) && PHORUM_MOD_EMAIL_VIEW || phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_USERS) && PHORUM_MOD_EMAIL_VIEW)) { $messages[$id][$spec[3]] = htmlspecialchars($message[$spec[1]], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); $email_url = phorum_api_format_html_encode("mailto:" . $message[$spec[2]]); $messages[$id]["URL"]["PROFILE"] = $email_url; } else { $messages[$id][$spec[3]] = htmlspecialchars($message[$spec[1]], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); } if ($censor_search !== NULL) { $messages[$id][$spec[3]] = preg_replace($censor_search, $censor_replace, $messages[$id][$spec[3]]); } } } // A hook for module writers to apply custom message formatting. if (isset($PHORUM["hooks"]["format"])) { $messages = phorum_api_hook("format", $messages); } // A hook for module writers for doing post formatting fixups. if (isset($PHORUM["hooks"]["format_fixup"])) { $messages = phorum_api_hook("format_fixup", $messages); } // Clean up after the mods are done. foreach ($messages as $id => $message) { // Clean up line breaks inside pre and xmp tags. These tags // take care of showing newlines as breaks themselves. if (isset($message['body']) && $message['body'] != '') { foreach (array('pre', 'goep', 'xmp') as $tagname) { if (preg_match_all("/(<{$tagname}.*?>).+?(<\\/{$tagname}>)/si", $message['body'], $matches)) { foreach ($matches[0] as $match) { $stripped = str_replace($phorum_br, '', $match); $message['body'] = str_replace($match, $stripped, $message['body']); } } } // Remove line break after div, quote and code tags. These // tags have their own line break. Without this, there would // be to many white lines. $message['body'] = preg_replace("/\\s*(<\\/?(?:div|xmp|blockquote|pre)[^>]*>)\\s*\\Q{$phorum_br}\\E/", '$1', $message['body']); // Normalize the Phorum line breaks that are left. $messages[$id]['body'] = str_replace($phorum_br, "<br />", $message['body']); } } return $messages; }
/** * Check if the active user has permission to delete a file. * * @example file_delete.php Delete a file. * * @param integer $file_id * The file_id of the file for which to check the delete access. * * @return boolean * TRUE if the user has rights to delete the file, FALSE otherwise. */ function phorum_api_file_check_delete_access($file_id) { global $PHORUM; settype($file_id, "int"); // Administrator users always have rights to delete files. if ($PHORUM["user"]["admin"]) { return TRUE; } // Anonymous users never have rights to delete files. if (empty($PHORUM["user"]["user_id"])) { return FALSE; } // For other users, the file information has to be retrieved // to be able to check the delete access. $file = phorum_api_file_check_read_access($file_id, PHORUM_FLAG_IGNORE_PERMS); // To prevent permission errors after deleting the same file twice, // we'll return TRUE if we did not find a file (if the file is not found, // then there's no harm in deleting it; the file storage API will // silently ignore deleting non-existent files). If some other error // occurred, then we return FALSE (most likely, the user does not // even have read permission for the file, so delete access would // be out of the question too). if ($file === FALSE) { if (phorum_api_errno() == PHORUM_ERRNO_NOTFOUND) { return TRUE; } else { return FALSE; } } // We don't care about deleting temporary files and files that // are linked to the posting editor (during writing a post). // Those are both intermediate states for files, without them // being available on the forum. So for those, we always grant // delete access. if ($file["link"] == PHORUM_LINK_TEMPFILE || $file["link"] == PHORUM_LINK_EDITOR) { return TRUE; } // If the file is owned by the user, then the user has rights // to delete the file (this would be a personal user file). if (!empty($file["user_id"]) && $file["user_id"] == $PHORUM["user"]["user_id"]) { return TRUE; } // The file is not owned by the user. In that case, the user only has // rights to delete it if it is a file that is linked to a message which // the user posted himself of which was posted in a forum for which // the user is a moderator. if ($file["link"] == PHORUM_LINK_MESSAGE) { // Retrieve the message to which the file is linked. $message = phorum_db_get_message($file["message_id"]); // If the message cannot be found, we do not care if the linked // file is deleted. It's clearly an orphin file. if (!$message) { return TRUE; } // Check if the user posted the message himself. if (!empty($message["user_id"]) && $message["user_id"] == $PHORUM["user"]["user_id"]) { return TRUE; } // Check if the user is moderator for the forum_id of the message. if (phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES, $message["forum_id"])) { return TRUE; } } // The default policy for any unhandled case is to deny access. return FALSE; }
return; } // somehow we got to a folder if ($PHORUM["folder_flag"]) { phorum_api_redirect(PHORUM_INDEX_URL, $PHORUM['forum_id']); } if (isset($PHORUM["args"][1]) && is_numeric($PHORUM["args"][1])) { $message_id = $PHORUM["args"][1]; } else { phorum_api_redirect(PHORUM_INDEX_URL, $PHORUM['forum_id']); } $message = $PHORUM['DB']->get_message($message_id); if (empty($message)) { phorum_api_redirect(PHORUM_INDEX_URL, $PHORUM["forum_id"]); } $PHORUM["DATA"]["MODERATOR"] = phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES); $edit_tracks = $PHORUM['DB']->get_message_edits($message_id); if (count($edit_tracks) == 0 || $PHORUM["track_edits"] == PHORUM_EDIT_TRACK_OFF || $PHORUM["track_edits"] == PHORUM_EDIT_TRACK_MODERATOR && !$PHORUM["DATA"]["MODERATOR"]) { phorum_api_redirect(PHORUM_READ_URL, $message['thread'], $message_id); } $diffs = array_reverse($edit_tracks); // push an empty diff for the current status array_push($diffs, array()); $prev_body = -1; $prev_subject = -1; foreach ($diffs as $diff_info) { if (!isset($diff_info["user_id"])) { $this_version["username"] = empty($PHORUM['custom_display_name']) ? htmlspecialchars($message["author"], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]) : $message["author"]; $this_version["user_id"] = $message["user_id"]; $this_version["date"] = phorum_api_format_date($PHORUM["long_date_time"], $message["datestamp"]); $this_version["original"] = true;
/** * Formats forum messages. * * @param array $data * An array containing an array of messages to be formatted. * * @param array $author_specs * By default, the formatting function will create author info * data out of the fields "user_id", "author" and "email". * This will create $data["URL"]["PROFILE"] if needed (either pointing * to a user profile for registered users or the email address of * anonymous users that left an email address in the forum) and will * do formatting on the $data["author"] field. * * By providing extra $author_specs, this formatting can be done on * more author fields. This argument should be an array, containing * arrays with five fields: the field that contains a user_id, * the field for the name of the author and the field for the email * address (can be NULL if none available), the name of the field * to store the author name in and the name of the URL field to store * the profile/email link in. For the default author field like * describe above, this array would be: * * array("user_id", "author", "email", "author", "PROFILE"); * * @return data - The formatted messages. */ function phorum_format_messages($data, $author_specs = NULL) { $PHORUM = $GLOBALS["PHORUM"]; // Prepare author specs. if ($author_specs === NULL) { $author_specs = array(); } $author_specs[] = array("user_id", "author", "email", "author", "PROFILE"); // Prepare the bad-words replacement code. $bad_word_check = false; $banlists = NULL; if (!empty($PHORUM['cache_banlists']) && !empty($PHORUM['banlist_version'])) { $cache_key = $PHORUM['forum_id']; $banlists = phorum_cache_get('banlist', $cache_key, $PHORUM['banlist_version']); } // not found or no caching enabled if ($banlists === NULL) { $banlists = phorum_db_get_banlists(); if (!empty($PHORUM['cache_banlists']) && !empty($PHORUM['banlist_version'])) { phorum_cache_put('banlist', $cache_key, $banlists, 7200, $PHORUM['banlist_version']); } } if (isset($banlists[PHORUM_BAD_WORDS]) && is_array($banlists[PHORUM_BAD_WORDS])) { $replace_vals = array(); $replace_words = array(); foreach ($banlists[PHORUM_BAD_WORDS] as $item) { $replace_words[] = "/\\b" . preg_quote($item['string'], '/') . "(ing|ed|s|er|es)*\\b/i"; $replace_vals[] = PHORUM_BADWORD_REPLACE; $bad_word_check = true; } } // A special <br> tag to keep track of breaks that are added by phorum. $phorum_br = '<phorum break>'; // prepare url-templates used later on $profile_url_template = phorum_get_url(PHORUM_PROFILE_URL, '%spec_data%'); // Apply Phorum's formatting rules to all messages. foreach ($data as $key => $message) { // Normally, the message_id must be set, since we should be handling // message data. It might not be set however, because sometimes // the message formatting is called using some fake message data // for formatting something else than a message. if (!isset($message['message_id'])) { $data[$key]['message_id'] = $message['message_id'] = $key; } // Work on the message body ======================== if (isset($message["body"])) { $body = $message["body"]; // Convert legacy <> urls into bare urls. $body = preg_replace("/<((http|https|ftp):\\/\\/[a-z0-9;\\/\\?:@=\\&\$\\-_\\.\\+!*'\\(\\),~%]+?)>/i", "\$1", $body); // Escape special HTML characters. $escaped_body = htmlspecialchars($body, ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); if ($escaped_body == "") { if (function_exists("iconv")) { // we are gonna guess and see if we get lucky $escaped_body = iconv("ISO-8859-1", $PHORUM["DATA"]["HCHARSET"], $body); } else { // we let htmlspecialchars use its defaults $escaped_body = htmlspecialchars($body); } } $body = $escaped_body; // Replace newlines with $phorum_br temporarily. // This way the mods know what Phorum did vs the user. $body = str_replace("\n", "{$phorum_br}\n", $body); // Run bad word replacement code. if ($bad_word_check) { $body = preg_replace($replace_words, $replace_vals, $body); } $data[$key]["body"] = $body; } // Work on the other fields ======================== // Run bad word replacement code on subject and author. if ($bad_word_check) { if (isset($message["subject"])) { $data[$key]["subject"] = preg_replace($replace_words, $replace_vals, $data[$key]["subject"]); } if (isset($message["author"])) { $data[$key]["author"] = preg_replace($replace_words, $replace_vals, $data[$key]["author"]); } } // Escape special HTML characters in fields. if (isset($message["email"])) { $data[$key]["email"] = htmlspecialchars($data[$key]["email"], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); } if (isset($message["subject"])) { $data[$key]["subject"] = htmlspecialchars($data[$key]["subject"], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); } // Do author formatting for all provided author fields. foreach ($author_specs as $spec) { // Use "Anonymous user" as the author name if there's no author // name available for some reason. if (!isset($message[$spec[1]]) || $message[$spec[1]] == '') { $data[$key][$spec[3]] = $PHORUM["DATA"]["LANG"]["AnonymousUser"]; } elseif (!empty($message[$spec[0]])) { $url = str_replace('%spec_data%', $message[$spec[0]], $profile_url_template); $data[$key]["URL"][$spec[4]] = $url; $data[$key][$spec[3]] = empty($PHORUM["custom_display_name"]) ? htmlspecialchars($message[$spec[1]], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]) : $message[$spec[1]]; } elseif ($spec[2] !== NULL && !empty($message[$spec[2]]) && (empty($PHORUM['hide_email_addr']) || !empty($PHORUM["user"]["admin"]) || phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES) && PHORUM_MOD_EMAIL_VIEW || phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_USERS) && PHORUM_MOD_EMAIL_VIEW)) { $data[$key][$spec[3]] = htmlspecialchars($message[$spec[1]], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); $email_url = phorum_html_encode("mailto:" . $message[$spec[2]]); $data[$key]["URL"]["PROFILE"] = $email_url; } else { $data[$key][$spec[3]] = htmlspecialchars($message[$spec[1]], ENT_COMPAT, $PHORUM["DATA"]["HCHARSET"]); } } } // A hook for module writers to apply custom message formatting. if (isset($PHORUM["hooks"]["format"])) { $data = phorum_hook("format", $data); } // A hook for module writers for doing post formatting fixups. if (isset($PHORUM["hooks"]["format_fixup"])) { $data = phorum_hook("format_fixup", $data); } // Clean up after the mods are done. foreach ($data as $key => $message) { // Clean up line breaks inside pre and xmp tags. These tags // take care of showing newlines as breaks themselves. if (isset($message["body"])) { foreach (array("pre", "goep", "xmp") as $tagname) { if (preg_match_all("/(<{$tagname}.*?>).+?(<\\/{$tagname}>)/si", $message["body"], $matches)) { foreach ($matches[0] as $match) { $stripped = str_replace($phorum_br, "", $match); $message["body"] = str_replace($match, $stripped, $message["body"]); } } } // Remove line break after div, quote and code tags. These // tags have their own line break. Without this, there would // be to many white lines. $message["body"] = preg_replace("/\\s*(<\\/?(?:div|xmp|blockquote|pre)[^>]*>)\\s*\\Q{$phorum_br}\\E/", "\$1", $message["body"]); // Normalize the Phorum line breaks that are left. $data[$key]["body"] = str_replace($phorum_br, "<br />", $message["body"]); } } return $data; }
$mode = "reply"; } // Do ban list checks. Only check the bans on entering and // on finishing up. No checking is needed on intermediate requests. if ($initial || $finish || $preview) { include './include/posting/check_banlist.php'; } // Determine the abilities that the current user has. // Is the forum running in a moderated state? $PHORUM["DATA"]["MODERATED"] = $PHORUM["moderation"] == PHORUM_MODERATE_ON && !phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES); // Does the user have administrator permissions? $PHORUM["DATA"]["ADMINISTRATOR"] = $PHORUM["user"]["admin"]; // Does the user have moderator permissions? $PHORUM["DATA"]["MODERATOR"] = phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES); // Ability: Do we allow attachments? $PHORUM["DATA"]["ATTACHMENTS"] = $PHORUM["max_attachments"] > 0 && phorum_api_user_check_access(PHORUM_USER_ALLOW_ATTACH); // What options does this user have for a message? $PHORUM["DATA"]["OPTION_ALLOWED"] = array("sticky" => FALSE, "allow_reply" => FALSE, "subscribe" => FALSE, "subscribe_mail" => FALSE); // Subscribing to threads for new messages by authenticated users or for // editing messages posted by authenticated users (in which case the // thread subscription for the user that posted the message can be // updated). if (($mode == "post" || $mode == "reply") && $PHORUM["DATA"]["LOGGEDIN"] || $mode == "edit" && !empty($message["user_id"])) { $PHORUM["DATA"]["OPTION_ALLOWED"]["subscribe"] = TRUE; $PHORUM["DATA"]["OPTION_ALLOWED"]["subscribe_mail"] = !empty($PHORUM['allow_email_notify']) ? TRUE : FALSE; } // For moderators and administrators. if (($PHORUM["DATA"]["MODERATOR"] || $PHORUM["DATA"]["ADMINISTRATOR"]) && $message["parent_id"] == 0) { $PHORUM["DATA"]["OPTION_ALLOWED"]["sticky"] = true; $PHORUM["DATA"]["OPTION_ALLOWED"]["allow_reply"] = true; }
/** * Check if the user has read permission for a forum page. * * If the user does not have read permission for the currently active * forum, then an error message is shown. What message to show depends * on the exact case. Possible cases are: * * - The user is logged in: final missing read permission message; * - The user is not logged in, but wouldn't be allowed to read the * forum, even if he were logged in: final missing read permission message; * - The user is not logged in, but could be allowed to read the * forum if he were logged in: please login message. * * @return boolean * TRUE in case the user is allowed to read the forum, * FALSE otherwise. */ function phorum_check_read_common() { global $PHORUM; $retval = TRUE; if ($PHORUM["forum_id"] > 0 && !$PHORUM["folder_flag"] && !phorum_api_user_check_access(PHORUM_USER_ALLOW_READ)) { if ($PHORUM["DATA"]["LOGGEDIN"]) { // if they are logged in and not allowed, they don't have rights $PHORUM["DATA"]["OKMSG"] = $PHORUM["DATA"]["LANG"]["NoRead"]; } else { // Check if they could read if logged in. // If so, let them know to log in. if (empty($PHORUM["DATA"]["POST"]["parentid"]) && $PHORUM["reg_perms"] & PHORUM_USER_ALLOW_READ) { $PHORUM["DATA"]["OKMSG"] = $PHORUM["DATA"]["LANG"]["PleaseLoginRead"]; } else { $PHORUM["DATA"]["OKMSG"] = $PHORUM["DATA"]["LANG"]["NoRead"]; } } phorum_build_common_urls(); phorum_api_output("message"); $retval = FALSE; } return $retval; }
// This program is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY, without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // // // // You should have received a copy of the Phorum License // // along with this program. // // // //////////////////////////////////////////////////////////////////////////////// if (!defined("PHORUM_CONTROL_CENTER")) { return; } $template = "cc_start"; $PHORUM['DATA']['UserPerms'] = phorum_readable_permissions(); $PHORUM['DATA']['PROFILE']['raw_date_added'] = $PHORUM['DATA']['PROFILE']['date_added']; $PHORUM['DATA']['PROFILE']['date_added'] = phorum_api_format_date($PHORUM['short_date_time'], $PHORUM['DATA']['PROFILE']['date_added']); if ($PHORUM["track_user_activity"] && (!empty($PHORUM["user"]["admin"]) || phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES) || phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_USERS) || !$PHORUM['DATA']['PROFILE']["hide_activity"])) { $PHORUM["DATA"]["PROFILE"]["raw_date_last_active"] = $PHORUM["DATA"]["PROFILE"]["date_last_active"]; $PHORUM["DATA"]["PROFILE"]["date_last_active"] = phorum_api_format_date($PHORUM['short_date_time'], $PHORUM["DATA"]["PROFILE"]["date_last_active"]); } else { unset($PHORUM["DATA"]["PROFILE"]["date_last_active"]); } if (isset($PHORUM["hooks"]["profile"])) { $PHORUM["DATA"]["PROFILE"] = phorum_api_hook("profile", $PHORUM["DATA"]["PROFILE"]); } /* --------------------------------------------------------------- */ function phorum_readable_permissions() { global $PHORUM; $newperms = array(); if (isset($PHORUM["user"]["permissions"])) { $forums = phorum_api_forums_get(array_keys($PHORUM["user"]["permissions"]));
/** * Subscribe a user to a thread. * * Remark: Currently, there is no active support for subscribing to forums * using subscription type PHORUM_SUBSCRIPTION_DIGEST in the Phorum core. * * @param integer $user_id * The id of the user to create the subscription for. * * @param integer $thread * The id of the thread to describe to. * * @param integer $forum_id * The id of the forum in which the thread to subscribe to resides. * * @param integer $type * The type of subscription. Available types are: * - {@link PHORUM_SUBSCRIPTION_NONE} * - {@link PHORUM_SUBSCRIPTION_MESSAGE} * - {@link PHORUM_SUBSCRIPTION_BOOKMARK} * - {@link PHORUM_SUBSCRIPTION_DIGEST} */ function phorum_api_user_subscribe($user_id, $thread, $forum_id, $type) { // Check if the user is allowed to read the forum. if (!phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, $forum_id)) { return; } // Setup the subscription. phorum_db_user_subscribe($user_id, $thread, $forum_id, $type); }
/** * Search the database using the provided search criteria and return * an array containing the total count of matches and the visible * messages based on the page $offset and $length. * * @param string $search * The query to search on in messages and subjects. * * @param mixed $author * The query to search on in the message authors or a numerical user_id * if searching for all messages for a certain user_id. * * @param boolean $return_threads * Whether to return the results as threads (TRUE) or messages (FALSE). * When searching for a user ($match_type = USER_ID), then only the * thread starter messages that were posted by the user are returned. * * @param integer $page * The result page offset starting with 0. * * @param integer $limit * The result page limit (nr. of results per page). * * @param string $match_type * The type of search. This can be one of: * - ALL: search on all of the words (uses $search) * - ANY: search on any of the words (uses $search) * - PHRASE: search for an exact phrase (uses $search) * - USER_ID: search for an author id (uses $author) * * @param integer $days * The number of days to go back in the database for searching * (last [x] days) or zero to search within all dates. * * @param string $match_forum * The forum restriction. This can be either the string "ALL" to search * in any of the readable forums or a comma separated list of forum_ids. * * @return array * An array containing two fields: * - "count" contains the total number of matching messages. * - "rows" contains the messages that are visible, based on the page * $page and page $limit. The messages are indexed by message_id. */ public function search($search, $author, $return_threads, $page, $limit, $match_type, $days, $match_forum) { global $PHORUM; $fulltext_mode = isset($PHORUM['DBCONFIG']['mysql_use_ft']) && $PHORUM['DBCONFIG']['mysql_use_ft']; $search = trim($search); $author = trim($author); settype($return_threads, 'bool'); settype($page, 'int'); settype($limit, 'int'); settype($days, 'int'); // For spreading search results over multiple pages. $offset = $page * $limit; // Initialize the return data. $return = array('count' => 0, 'rows' => array()); // Return immediately if the search queries are empty. if ($search == '' && $author == '') { return $return; } // Check what forums the active Phorum user can read. $allowed_forums = phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, PHORUM_ACCESS_LIST); // If the user is not allowed to search any forum or the current // active forum, then return the emtpy search results array. if (empty($allowed_forums) || $PHORUM['forum_id'] > 0 && !in_array($PHORUM['forum_id'], $allowed_forums)) { return $return; } // Prepare forum_id restriction. $match_forum_arr = explode(",", $match_forum); $search_forums = array(); foreach ($match_forum_arr as $forum_id) { if ($forum_id == "ALL") { $search_forums = $allowed_forums; break; } if (isset($allowed_forums[$forum_id])) { $search_forums[] = $forum_id; } } if (count($search_forums)) { $forum_where = "AND forum_id in (" . implode(",", $search_forums) . ")"; } else { // Hack attempt or error. Return empty search results. return $return; } // Prepare day limit restriction. if ($days > 0) { $ts = time() - 86400 * $days; $datestamp_where = "AND datestamp >= {$ts}"; } else { $datestamp_where = ''; } // We make use of temporary tables for storing intermediate search // results. These tables are stored in $tables during processing. $tables = array(); // ------------------------------------------------------------------- // Handle search for user_id only. // ------------------------------------------------------------------- if ($search == '' && $author != '' && $match_type == 'USER_ID') { $user_id = (int) $author; if (empty($user_id)) { return $return; } // Search for messages. $where = "user_id = {$user_id} AND\n status=" . PHORUM_STATUS_APPROVED . " AND\n moved=0"; if ($return_threads) { $where .= " AND parent_id = 0"; } $sql = "SELECT SQL_CALC_FOUND_ROWS *\n FROM {$this->message_table} " . ($this->_can_USE_INDEX ? "USE INDEX (user_messages)" : "") . "WHERE {$where} {$forum_where}\n ORDER BY datestamp DESC"; // Retrieve the message rows. $rows = $this->interact(DB_RETURN_ASSOCS, $sql, "message_id", NULL, $limit, $offset); // Retrieve the number of found messages. $count = $this->interact(DB_RETURN_VALUE, "SELECT found_rows()"); // Fill the return data. $return = array("count" => $count, "rows" => $rows); return $return; } // ------------------------------------------------------------------- // Handle search for message and subject. // ------------------------------------------------------------------- if ($search != '') { $match_str = ''; $tokens = array(); if ($match_type == "PHRASE") { $search = str_replace('"', '', $search); $match_str = '"' . $this->interact(DB_RETURN_QUOTED, $search) . '"'; } else { // Surround with spaces so matching is easier. $search = " {$search} "; // Pull out all grouped terms, e.g. (nano mini). $paren_terms = array(); if (strstr($search, '(')) { preg_match_all('/ ([+\\-~]*\\(.+?\\)) /', $search, $m); $search = preg_replace('/ [+\\-~]*\\(.+?\\) /', ' ', $search); $paren_terms = $m[1]; } // Pull out all the double quoted strings, // e.g. '"iMac DV" or -"iMac DV". $quoted_terms = array(); if (strstr($search, '"')) { preg_match_all('/ ([+\\-~]*".+?") /', $search, $m); $search = preg_replace('/ [+\\-~]*".+?" /', ' ', $search); $quoted_terms = $m[1]; } // Finally, pull out the rest words in the string. $norm_terms = preg_split("/\\s+/", $search, 0, PREG_SPLIT_NO_EMPTY); // Merge all search terms together. $tokens = array_merge($quoted_terms, $paren_terms, $norm_terms); } // Handle full text message / subject search. if ($fulltext_mode) { // Create a match string based on the parsed query tokens. if (count($tokens)) { $match_str = ''; foreach ($tokens as $term) { if (!strstr("+-~", substr($term, 0, 1))) { if (strstr($term, ".") && !preg_match('!^".+"$!', $term) && substr($term, -1) != "*") { $term = "\"{$term}\""; } if ($match_type == "ALL") { $term = "+" . $term; } } $match_str .= "{$term} "; } $match_str = trim($match_str); $match_str = $this->interact(DB_RETURN_QUOTED, $match_str); } $table_name = $this->search_table . "_ft_" . md5(microtime()); $this->interact(DB_RETURN_RES, "CREATE TEMPORARY TABLE {$table_name} (\n KEY (message_id)\n ) ENGINE=HEAP\n SELECT message_id\n FROM {$this->search_table}\n WHERE MATCH (search_text)\n AGAINST ('{$match_str}' IN BOOLEAN MODE)"); $tables[] = $table_name; } else { if (count($tokens)) { $condition = $match_type == "ALL" ? "AND" : "OR"; foreach ($tokens as $tid => $token) { $tokens[$tid] = $this->interact(DB_RETURN_QUOTED, $token); } $match_str = "('%" . implode("%' {$condition} '%", $tokens) . "%')"; } $table_name = $this->search_table . "_like_" . md5(microtime()); $this->interact(DB_RETURN_RES, "CREATE TEMPORARY TABLE {$table_name} (\n KEY (message_id)\n ) ENGINE=HEAP\n SELECT message_id\n FROM {$this->search_table}\n WHERE search_text LIKE {$match_str}"); $tables[] = $table_name; } } // ------------------------------------------------------------------- // Handle search for author. // ------------------------------------------------------------------- if ($author != '') { $table_name = $this->search_table . "_author_" . md5(microtime()); // Search either by user_id or by username. if ($match_type == "USER_ID") { $author = (int) $author; $author_where = "user_id = {$author}"; } else { $author = $this->interact(DB_RETURN_QUOTED, $author); $author_where = "author = '{$author}'"; } $this->interact(DB_RETURN_RES, "CREATE TEMPORARY TABLE {$table_name} (\n KEY (message_id)\n ) ENGINE=HEAP\n SELECT message_id\n FROM {$this->message_table}\n WHERE {$author_where}"); $tables[] = $table_name; } // ------------------------------------------------------------------- // Gather the results. // ------------------------------------------------------------------- if (count($tables)) { // If we only have one temporary table, we can use it directly. if (count($tables) == 1) { $table = array_shift($tables); } else { $table = $this->search_table . "_final_" . md5(microtime()); $joined_tables = ""; $main_table = array_shift($tables); foreach ($tables as $tbl) { $joined_tables .= "INNER JOIN {$tbl} USING (message_id)"; } $this->interact(DB_RETURN_RES, "CREATE TEMPORARY TABLE {$table} (\n KEY (message_id)\n ) ENGINE=HEAP\n SELECT m.message_id\n FROM {$main_table} m {$joined_tables}"); } // When only threads need to be returned, then join the results // that we have so far with the message table into a result set // that only contains the threads for the results. if ($return_threads) { $threads_table = $this->search_table . "_final_threads_" . md5(microtime()); $this->interact(DB_RETURN_RES, "CREATE TEMPORARY TABLE {$threads_table} (\n KEY (message_id)\n ) ENGINE=HEAP\n SELECT distinct thread AS message_id\n FROM {$this->message_table}\n INNER JOIN {$table}\n USING (message_id)"); $table = $threads_table; } // Retrieve the found messages. $rows = $this->interact(DB_RETURN_ASSOCS, "SELECT SQL_CALC_FOUND_ROWS *\n FROM {$this->message_table}\n INNER JOIN {$table} USING (message_id)\n WHERE status=" . PHORUM_STATUS_APPROVED . "\n {$forum_where}\n {$datestamp_where}\n ORDER BY datestamp DESC", "message_id", NULL, $limit, $offset); // Retrieve the number of found messages. $count = $this->interact(DB_RETURN_VALUE, "SELECT found_rows()"); // Fill the return data. $return = array("count" => $count, "rows" => $rows); } return $return; }
$msg = phorum_pm_quoteformat($message["author"], $message["user_id"], $msg); // Include the other recipient, excecpt the active // user himself, when replying to all. if (isset($_POST["reply_to_all"])) { foreach ($message["recipients"] as $rcpt) { if ($user_id == $rcpt["user_id"]) { continue; } $msg["recipients"][$rcpt["user_id"]] = array("display_name" => $rcpt["display_name"], "user_id" => $rcpt["user_id"]); } } $hide_userselect = 1; // Setup data for replying privately to a forum post. } elseif (isset($PHORUM["args"]["message_id"])) { $message = $PHORUM['DB']->get_message($PHORUM["args"]["message_id"], "message_id", true); if (phorum_api_user_check_access(PHORUM_USER_ALLOW_READ) && ($PHORUM["forum_id"] == $message["forum_id"] || $message["forum_id"] == 0)) { // get url to the message board thread $origurl = phorum_api_url(PHORUM_READ_URL, $message["thread"], $message["message_id"]); // Get the data for the user that we reply to. $user = phorum_api_user_get($message["user_id"]); $msg["subject"] = $message["subject"]; $msg["message"] = $message["body"]; $msg["recipients"][$message["user_id"]] = array('display_name' => $user["display_name"], 'user_id' => $user["user_id"]); $msg = phorum_pm_quoteformat($user["display_name"], $user["user_id"], $msg, $origurl); } $hide_userselect = 1; } } /** * [hook] * pm_send_init
// Remember this for the template. $email_temp_part = $_POST['email']; unset($_POST['email']); } list($error, $okmsg) = phorum_controlcenter_user_save($panel); } } if (!empty($email_temp_part)) { $PHORUM['DATA']['PROFILE']['email_temp_part'] = $email_temp_part; } // TEMPLATETODO // flip this due to db vs. UI wording. if (!empty($PHORUM['DATA']['PROFILE']["hide_email"])) { $PHORUM["DATA"]["PROFILE"]["hide_email_checked"] = ""; } else { // more html stuff in the code. yuck. $PHORUM["DATA"]["PROFILE"]["hide_email_checked"] = " checked=\"checked\""; } if (phorum_api_user_check_access(PHORUM_USER_ALLOW_MODERATE_MESSAGES, PHORUM_ACCESS_ANY)) { $PHORUM["DATA"]["PROFILE"]["show_moderate_options"] = true; if (!empty($PHORUM['DATA']['PROFILE']["moderation_email"])) { $PHORUM["DATA"]["PROFILE"]["moderation_email_checked"] = " checked=\"checked\""; } else { $PHORUM["DATA"]["PROFILE"]["moderation_email_checked"] = ""; } } else { $PHORUM["DATA"]["PROFILE"]["show_moderate_options"] = false; } $PHORUM["DATA"]["PROFILE"]["EMAIL_CONFIRM"] = $PHORUM["registration_control"]; $PHORUM['DATA']['PROFILE']['MAILSETTINGS'] = 1; $template = "cc_usersettings";
$row["URL"]["SPLIT"] = str_replace(array('%action_id%', '%message_id%'), array(PHORUM_SPLIT_THREAD, $row["message_id"]), $moderation_url_template); if ($row['is_unapproved']) { $row["URL"]["APPROVE"] = str_replace(array('%action_id%', '%message_id%'), array(PHORUM_APPROVE_MESSAGE, $row["message_id"]), $moderation_url_template); } else { $row["URL"]["HIDE"] = str_replace(array('%action_id%', '%message_id%'), array(PHORUM_HIDE_POST, $row["message_id"]), $moderation_url_template); } if ($build_move_url) { $row["URL"]["MOVE"] = $URLS["move_url"]; } $row["URL"]["MERGE"] = $URLS["merge_url"]; $row["URL"]["CLOSE"] = $URLS["close_url"]; $row["URL"]["REOPEN"] = $URLS["reopen_url"]; } // allow editing only if logged in, allowed for forum, the thread is open, // its the same user, and its within the time restriction if ($PHORUM["user"]["user_id"] == $row["user_id"] && phorum_api_user_check_access(PHORUM_USER_ALLOW_EDIT) && !$thread_is_closed && ($PHORUM["user_edit_timelimit"] == 0 || $row["datestamp"] + $PHORUM["user_edit_timelimit"] * 60 >= time())) { $row["edit"] = 1; if (!$PHORUM["DATA"]["MODERATOR"]) { $row["URL"]["EDIT"] = str_replace(array('%action_id%', '%message_id%'), array("edit", $row["message_id"]), $edit_url_template); } } // this stuff is used in threaded and non threaded. $row["raw_short_datestamp"] = $row["datestamp"]; $row["short_datestamp"] = phorum_date($PHORUM["short_date_time"], $row["datestamp"]); $row["raw_datestamp"] = $row["datestamp"]; $row["datestamp"] = phorum_date($PHORUM["long_date_time"], $row["datestamp"]); $row["URL"]["READ"] = str_replace(array('%thread_id%', '%message_id%'), array($row["thread"], $row["message_id"]), $read_url_template_both); $row["URL"]["REPLY"] = str_replace(array('%thread_id%', '%message_id%'), array($row["thread"], $row["message_id"]), $reply_url_template); $row["URL"]["QUOTE"] = str_replace(array('%thread_id%', '%message_id%'), array($row["thread"], $row["message_id"]), $reply_url_template_quote); $row["URL"]["PM"] = false; if ($PHORUM["DATA"]["LOGGEDIN"]) {
function sphinx_search_action($arrSearch) { global $PHORUM; // No pecl class, try php version if (!class_exists('SphinxClient')) { // loads from php include_path require_once 'sphinxapi.php'; } // these are the index-names set in sphinx.conf - one for searching messages, the other for searching by authors only // both contain an additional index for the deltas - changes done after the last full reindex $index_name_msg = 'phorum5_msg_d phorum5_msg'; $index_name_author = 'phorum5_author phorum5_author_d'; // excerpts_index is just one index as that function only accepts one, it used for determining charsets / mapping tables, nothing more $excerpts_index = 'phorum5_msg'; $index = $index_name_msg; if ($arrSearch['match_type'] == 'ALL') { $match_mode = SPH_MATCH_ALL; } elseif ($arrSearch['match_type'] == 'ANY') { $match_mode = SPH_MATCH_ANY; } elseif ($arrSearch['match_type'] == 'PHRASE') { $match_mode = SPH_MATCH_PHRASE; } elseif ($arrSearch['match_type'] == 'AUTHOR') { $match_mode = SPH_MATCH_PHRASE; $index = $index_name_author; } else { // Return search control to Phorum in case the search type isn't handled by the module. return $arrSearch; } if (empty($arrSearch['search']) && !empty($arrSearch['author'])) { $arrSearch['search'] = $arrSearch['author']; $index = $index_name_author; } $sphinx = new SphinxClient(); $sphinx->SetServer($PHORUM['mod_sphinx_search']['hostname'], $PHORUM['mod_sphinx_search']['port']); $sphinx->SetMatchMode($match_mode); // set the limits for paging $sphinx->SetLimits($arrSearch['offset'], $arrSearch['length']); // set the timeframe to search if ($arrSearch['match_dates'] > 0) { $min_ts = time() - 86400 * $arrSearch['match_dates']; $max_ts = time(); $sphinx->SetFilterRange('datestamp', $min_ts, $max_ts); } // Check what forums the active Phorum user can read. $allowed_forums = phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, PHORUM_ACCESS_LIST); // If the user is not allowed to search any forum or the current // active forum, then return the emtpy search results array. if (empty($allowed_forums) || $PHORUM['forum_id'] > 0 && !in_array($PHORUM['forum_id'], $allowed_forums)) { $arrSearch['results'] = array(); $arrSearch['totals'] = 0; $arrSearch['continue'] = 0; $arrSearch['raw_body'] = 1; return $arrSearch; } // Prepare forum_id restriction. $search_forums = array(); foreach (explode(',', $arrSearch['match_forum']) as $forum_id) { if ($forum_id == 'ALL') { $search_forums = $allowed_forums; break; } if (isset($allowed_forums[$forum_id])) { $search_forums[] = $forum_id; } } $sphinx->SetFilter('forum_id', $search_forums); // set the sort-mode $sphinx->SetSortMode(SPH_SORT_ATTR_DESC, 'datestamp'); // do the actual query $results = $sphinx->Query($arrSearch['search'], $index); $res = $sphinx->GetLastWarning(); if ($res) { error_log("sphinx_search.php: WARNING: {$res}"); } $res = $sphinx->GetLastError(); if ($res) { error_log("sphinx_search.php: ERROR: {$res}"); } // if no messages were found, then return empty handed. if (!isset($results['matches'])) { $arrSearch['results'] = array(); $arrSearch['totals'] = 0; $arrSearch['continue'] = 0; $arrSearch['raw_body'] = 1; return $arrSearch; } $search_msg_ids = $results['matches']; // get the messages we found $found_messages = phorum_db_get_message(array_keys($search_msg_ids), 'message_id', true); // sort them in reverse order of the message_id to automagically sort them by date desc this way krsort($found_messages); reset($found_messages); // prepare the array for building highlighted excerpts $docs = array(); foreach ($found_messages as $id => $data) { // remove hidden text in the output - only added by the hidden_msg module $data['body'] = preg_replace("/(\\[hide=([\\#a-z0-9]+?)\\](.+?)\\[\\/hide\\])/is", '', $data['body']); $docs[] = htmlspecialchars(phorum_strip_body($data['body'])); } $words = ''; if (!empty($results['words'])) { $words = implode(' ', array_keys($results['words'])); } $opts = array('chunk_separator' => ' [...] '); // build highlighted excerpts $highlighted = $sphinx->BuildExcerpts($docs, $excerpts_index, $words, $opts); $res = $sphinx->GetLastWarning(); if ($res) { error_log("sphinx_search.php: WARNING: {$res}"); } $res = $sphinx->GetLastError(); if ($res) { error_log("sphinx_search.php: ERROR: {$res}"); } $cnt = 0; foreach ($found_messages as $id => $content) { $found_messages[$id]['short_body'] = $highlighted[$cnt]; $cnt++; } $arrSearch['results'] = $found_messages; // we need the total results $arrSearch['totals'] = $results['total_found']; if ($arrSearch['totals'] > 1000) { $arrSearch['totals'] = 1000; } // don't run the default search $arrSearch['continue'] = 0; // tell it to leave the body alone $arrSearch['raw_body'] = 1; return $arrSearch; }