diff options
author | Meik Sievertsen <acydburn@phpbb.com> | 2008-02-15 19:10:02 +0000 |
---|---|---|
committer | Meik Sievertsen <acydburn@phpbb.com> | 2008-02-15 19:10:02 +0000 |
commit | 9e55e1738874a0ab352f91a15012b33fe1c3e9f9 (patch) | |
tree | 09ca4ced265a499b0fcb64a4560e1c9a7afba20d | |
parent | Update (diff) | |
download | phpbb-9e55e1738874a0ab352f91a15012b33fe1c3e9f9.tar.gz phpbb-9e55e1738874a0ab352f91a15012b33fe1c3e9f9.tar.bz2 phpbb-9e55e1738874a0ab352f91a15012b33fe1c3e9f9.zip |
revamp how we query permissions. This is half-experimental actually, needs a bit of testing.
Should fix the bug with low max_join_size values, but may give problems for those on very low memory settings.
git-svn-id: file:///svn/phpbb/branches/phpBB-3_0_0@8384 89ea8834-ac86-4346-8a33-228a782c2dd0
-rw-r--r-- | phpBB/includes/acp/acp_permissions.php | 2 | ||||
-rw-r--r-- | phpBB/includes/acp/auth.php | 44 | ||||
-rw-r--r-- | phpBB/includes/auth.php | 424 | ||||
-rw-r--r-- | phpBB/includes/functions_admin.php | 23 | ||||
-rw-r--r-- | phpBB/install/database_update.php | 2 |
5 files changed, 282 insertions, 213 deletions
diff --git a/phpBB/includes/acp/acp_permissions.php b/phpBB/includes/acp/acp_permissions.php index 1b2b19d4ab..a19a350646 100644 --- a/phpBB/includes/acp/acp_permissions.php +++ b/phpBB/includes/acp/acp_permissions.php @@ -48,7 +48,7 @@ class acp_permissions $this->tpl_name = 'permission_trace'; - if ($user_id && isset($auth_admin->option_ids[$permission]) && $auth->acl_get('a_viewauth')) + if ($user_id && isset($auth_admin->acl_options['id'][$permission]) && $auth->acl_get('a_viewauth')) { $this->page_title = sprintf($user->lang['TRACE_PERMISSION'], $user->lang['acl_' . $permission]['lang']); $this->permission_trace($user_id, $forum_id, $permission); diff --git a/phpBB/includes/acp/auth.php b/phpBB/includes/acp/auth.php index 177c42f581..71872ceb6a 100644 --- a/phpBB/includes/acp/auth.php +++ b/phpBB/includes/acp/auth.php @@ -22,8 +22,6 @@ if (!defined('IN_PHPBB')) */ class auth_admin extends auth { - var $option_ids = array(); - /** * Init auth settings */ @@ -33,7 +31,7 @@ class auth_admin extends auth if (($this->acl_options = $cache->get('_acl_options')) === false) { - $sql = 'SELECT auth_option, is_global, is_local + $sql = 'SELECT auth_option_id, auth_option, is_global, is_local FROM ' . ACL_OPTIONS_TABLE . ' ORDER BY auth_option_id'; $result = $db->sql_query($sql); @@ -51,25 +49,14 @@ class auth_admin extends auth { $this->acl_options['local'][$row['auth_option']] = $local++; } + + $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id']; + $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option']; } $db->sql_freeresult($result); $cache->put('_acl_options', $this->acl_options); } - - if (!sizeof($this->option_ids)) - { - $sql = 'SELECT auth_option_id, auth_option - FROM ' . ACL_OPTIONS_TABLE; - $result = $db->sql_query($sql); - - $this->option_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $this->option_ids[$row['auth_option']] = $row['auth_option_id']; - } - $db->sql_freeresult($result); - } } /** @@ -779,7 +766,7 @@ class auth_admin extends auth $this->acl_clear_prefetch(); // Because we just changed the options and also purged the options cache, we instantly update/regenerate it for later calls to succeed. - $this->option_ids = $this->acl_options = array(); + $this->acl_options = array(); $this->auth_admin(); return true; @@ -817,7 +804,7 @@ class auth_admin extends auth $flag = substr($flag, 0, strpos($flag, '_') + 1); // This ID (the any-flag) is set if one or more permissions are true... - $any_option_id = (int) $this->option_ids[$flag]; + $any_option_id = (int) $this->acl_options['id'][$flag]; // Remove any-flag from auth ary if (isset($auth[$flag])) @@ -829,7 +816,7 @@ class auth_admin extends auth $auth_option_ids = array((int)$any_option_id); foreach ($auth as $auth_option => $auth_setting) { - $auth_option_ids[] = (int) $this->option_ids[$auth_option]; + $auth_option_ids[] = (int) $this->acl_options['id'][$auth_option]; } $sql = "DELETE FROM $table @@ -892,7 +879,7 @@ class auth_admin extends auth { foreach ($auth as $auth_option => $setting) { - $auth_option_id = (int) $this->option_ids[$auth_option]; + $auth_option_id = (int) $this->acl_options['id'][$auth_option]; if ($setting != ACL_NO) { @@ -948,7 +935,7 @@ class auth_admin extends auth $sql_ary = array(); foreach ($auth as $auth_option => $setting) { - $auth_option_id = (int) $this->option_ids[$auth_option]; + $auth_option_id = (int) $this->acl_options['id'][$auth_option]; if ($setting != ACL_NO) { @@ -965,7 +952,7 @@ class auth_admin extends auth { $sql_ary[] = array( 'role_id' => (int) $role_id, - 'auth_option_id' => (int) $this->option_ids[$flag], + 'auth_option_id' => (int) $this->acl_options['id'][$flag], 'auth_setting' => ACL_NEVER ); } @@ -1242,13 +1229,8 @@ class auth_admin extends auth return false; } - $hold_ary = $this->acl_raw_data($from_user_id, false, false); + $hold_ary = $this->acl_raw_data_single_user($from_user_id); - if (isset($hold_ary[$from_user_id])) - { - $hold_ary = $hold_ary[$from_user_id]; - } - // Key 0 in $hold_ary are global options, all others are forum_ids // We disallow copying admin permissions @@ -1256,12 +1238,12 @@ class auth_admin extends auth { if (strpos($opt, 'a_') === 0) { - $hold_ary[0][$opt] = ACL_NEVER; + $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_NEVER; } } // Force a_switchperm to be allowed - $hold_ary[0]['a_switchperm'] = ACL_YES; + $hold_ary[0][$this->acl_options['id']['a_switchperm']] = ACL_YES; $user_permissions = $this->build_bitstring($hold_ary); diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php index c965149018..03f2a92ef8 100644 --- a/phpBB/includes/auth.php +++ b/phpBB/includes/auth.php @@ -39,7 +39,7 @@ class auth if (($this->acl_options = $cache->get('_acl_options')) === false) { - $sql = 'SELECT auth_option, is_global, is_local + $sql = 'SELECT auth_option_id, auth_option, is_global, is_local FROM ' . ACL_OPTIONS_TABLE . ' ORDER BY auth_option_id'; $result = $db->sql_query($sql); @@ -57,6 +57,9 @@ class auth { $this->acl_options['local'][$row['auth_option']] = $local++; } + + $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id']; + $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option']; } $db->sql_freeresult($result); @@ -302,7 +305,14 @@ class auth */ function acl_get_list($user_id = false, $opts = false, $forum_id = false) { - $hold_ary = $this->acl_raw_data($user_id, $opts, $forum_id); + if ($user_id !== false && !is_array($user_id) && $opts === false && $forum_id === false) + { + $hold_ary = array($user_id => $this->acl_raw_data_single_user($user_id)); + } + else + { + $hold_ary = $this->acl_raw_data($user_id, $opts, $forum_id); + } $auth_ary = array(); foreach ($hold_ary as $user_id => $forum_ary) @@ -332,12 +342,7 @@ class auth // Empty user_permissions $userdata['user_permissions'] = ''; - $hold_ary = $this->acl_raw_data($userdata['user_id'], false, false); - - if (isset($hold_ary[$userdata['user_id']])) - { - $hold_ary = $hold_ary[$userdata['user_id']]; - } + $hold_ary = $this->acl_raw_data_single_user($userdata['user_id']); // Key 0 in $hold_ary are global options, all others are forum_ids @@ -348,42 +353,11 @@ class auth { if (strpos($opt, 'a_') === 0) { - $hold_ary[0][$opt] = ACL_YES; + $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_YES; } } } - // Sometimes, it can happen $hold_ary holding forums which do not exist. - // Since this function is not called that often (we are caching the data) we check for this inconsistency. - $sql = 'SELECT forum_id - FROM ' . FORUMS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', array_keys($hold_ary), false, true); - $result = $db->sql_query($sql); - - $forum_ids = (isset($hold_ary[0])) ? array(0) : array(); - while ($row = $db->sql_fetchrow($result)) - { - $forum_ids[] = $row['forum_id']; - } - $db->sql_freeresult($result); - - // Now determine forums which do not exist and remove the unneeded information (for modding purposes it is clearly the wrong place. ;)) - $missing_forums = array_diff(array_keys($hold_ary), $forum_ids); - - if (sizeof($missing_forums)) - { - foreach ($missing_forums as $forum_id) - { - unset($hold_ary[$forum_id]); - } - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $missing_forums); - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $missing_forums); - $db->sql_query($sql); - } - $hold_str = $this->build_bitstring($hold_ary); if ($hold_str) @@ -420,15 +394,15 @@ class auth $bitstring = array(); foreach ($this->acl_options[$ary_key] as $opt => $id) { - if (isset($auth_ary[$opt])) + if (isset($auth_ary[$this->acl_options['id'][$opt]])) { - $bitstring[$id] = $auth_ary[$opt]; + $bitstring[$id] = $auth_ary[$this->acl_options['id'][$opt]]; $option_key = substr($opt, 0, strpos($opt, '_') + 1); // If one option is allowed, the global permission for this option has to be allowed too // example: if the user has the a_ permission this means he has one or more a_* permissions - if ($auth_ary[$opt] == ACL_YES && (!isset($bitstring[$this->acl_options[$ary_key][$option_key]]) || $bitstring[$this->acl_options[$ary_key][$option_key]] == ACL_NEVER)) + if ($auth_ary[$this->acl_options['id'][$opt]] == ACL_YES && (!isset($bitstring[$this->acl_options[$ary_key][$option_key]]) || $bitstring[$this->acl_options[$ary_key][$option_key]] == ACL_NEVER)) { $bitstring[$this->acl_options[$ary_key][$option_key]] = ACL_YES; } @@ -466,8 +440,26 @@ class auth */ function acl_clear_prefetch($user_id = false) { - global $db; + global $db, $cache; + // Rebuild options cache + $cache->destroy('_role_cache'); + + $sql = 'SELECT * + FROM ' . ACL_ROLES_DATA_TABLE . ' + ORDER BY role_id ASC'; + $result = $db->sql_query($sql); + + $this->role_cache = array(); + while ($row = $db->sql_fetchrow($result)) + { + $this->role_cache[$row['role_id']][$row['auth_option_id']] = (bool) $row['auth_setting']; + } + $db->sql_freeresult($result); + + $cache->put('_role_cache', $this->role_cache); + + // Now empty user permissions $where_sql = ''; if ($user_id !== false) @@ -528,103 +520,71 @@ class auth $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : ''; $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : ''; - $sql_opts = ''; + $sql_opts = $sql_opts_select = $sql_opts_from = ''; + $hold_ary = array(); if ($opts !== false) { + $sql_opts_select = ', ao.auth_option'; + $sql_opts_from = ', ' . ACL_OPTIONS_TABLE . ' ao'; $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts); } - $hold_ary = array(); + $sql_ary = array(); - // First grab user settings ... each user has only one setting for each - // option ... so we shouldn't need any ACL_NEVER checks ... he says ... - // Grab assigned roles... - $sql = $db->sql_build_query('SELECT', array( - 'SELECT' => 'ao.auth_option, a.auth_role_id, r.auth_setting as role_auth_setting, a.user_id, a.forum_id, a.auth_setting', - - 'FROM' => array( - ACL_OPTIONS_TABLE => 'ao', - ACL_USERS_TABLE => 'a' - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id' - ) - ), - - 'WHERE' => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id) - ' . (($sql_user) ? 'AND a.' . $sql_user : '') . " + // Grab non-role settings - user-specific + $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . ' + FROM ' . ACL_USERS_TABLE . ' a' . $sql_opts_from . ' + WHERE a.auth_role_id = 0 ' . + (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . + (($sql_user) ? 'AND a.' . $sql_user : '') . " $sql_forum - $sql_opts", - )); - $result = $db->sql_query($sql); + $sql_opts"; + + // Now the role settings - user-specific + $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . ' + FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . ' + WHERE a.auth_role_id = r.role_id ' . + (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . + (($sql_user) ? 'AND a.' . $sql_user : '') . " + $sql_forum + $sql_opts"; - while ($row = $db->sql_fetchrow($result)) + foreach ($sql_ary as $sql) { - $setting = ($row['auth_role_id']) ? $row['role_auth_setting'] : $row['auth_setting']; - $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $setting; - } - $db->sql_freeresult($result); - - // Now grab group settings ... ACL_NEVER overrides ACL_YES so act appropriatley - $sql_ary[] = $db->sql_build_query('SELECT', array( - 'SELECT' => 'ug.user_id, ao.auth_option, a.forum_id, a.auth_setting, a.auth_role_id, r.auth_setting as role_auth_setting', + $result = $db->sql_query($sql); - 'FROM' => array( - USER_GROUP_TABLE => 'ug', - ACL_OPTIONS_TABLE => 'ao', - ACL_GROUPS_TABLE => 'a' - ), + while ($row = $db->sql_fetchrow($result)) + { + $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']]; + $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting']; + } + $db->sql_freeresult($result); + } - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id' - ) - ), + $sql_ary = array(); - 'WHERE' => 'ao.auth_option_id = a.auth_option_id + // Now grab group settings - non-role specific... + $sql_ary[] = 'SELECT ug.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . ' + FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug' . $sql_opts_from . ' + WHERE a.auth_role_id = 0 ' . + (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . ' AND a.group_id = ug.group_id AND ug.user_pending = 0 ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . " $sql_forum - $sql_opts" - )); - - $sql_ary[] = $db->sql_build_query('SELECT', array( - 'SELECT' => 'ug.user_id, a.forum_id, a.auth_setting, a.auth_role_id, r.auth_setting as role_auth_setting, ao.auth_option' , - - 'FROM' => array( - ACL_OPTIONS_TABLE => 'ao' - - ), - - 'LEFT_JOIN' => array( - - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'r.auth_option_id = ao.auth_option_id' - ), - array( - 'FROM' => array(ACL_GROUPS_TABLE => 'a'), - 'ON' => 'a.auth_role_id = r.role_id' - ), - array( - 'FROM' => array(USER_GROUP_TABLE => 'ug'), - 'ON' => 'ug.group_id = a.group_id' - ) - - ), + $sql_opts"; - 'WHERE' => 'ug.user_pending = 0 + // Now grab group settings - role specific... + $sql_ary[] = 'SELECT ug.user_id, a.forum_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . ' + FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . ' + WHERE a.auth_role_id = r.role_id ' . + (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . ' + AND a.group_id = ug.group_id + AND ug.user_pending = 0 ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . " $sql_forum - $sql_opts" - )); - + $sql_opts"; foreach ($sql_ary as $sql) { @@ -632,24 +592,26 @@ class auth while ($row = $db->sql_fetchrow($result)) { - if (!isset($hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']]) || (isset($hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']]) && $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] != ACL_NEVER)) + $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']]; + + if (!isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) || (isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) && $hold_ary[$row['user_id']][$row['forum_id']][$option] != ACL_NEVER)) { - $setting = ($row['auth_role_id']) ? $row['role_auth_setting'] : $row['auth_setting']; - $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $setting; - - // Check for existence of ACL_YES if an option got set to ACL_NEVER - if ($setting == ACL_NEVER) + $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting']; + + // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again) + if ($row['auth_setting'] == ACL_NEVER) { - $flag = substr($row['auth_option'], 0, strpos($row['auth_option'], '_') + 1); + $flag = substr($option, 0, strpos($option, '_') + 1); if (isset($hold_ary[$row['user_id']][$row['forum_id']][$flag]) && $hold_ary[$row['user_id']][$row['forum_id']][$flag] == ACL_YES) { unset($hold_ary[$row['user_id']][$row['forum_id']][$flag]); - - if (in_array(ACL_YES, $hold_ary[$row['user_id']][$row['forum_id']])) + +/* if (in_array(ACL_YES, $hold_ary[$row['user_id']][$row['forum_id']])) { $hold_ary[$row['user_id']][$row['forum_id']][$flag] = ACL_YES; } +*/ } } } @@ -671,45 +633,43 @@ class auth $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : ''; $sql_opts = ''; + $hold_ary = $sql_ary = array(); if ($opts !== false) { $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts); } - $hold_ary = array(); - - // Grab user settings... - $sql = $db->sql_build_query('SELECT', array( - 'SELECT' => 'ao.auth_option, a.auth_role_id, r.auth_setting as role_auth_setting, a.user_id, a.forum_id, a.auth_setting', - - 'FROM' => array( - ACL_OPTIONS_TABLE => 'ao', - ACL_USERS_TABLE => 'a' - ), - - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id' - ), - ), - - 'WHERE' => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id) - ' . (($sql_user) ? 'AND a.' . $sql_user : '') . " + // Grab user settings - non-role specific... + $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option + FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao + WHERE a.auth_role_id = 0 + AND a.auth_option_id = ao.auth_option_id ' . + (($sql_user) ? 'AND a.' . $sql_user : '') . " $sql_forum - $sql_opts", + $sql_opts + ORDER BY a.forum_id, ao.auth_option"; - 'ORDER_BY' => 'a.forum_id, ao.auth_option' - )); - $result = $db->sql_query($sql); + // Now the role settings - user-specific + $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id, ao.auth_option + FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao + WHERE a.auth_role_id = r.role_id + AND r.auth_option_id = ao.auth_option_id ' . + (($sql_user) ? 'AND a.' . $sql_user : '') . " + $sql_forum + $sql_opts + ORDER BY a.forum_id, ao.auth_option"; - while ($row = $db->sql_fetchrow($result)) + foreach ($sql_ary as $sql) { - $setting = ($row['auth_role_id']) ? $row['role_auth_setting'] : $row['auth_setting']; - $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $setting; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting']; + } + $db->sql_freeresult($result); } - $db->sql_freeresult($result); return $hold_ary; } @@ -725,43 +685,118 @@ class auth $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : ''; $sql_opts = ''; + $hold_ary = $sql_ary = array(); if ($opts !== false) { $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts); } - $hold_ary = array(); + // Grab group settings - non-role specific... + $sql_ary[] = 'SELECT a.group_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option + FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao + WHERE a.auth_role_id = 0 + AND a.auth_option_id = ao.auth_option_id ' . + (($sql_group) ? 'AND a.' . $sql_group : '') . " + $sql_forum + $sql_opts + ORDER BY a.forum_id, ao.auth_option"; + + // Now grab group settings - role specific... + $sql_ary[] = 'SELECT a.group_id, a.forum_id, r.auth_setting, r.auth_option_id, ao.auth_option + FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao + WHERE a.auth_role_id = r.role_id + AND r.auth_option_id = ao.auth_option_id ' . + (($sql_group) ? 'AND a.' . $sql_group : '') . " + $sql_forum + $sql_opts + ORDER BY a.forum_id, ao.auth_option"; + + foreach ($sql_ary as $sql) + { + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting']; + } + $db->sql_freeresult($result); + } - // Grab group settings... - $sql = $db->sql_build_query('SELECT', array( - 'SELECT' => 'a.group_id, ao.auth_option, a.forum_id, a.auth_setting, a.auth_role_id, r.auth_setting as role_auth_setting', + return $hold_ary; + } - 'FROM' => array( - ACL_OPTIONS_TABLE => 'ao', - ACL_GROUPS_TABLE => 'a' - ), + /** + * Get raw acl data based on user for caching user_permissions + * This function returns the same data as acl_raw_data(), but without the user id as the first key within the array. + */ + function acl_raw_data_single_user($user_id) + { + global $db, $cache; - 'LEFT_JOIN' => array( - array( - 'FROM' => array(ACL_ROLES_DATA_TABLE => 'r'), - 'ON' => 'a.auth_role_id = r.role_id' - ), - ), + // Check if the role-cache is there + if (($this->role_cache = $cache->get('_role_cache')) === false) + { + $this->role_cache = array(); - 'WHERE' => '(ao.auth_option_id = a.auth_option_id OR ao.auth_option_id = r.auth_option_id) - ' . (($sql_group) ? 'AND a.' . $sql_group : '') . " - $sql_forum - $sql_opts", + // We pre-fetch roles + $sql = 'SELECT * + FROM ' . ACL_ROLES_DATA_TABLE . ' + ORDER BY role_id ASC'; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $this->role_cache[$row['role_id']][$row['auth_option_id']] = (bool) $row['auth_setting']; + } + $db->sql_freeresult($result); + + $cache->put('_role_cache', $this->role_cache); + } + + $hold_ary = array(); - 'ORDER_BY' => 'a.forum_id, ao.auth_option' - )); + // Grab user-specific permission settings + $sql = 'SELECT forum_id, auth_option_id, auth_role_id, auth_setting + FROM ' . ACL_USERS_TABLE . ' + WHERE user_id = ' . $user_id; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $setting = ($row['auth_role_id']) ? $row['role_auth_setting'] : $row['auth_setting']; - $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $setting; + // If a role is assigned, assign all options included within this role. Else, only set this one option. + if ($row['auth_role_id']) + { + $hold_ary[$row['forum_id']] = (empty($hold_ary[$row['forum_id']])) ? $this->role_cache[$row['auth_role_id']] : $hold_ary[$row['forum_id']] + $this->role_cache[$row['auth_role_id']]; + } + else + { + $hold_ary[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting']; + } + } + $db->sql_freeresult($result); + + // Now grab group-specific permission settings + $sql = 'SELECT a.forum_id, a.auth_option_id, a.auth_role_id, a.auth_setting + FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug + WHERE a.group_id = ug.group_id + AND ug.user_pending = 0 + AND ug.user_id = ' . $user_id; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + if (!$row['auth_role_id']) + { + $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $row['auth_option_id'], $row['auth_setting']); + } + else + { + foreach ($this->role_cache[$row['auth_role_id']] as $option_id => $setting) + { + $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $option_id, $setting); + } + } } $db->sql_freeresult($result); @@ -769,6 +804,35 @@ class auth } /** + * Private function snippet for setting a specific piece of the hold_ary + */ + function _set_group_hold_ary(&$hold_ary, $option_id, $setting) + { + if (!isset($hold_ary[$option_id]) || (isset($hold_ary[$option_id]) && $hold_ary[$option_id] != ACL_NEVER)) + { + $hold_ary[$option_id] = $setting; + + // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again) + if ($setting == ACL_NEVER) + { + $flag = substr($this->acl_options['option'][$option_id], 0, strpos($this->acl_options['option'][$option_id], '_') + 1); + $flag = (int) $this->acl_options['id'][$flag]; + + if (isset($hold_ary[$flag]) && $hold_ary[$flag] == ACL_YES) + { + unset($hold_ary[$flag]); + +/* This is uncommented, because i suspect this being slightly wrong due to mixed permission classes being possible + if (in_array(ACL_YES, $hold_ary)) + { + $hold_ary[$flag] = ACL_YES; + }*/ + } + } + } + } + + /** * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him. */ function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0) diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 268eccbca4..7fd21948d0 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -2998,6 +2998,29 @@ function tidy_database() { global $db; + // Here we check permission consistency + + // Sometimes, it can happen permission tables having forums listed which do not exist + $sql = 'SELECT forum_id + FROM ' . FORUMS_TABLE; + $result = $db->sql_query($sql); + + $forum_ids = array(0); + while ($row = $db->sql_fetchrow($result)) + { + $forum_ids[] = $row['forum_id']; + } + $db->sql_freeresult($result); + + // Delete those rows from the acl tables not having listed the forums above + $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true); + $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_ids, true); + $db->sql_query($sql); + set_config('database_last_gc', time(), true); } diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 899384fb41..7eeca7dbb8 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -8,7 +8,7 @@ * */ -$updates_to_version = '3.0.0'; +$updates_to_version = '3.0.1-dev'; // Return if we "just include it" to find out for which version the database update is responsible for if (defined('IN_PHPBB') && defined('IN_INSTALL')) |