/** * Retrieve a list of recent messages for all forums for which the user has * read permission, for a particular forum, for a list of forums or for a * particular thread. Optionally, only top level thread messages can be * retrieved. * * The original version of this function came from Jim Winstead of mysql.com * * @param integer $limit * Limit the number of returned messages to this number. * * @param integer $offset * When using the $limit parameter to limit the number of returned * messages, this parameter can be used to specify the retrieval offset. * * @param integer $forum_id * A forum_id, an array of forum_ids or 0 (zero) to retrieve messages * from any forum. * * @param integer $thread * A thread id or 0 (zero) to retrieve messages from any thread. * * @param integer $list_type * This parameter determines the type of list that has to be returned. * Options for this parameter are: * - LIST_RECENT_MESSAGES: return a list of recent messages * - LIST_RECENT_THREADS: return a list of recent threads * - LIST_UPDATED_THREADS: return a list of recently updated threads * - LIST_UNREAD_MESSAGES: return a list of unread messages * * @return array * An array of recent messages, indexed by message_id. One special key * "users" is set too. This one contains an array of all involved * user_ids. */ public function get_recent_messages($limit, $offset = 0, $forum_id = 0, $thread = 0, $list_type = LIST_RECENT_MESSAGES) { global $PHORUM; // Backward compatibility for the old $threads_only parameter. if (is_bool($list_type)) { $list_type = $list_type ? LIST_RECENT_THREADS : LIST_RECENT_MESSAGES; } settype($limit, 'int'); settype($offset, 'int'); settype($thread, 'int'); settype($list_type, 'int'); $this->sanitize_mixed($forum_id, 'int'); if ($list_type == LIST_UNREAD_MESSAGES) { if (empty($PHORUM['user']['user_id'])) { trigger_error(__METHOD__ . ": \$list_type parameter LIST_UNREAD_MESSAGES " . "used, but no authenticated user available; this feature " . "can only be used for authenticated users", E_USER_ERROR); } } // In case -1 is used as "any" value by the caller. if ($forum_id < 0) { $forum_id = 0; } if ($thread < 0) { $thread = 0; } // Parameter checking. if ($list_type < 0 || $list_type > 3) { trigger_error(__METHOD__ . ": illegal \$list_type parameter used", E_USER_ERROR); } if ($list_type != LIST_RECENT_MESSAGES && $thread) { trigger_error(__METHOD__ . ":\$thread parameter can only be " . "used with \$list_type = LIST_RECENT_MESSAGES", E_USER_ERROR); } // We have to check what forums the active Phorum user can read first. // Even if a $thread is passed, we have to make sure that the user // can read the containing forum. Here we convert the $forum_id // argument into an argument that is usable for // phorum_api_user_check_access(), in such way that it will always // return an array of accessible forum_ids. if ($forum_id == 0) { $forum_id = PHORUM_ACCESS_LIST; } elseif (!is_array($forum_id)) { $forum_id = array($forum_id => $forum_id); } $allowed_forums = phorum_api_user_check_access(PHORUM_USER_ALLOW_READ, $forum_id); // If the user is not allowed to see any forum, // then return an empty array. if (empty($allowed_forums)) { return array(); } // Keep track of the database index that we want to force // in order to optimize the query. $use_key = NULL; // We need to differentiate on which key to use. // If selecting on a specific thread, then the best index // to use would be the thread_message index. if ($thread) { $use_key = 'thread_message'; } elseif (count($allowed_forums) == 1) { switch ($list_type) { case LIST_RECENT_MESSAGES: case LIST_UNREAD_MESSAGES: $use_key = 'forum_recent_messages'; break; case LIST_RECENT_THREADS: $use_key = 'list_page_flat'; break; case LIST_UPDATED_THREADS: $use_key = 'list_page_float'; break; } } else { switch ($list_type) { case LIST_RECENT_MESSAGES: case LIST_UNREAD_MESSAGES: $use_key = 'PRIMARY'; break; case LIST_RECENT_THREADS: $use_key = 'recent_threads'; break; case LIST_UPDATED_THREADS: $use_key = 'updated_threads'; break; } } // Build the SQL query. $sql = "SELECT msg.* FROM {$this->message_table} msg"; if ($this->_can_USE_INDEX && $use_key !== NULL) { $sql .= " USE INDEX ({$use_key})"; } if ($list_type == LIST_UNREAD_MESSAGES) { $sql .= " LEFT JOIN {$this->user_newflags_min_id_table} min\n ON msg.forum_id = min.forum_id AND\n min.user_id = " . (int) $PHORUM['user']['user_id'] . " LEFT JOIN {$this->user_newflags_table} new\n ON msg.message_id = new.message_id AND\n new.user_id = " . (int) $PHORUM['user']['user_id']; } $sql .= " WHERE msg.status = " . PHORUM_STATUS_APPROVED; // When we are retrieving unread messages, we need to find out // how many new messages we have and what forums contain those // new messages. This is a relatively light query, which' output // can be used to greatly improve the query that we need to // run here. if ($list_type == LIST_UNREAD_MESSAGES) { $tmp = $this->get_forums($allowed_forums, NULL, NULL, NULL, NULL, 2); $tmp = phorum_api_newflags_apply_to_forums($tmp, PHORUM_NEWFLAGS_COUNT); $unread_count = 0; $unread_forums = array(); foreach ($tmp as $f) { if (!empty($f['new_messages'])) { $unread_count += $f['new_messages']; $unread_forums[$f['forum_id']] = $f['forum_id']; } } // No new messages? Then we're done here. if ($unread_count == 0) { return array(); } // Otherwise, update the query parameters to improve // the unread messages query. if ($unread_count < $limit) { $limit = $unread_count; } $allowed_forums = $unread_forums; } if (count($allowed_forums) == 1) { $sql .= " AND msg.forum_id = " . array_shift($allowed_forums); } else { $sql .= " AND msg.forum_id IN (" . implode(",", $allowed_forums) . ")"; } if ($thread) { $sql .= " AND msg.thread = {$thread}"; } $sql .= " AND msg.moved = 0"; if ($list_type == LIST_UNREAD_MESSAGES) { $sql .= " AND (min_id IS NULL OR msg.message_id > min_id)\n AND new.message_id IS NULL"; } if ($list_type == LIST_RECENT_THREADS || $list_type == LIST_UPDATED_THREADS) { $sql .= ' AND msg.parent_id = 0'; } if ($list_type == LIST_UPDATED_THREADS) { $sql .= ' ORDER BY msg.modifystamp DESC'; } else { $sql .= ' ORDER BY msg.datestamp DESC'; } // Retrieve matching messages from the database. $messages = $this->interact(DB_RETURN_ASSOCS, $sql, 'message_id', NULL, $limit, $offset); // Post processing of received messages. $involved_users = array(); foreach ($messages as $id => $message) { // Unpack the message meta data. $messages[$id]['meta'] = empty($message['meta']) ? array() : unserialize($message['meta']); // Collect all involved users. if (isset($message['user_id'])) { $involved_users[$message['user_id']] = $message['user_id']; } } // Store the involved users in the message array. $messages['users'] = $involved_users; return $messages; }
/** * This function handles preparing forum or folder data * for use in the templates. * * @param array $forums * An array of forum and/or folder data records to format. * * @param int $flags * If the {@link PHORUM_FLAG_ADD_UNREAD_INFO} flag is set, then template * data for showing new messages/threads will be added to the data records. * The exact data that is added depends on the value of the * $PHORUM['show_new_on_index'] setting variable. * * @param array * The same as the $forums argument array, with formatting applied * and template variables added. */ function phorum_api_format_forums($forums, $flags = 0) { global $PHORUM; static $index_url_template; static $list_url_template; static $markread_url_template; static $feed_url_template; if (empty($feed_url_template)) { $index_url_template = phorum_api_url(PHORUM_INDEX_URL, '%forum_id%'); $orig_forum_id = $PHORUM['forum_id']; $PHORUM['forum_id'] = '%forum_id%'; $post_url_template = phorum_api_url(PHORUM_POSTING_URL); $PHORUM['forum_id'] = $orig_forum_id; $list_url_template = phorum_api_url(PHORUM_LIST_URL, '%forum_id%'); $markread_url_template = phorum_api_url(PHORUM_INDEX_URL, '%forum_id%', 'markread', '%folder_id%'); $feed_url_template = phorum_api_url(PHORUM_FEED_URL, '%forum_id%', 'type=' . $PHORUM['default_feed']); } // For tracking forums for which we have to check unread messages. $forums_to_check = array(); foreach ($forums as $forum_id => $forum) { // Setup template data for folders. if ($forum['folder_flag']) { // A URL for the index view for this folder. We also set this // one up as URL->LIST, because up to Phorum 5.3 that variable // was in use. $forum['URL']['INDEX'] = $forum['URL']['LIST'] = str_replace('%forum_id%', $forum_id, $index_url_template); } else { // A URL for the message list for this forum. $forum['URL']['LIST'] = str_replace('%forum_id%', $forum_id, $list_url_template); // A "mark forum read" URL for authenticated users. if ($PHORUM['user']['user_id']) { $forum['URL']['MARK_READ'] = str_replace(array('%forum_id%', '%folder_id%'), array($forum_id, $PHORUM['forum_id']), $markread_url_template); } // A URL to post a new message. $forum['URL']['POST'] = str_replace('%forum_id%', $forum_id, $post_url_template); // A URL to the syndication feed. if (!empty($PHORUM['use_rss'])) { $forum['URL']['FEED'] = str_replace('%forum_id%', $forum_id, $feed_url_template); } // For dates, we store an unmodified version to always have // the original date available for modules. Not strictly // needed for this one, since we to not override the original // "last_post_time" field, but we still add it to be compliant // with the rest of the Phorum code. $forum['raw_last_post'] = $forum['last_post_time']; // Format the last post time, unless no messages were posted at all. if ($forum['message_count'] > 0) { $forum['last_post'] = phorum_api_format_date($PHORUM['long_date_time'], $forum['last_post_time']); } else { $forum['last_post'] = ' '; } // Some number formatting. $forum['raw_message_count'] = $forum['message_count']; $forum['message_count'] = number_format($forum['message_count'], 0, $PHORUM['dec_sep'], $PHORUM['thous_sep']); $forum['raw_thread_count'] = $forum['thread_count']; $forum['thread_count'] = number_format($forum['thread_count'], 0, $PHORUM['dec_sep'], $PHORUM['thous_sep']); $forums_to_check[] = $forum_id; } // Put the formatted record back in the array. $forums[$forum_id] = $forum; } // Add unread message information. if ($flags & PHORUM_FLAG_ADD_UNREAD_INFO && $PHORUM['show_new_on_index'] != PHORUM_NEWFLAGS_NOCOUNT && $PHORUM['user']['user_id'] && !empty($forums_to_check)) { $forums = phorum_api_newflags_apply_to_forums($forums, $PHORUM['show_new_on_index'], $forums_to_check); } return $forums; }