예제 #1
0
 /**
  * Executes the command cache:purge.
  *
  * Purge the cache (including permissions) and increment the asset_version number
  *
  * @param InputInterface  $input  An InputInterface instance
  * @param OutputInterface $output An OutputInterface instance
  *
  * @return null
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $this->config->increment('assets_version', 1);
     $this->cache->purge();
     // Clear permissions
     $this->auth->acl_clear_prefetch();
     src_cache_moderators($this->db, $this->cache, $this->auth);
     $this->log->add('admin', ANONYMOUS, '', 'LOG_PURGE_CACHE', time(), array());
     $output->writeln($this->user->lang('PURGE_CACHE_SUCCESS'));
 }
예제 #2
0
    /**
     * Create topic/post visibility SQL for all forums on the srcrd
     *
     * Note: Read permissions are not checked. Forums without read permissions
     *		should be in $exclude_forum_ids
     *
     * @param $mode				string	Either "topic" or "post"
     * @param $exclude_forum_ids	array	Array of forum ids which are excluded
     * @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_global_visibility_sql($mode, $exclude_forum_ids = array(), $table_alias = '')
    {
        $where_sqls = array();
        $approve_forums = array_diff(array_keys($this->auth->acl_getf('m_approve', true)), $exclude_forum_ids);
        $visibility_sql_overwrite = null;
        /**
         * Allow changing the result of calling get_global_visibility_sql
         *
         * @event core.src_content_visibility_get_global_visibility_before
         * @var	array		where_sqls							The action the user tried to execute
         * @var	string		mode								Either "topic" or "post" depending on the query this is being used in
         * @var	array		exclude_forum_ids					Array of forum ids the current user doesn't have access to
         * @var	string		table_alias							Table alias to prefix in SQL queries
         * @var	array		approve_forums						Array of forums where the user has m_approve permissions
         * @var	string		visibility_sql_overwrite	Forces the function to return an implosion of where_sqls (joined by "OR")
         * @since 3.1.3-RC1
         */
        $vars = array('where_sqls', 'mode', 'exclude_forum_ids', 'table_alias', 'approve_forums', 'visibility_sql_overwrite');
        extract($this->src_dispatcher->trigger_event('core.src_content_visibility_get_global_visibility_before', compact($vars)));
        if ($visibility_sql_overwrite) {
            return $visibility_sql_overwrite;
        }
        if (sizeof($exclude_forum_ids)) {
            $where_sqls[] = '(' . $this->db->sql_in_set($table_alias . 'forum_id', $exclude_forum_ids, true) . '
				AND ' . $table_alias . $mode . '_visibility = ' . ITEM_APPROVED . ')';
        } else {
            $where_sqls[] = $table_alias . $mode . '_visibility = ' . ITEM_APPROVED;
        }
        if (sizeof($approve_forums)) {
            $where_sqls[] = $this->db->sql_in_set($table_alias . 'forum_id', $approve_forums);
            return '(' . implode(' OR ', $where_sqls) . ')';
        }
        // There is only one element, so we just return that one
        return $where_sqls[0];
    }
예제 #3
0
    /**
     * Submit profile field for validation
     */
    public function submit_cp_field($mode, $lang_id, &$cp_data, &$cp_error)
    {
        $sql_where = '';
        switch ($mode) {
            case 'register':
                // If the field is required we show it on the registration page
                $sql_where .= ' AND f.field_show_on_reg = 1';
                break;
            case 'profile':
                // Show hidden fields to moderators/admins
                if (!$this->auth->acl_gets('a_', 'm_') && !$this->auth->acl_getf_global('m_')) {
                    $sql_where .= ' AND f.field_show_profile = 1';
                }
                break;
            default:
                trigger_error('Wrong profile mode specified', E_USER_ERROR);
                break;
        }
        $sql = 'SELECT l.*, f.*
			FROM ' . $this->fields_language_table . ' l, ' . $this->fields_table . ' f
			WHERE l.lang_id = ' . (int) $lang_id . "\n\t\t\t\tAND f.field_active = 1\n\t\t\t\t{$sql_where}\n\t\t\t\tAND l.field_id = f.field_id\n\t\t\tORDER BY f.field_order";
        $result = $this->db->sql_query($sql);
        while ($row = $this->db->sql_fetchrow($result)) {
            $profile_field = $this->type_collection[$row['field_type']];
            $cp_data['pf_' . $row['field_ident']] = $profile_field->get_profile_field($row);
            $check_value = $cp_data['pf_' . $row['field_ident']];
            if (($cp_result = $profile_field->validate_profile_field($check_value, $row)) !== false) {
                // If the result is not false, it's an error message
                $cp_error[] = $cp_result;
            }
        }
        $this->db->sql_freeresult($result);
    }
