/** * Create topic/post visibility SQL for a given forum ID * * Note: Read permissions are not checked. * * @param $mode string Either "topic" or "post" * @param $forum_id int The forum id is used for permission checks * @param $table_alias string Table alias to prefix in SQL queries * @return string The appropriate combination SQL logic for topic/post_visibility */ public function get_visibility_sql($mode, $forum_id, $table_alias = '') { $where_sql = ''; $get_visibility_sql_overwrite = false; /** * Allow changing the result of calling get_visibility_sql * * @event core.src_content_visibility_get_visibility_sql_before * @var string where_sql Extra visibility conditions. It must end with either an SQL "AND" or an "OR" * @var string mode Either "topic" or "post" depending on the query this is being used in * @var array forum_id The forum id in which the search is made. * @var string table_alias Table alias to prefix in SQL queries * @var mixed get_visibility_sql_overwrite If a string, forces the function to return get_forums_visibility_sql_overwrite after executing the event * If false, get_visibility_sql continues normally * It must be either boolean or string * @since 3.1.4-RC1 */ $vars = array('where_sql', 'mode', 'forum_id', 'table_alias', 'get_visibility_sql_overwrite'); extract($this->src_dispatcher->trigger_event('core.src_content_visibility_get_visibility_sql_before', compact($vars))); if ($get_visibility_sql_overwrite !== false) { return $get_visibility_sql_overwrite; } if ($this->auth->acl_get('m_approve', $forum_id)) { return $where_sql . '1 = 1'; } return $where_sql . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED; }
/** * Determine whether the user is allowed to read and/or moderate the forum of the topic * * @param array $topic_ids Array with the topic ids * * @return array Returns an array with two keys 'm_' and 'read_f' which are also an array of topic_id => forum_id sets when the permissions are given. Sample: * array( * 'permission' => array( * topic_id => forum_id * ), * ), */ protected function get_topic_auth(array $topic_ids) { $forum_auth = array('f_read' => array(), 'm_' => array()); $topic_ids = array_unique($topic_ids); $sql = 'SELECT topic_id, forum_id FROM ' . TOPICS_TABLE . ' WHERE ' . $this->db->sql_in_set('topic_id', array_map('intval', $topic_ids)); $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { $row['topic_id'] = (int) $row['topic_id']; $row['forum_id'] = (int) $row['forum_id']; if ($this->auth->acl_get('f_read', $row['forum_id'])) { $forum_auth['f_read'][$row['topic_id']] = $row['forum_id']; } if ($this->auth->acl_gets('a_', 'm_', $row['forum_id'])) { $forum_auth['m_'][$row['topic_id']] = $row['forum_id']; } } $this->db->sql_freeresult($result); return $forum_auth; }
/** * Generate the debug output string * * @param \src\db\driver\driver_interface $db Database connection * @param \src\config\config $config Config object * @param \src\auth\auth $auth Auth object * @param \src\user $user User object * @param \src\event\dispatcher_interface $src_dispatcher Event dispatcher * @return string */ function src_generate_debug_output(\src\db\driver\driver_interface $db, \src\config\config $config, \src\auth\auth $auth, \src\user $user, \src\event\dispatcher_interface $src_dispatcher) { $debug_info = array(); // Output page creation time if (defined('src_DISPLAY_LOAD_TIME')) { if (isset($GLOBALS['starttime'])) { $totaltime = microtime(true) - $GLOBALS['starttime']; $debug_info[] = sprintf('<abbr title="SQL time: %.3fs / PHP time: %.3fs">Time: %.3fs</abbr>', $db->get_sql_time(), $totaltime - $db->get_sql_time(), $totaltime); } $debug_info[] = sprintf('<abbr title="Cached: %d">Queries: %d</abbr>', $db->sql_num_queries(true), $db->sql_num_queries()); $memory_usage = memory_get_peak_usage(); if ($memory_usage) { $memory_usage = get_formatted_filesize($memory_usage); $debug_info[] = 'Peak Memory Usage: ' . $memory_usage; } } if (defined('DEBUG')) { $debug_info[] = 'GZIP: ' . ($config['gzip_compress'] && @extension_loaded('zlib') ? 'On' : 'Off'); if ($user->load) { $debug_info[] = 'Load: ' . $user->load; } if ($auth->acl_get('a_')) { $debug_info[] = '<a href="' . build_url() . '&explain=1">SQL Explain</a>'; } } /** * Modify debug output information * * @event core.src_generate_debug_output * @var array debug_info Array of strings with debug information * * @since 3.1.0-RC3 */ $vars = array('debug_info'); extract($src_dispatcher->trigger_event('core.src_generate_debug_output', compact($vars))); return implode(' | ', $debug_info); }
/** * Performs a search on keywords depending on display specific params. You have to run split_keywords() first * * @param string $type contains either posts or topics depending on what should be searched for * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query * @param string $sort_key is the key of $sort_by_sql for the selected sorting * @param string $sort_dir is either a or d representing ASC and DESC * @param string $sort_days specifies the maximum amount of days a post may be old * @param array $ex_fid_ary specifies an array of forum ids which should not be searched * @param string $post_visibility specifies which types of posts the user can view in which forums * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain * @return boolean|int total number of results */ public function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $post_visibility, $topic_id, $author_ary, $author_name, &$id_ary, &$start, $per_page) { // No keywords? No posts. if (!strlen($this->search_query) && !sizeof($author_ary)) { return false; } $id_ary = array(); $join_topic = $type != 'posts'; // Sorting if ($type == 'topics') { switch ($sort_key) { case 'a': $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'poster_id ' . ($sort_dir == 'a' ? 'ASC' : 'DESC')); break; case 'f': $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'forum_id ' . ($sort_dir == 'a' ? 'ASC' : 'DESC')); break; case 'i': case 's': $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'post_subject ' . ($sort_dir == 'a' ? 'ASC' : 'DESC')); break; case 't': default: $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'topic_last_post_time ' . ($sort_dir == 'a' ? 'ASC' : 'DESC')); break; } } else { switch ($sort_key) { case 'a': $this->sphinx->SetSortMode($sort_dir == 'a' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'poster_id'); break; case 'f': $this->sphinx->SetSortMode($sort_dir == 'a' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'forum_id'); break; case 'i': case 's': $this->sphinx->SetSortMode($sort_dir == 'a' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_subject'); break; case 't': default: $this->sphinx->SetSortMode($sort_dir == 'a' ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_time'); break; } } // Most narrow filters first if ($topic_id) { $this->sphinx->SetFilter('topic_id', array($topic_id)); } $search_query_prefix = ''; switch ($fields) { case 'titleonly': // Only search the title if ($terms == 'all') { $search_query_prefix = '@title '; } // Weight for the title $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); // 1 is first_post, 0 is not first post $this->sphinx->SetFilter('topic_first_post', array(1)); break; case 'msgonly': // Only search the body if ($terms == 'all') { $search_query_prefix = '@data '; } // Weight for the body $this->sphinx->SetFieldWeights(array("title" => 1, "data" => 5)); break; case 'firstpost': // More relative weight for the title, also search the body $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); // 1 is first_post, 0 is not first post $this->sphinx->SetFilter('topic_first_post', array(1)); break; default: // More relative weight for the title, also search the body $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1)); break; } if (sizeof($author_ary)) { $this->sphinx->SetFilter('poster_id', $author_ary); } // As this is not simply possible at the moment, we limit the result to approved posts. // This will make it impossible for moderators to search unapproved and softdeleted posts, // but at least it will also cause the same for normal users. $this->sphinx->SetFilter('post_visibility', array(ITEM_APPROVED)); if (sizeof($ex_fid_ary)) { // All forums that a user is allowed to access $fid_ary = array_unique(array_intersect(array_keys($this->auth->acl_getf('f_read', true)), array_keys($this->auth->acl_getf('f_search', true)))); // All forums that the user wants to and can search in $search_forums = array_diff($fid_ary, $ex_fid_ary); if (sizeof($search_forums)) { $this->sphinx->SetFilter('forum_id', $search_forums); } } $this->sphinx->SetFilter('deleted', array(0)); $this->sphinx->SetLimits($start, (int) $per_page, SPHINX_MAX_MATCHES); $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); // Could be connection to localhost:9312 failed (errno=111, // msg=Connection refused) during rotate, retry if so $retries = SPHINX_CONNECT_RETRIES; while (!$result && strpos($this->sphinx->GetLastError(), "errno=111,") !== false && $retries--) { usleep(SPHINX_CONNECT_WAIT_TIME); $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); } if ($this->sphinx->GetLastError()) { add_log('critical', 'LOG_SPHINX_ERROR', $this->sphinx->GetLastError()); if ($this->auth->acl_get('a_')) { trigger_error($this->user->lang('SPHINX_SEARCH_FAILED', $this->sphinx->GetLastError())); } else { trigger_error($this->user->lang('SPHINX_SEARCH_FAILED_LOG')); } } $result_count = $result['total_found']; if ($result_count && $start >= $result_count) { $start = floor(($result_count - 1) / $per_page) * $per_page; $this->sphinx->SetLimits((int) $start, (int) $per_page, SPHINX_MAX_MATCHES); $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); // Could be connection to localhost:9312 failed (errno=111, // msg=Connection refused) during rotate, retry if so $retries = SPHINX_CONNECT_RETRIES; while (!$result && strpos($this->sphinx->GetLastError(), "errno=111,") !== false && $retries--) { usleep(SPHINX_CONNECT_WAIT_TIME); $result = $this->sphinx->Query($search_query_prefix . str_replace('"', '"', $this->search_query), $this->indexes); } } $id_ary = array(); if (isset($result['matches'])) { if ($type == 'posts') { $id_ary = array_keys($result['matches']); } else { foreach ($result['matches'] as $key => $value) { $id_ary[] = $value['attrs']['topic_id']; } } } else { return false; } $id_ary = array_slice($id_ary, 0, (int) $per_page); return $result_count; }
/** * Handles authentication when downloading attachments from PMs * * @param \src\db\driver\driver_interface $db The database object * @param \src\auth\auth $auth The authentication object * @param int $user_id The user id * @param int $msg_id The id of the PM that we are downloading from * * @return null */ function src_download_handle_pm_auth($db, $auth, $user_id, $msg_id) { if (!$auth->acl_get('u_pm_download')) { send_status_line(403, 'Forbidden'); trigger_error('SORRY_AUTH_VIEW_ATTACH'); } $allowed = src_download_check_pm_auth($db, $user_id, $msg_id); if (!$allowed) { send_status_line(403, 'Forbidden'); trigger_error('ERROR_NO_ATTACHMENT'); } }