예제 #4
0
 function get_moderator_approve_forums()
 {
     static $forum_ids;
     if (!isset($forum_ids)) {
         $forum_ids = array_keys($this->auth->acl_getf('m_approve', true));
     }
     return $forum_ids;
 }
예제 #5
0
 /**
  * Get a list of users that are authorised to receive notifications
  *
  * @param array $users Array of users that have subscribed to a notification
  * @param int $forum_id Forum ID of the forum
  * @param array $options Array of notification options
  * @param bool $sort Whether the users array should be sorted. Default: false
  * @return array Array of users that are authorised recipients
  */
 protected function get_authorised_recipients($users, $forum_id, $options, $sort = false)
 {
     if (empty($users)) {
         return array();
     }
     $users = array_unique($users);
     if ($sort) {
         sort($users);
     }
     $auth_read = $this->auth->acl_get_list($users, 'f_read', $forum_id);
     if (empty($auth_read)) {
         return array();
     }
     return $this->check_user_notification_options($auth_read[$forum_id]['f_read'], $options);
 }
예제 #6
0
    /**
     * 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;
    }
예제 #7
0
/**
* 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() . '&amp;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);
}
예제 #8
0
 /**
  * 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('&quot;', '"', $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('&quot;', '"', $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('&quot;', '"', $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('&quot;', '"', $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;
 }
예제 #9
0
    /**
     * Permission Unset
     *
     * Allows you to unset (remove) permissions for a certain group/role
     *
     * @param string $name The name of the role/group
     * @param string|array $auth_option The auth_option or array of
     * 	auth_options you would like to set
     * @param string $type The type (role|group)
     * @return null
     * @throws \src\db\migration\exception
     */
    public function permission_unset($name, $auth_option, $type = 'role')
    {
        if (!is_array($auth_option)) {
            $auth_option = array($auth_option);
        }
        $to_remove = array();
        $sql = 'SELECT auth_option_id
			FROM ' . ACL_OPTIONS_TABLE . '
			WHERE ' . $this->db->sql_in_set('auth_option', $auth_option);
        $result = $this->db->sql_query($sql);
        while ($row = $this->db->sql_fetchrow($result)) {
            $to_remove[] = (int) $row['auth_option_id'];
        }
        $this->db->sql_freeresult($result);
        if (empty($to_remove)) {
            return;
        }
        $type = (string) $type;
        // Prevent PHP bug.
        switch ($type) {
            case 'role':
                $sql = 'SELECT role_id
					FROM ' . ACL_ROLES_TABLE . "\n\t\t\t\t\tWHERE role_name = '" . $this->db->sql_escape($name) . "'";
                $this->db->sql_query($sql);
                $role_id = (int) $this->db->sql_fetchfield('role_id');
                if (!$role_id) {
                    throw new \src\db\migration\exception('ROLE_NOT_EXIST', $name);
                }
                $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . '
					WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove) . '
						AND role_id = ' . (int) $role_id;
                $this->db->sql_query($sql);
                break;
            case 'group':
                $sql = 'SELECT group_id
					FROM ' . GROUPS_TABLE . "\n\t\t\t\t\tWHERE group_name = '" . $this->db->sql_escape($name) . "'";
                $this->db->sql_query($sql);
                $group_id = (int) $this->db->sql_fetchfield('group_id');
                if (!$group_id) {
                    throw new \src\db\migration\exception('GROUP_NOT_EXIST', $name);
                }
                // If the group has a role set for them we will remove the requested permissions from that role.
                $sql = 'SELECT auth_role_id
					FROM ' . ACL_GROUPS_TABLE . '
					WHERE group_id = ' . $group_id . '
						AND auth_role_id <> 0';
                $this->db->sql_query($sql);
                $role_id = (int) $this->db->sql_fetchfield('auth_role_id');
                if ($role_id) {
                    $sql = 'SELECT role_name
						FROM ' . ACL_ROLES_TABLE . '
						WHERE role_id = ' . $role_id;
                    $this->db->sql_query($sql);
                    $role_name = $this->db->sql_fetchfield('role_name');
                    return $this->permission_unset($role_name, $auth_option, 'role');
                }
                $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . '
					WHERE ' . $this->db->sql_in_set('auth_option_id', $to_remove);
                $this->db->sql_query($sql);
                break;
        }
        $this->auth->acl_clear_prefetch();
    }
예제 #10
0
/**
* 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');
    }
}