This section contains detailed articles elaborating on some of the common issues phpBB users encounter while using the product. Articles submitted by members of the community are checked for accuracy by the relevant phpBB Team. If you do not find the answer to your question here, we recommend looking through the Support Section as well as using the Site Wide Search.

Permission System Overview For MOD Authors - Part Two

Description: A overview of permissions system that is geared towards MOD authors

In Categories:

Link to this article: Select All
[url=https://www.phpbb.com/support/docs/en/3.0/kb/article/permission-system-overview-for-mod-authors-part-two/]Knowledge Base - Permission System Overview For MOD Authors - Part Two[/url]

This permissions guide is in two parts due a limitation on article lengths in the Knowledge base. The first part of this guide can be found here

What are permission masks?
Masks are the effective permissions your user has for the different type of permission as we described already. You have user permissions, moderator permissions both local & global, forum permissions & administrator permissions. So for each of these you have a permission mask which can be viewed in the ACP. For forum permissions & moderator local permissions you need to select the forum you want to check first.

How do I workout permission masks?
From the "PERMISSIONS" tab select from "View administrative permissions", "View user-based permissions", "View global moderation permissions", "View forum moderation permissions" & "View forum-based permissions". If you select either of the last two you will first need to select the forum for which you are trying to view for. When viewing masks you can view for multiple/single user(s) or group(s). Permission for a group are set. However since permissions for a user can come from multiple groups you can trace the permission.

What is tracing a permission?
When viewing the mask of permissions for a user a icon( Image) appears beside each option will show how the option got its value. It will start with the default value and then work through each group the user is a member of and then also the user direct permission at the end. For each group or finally the user permission it looks at the setting and updates the total. Remember a NEVER will wipe out any YES and a YES can not overwrite a NEVER. This is a very handy tool to determine why a user is getting or not getting a permission. The final total is the effective permission for any option.

How do permissions get setup for a page when a user views it?
When a users (remember bots & guests are still users) views a page a session is started with $user->session_begin(); Next you call the following $auth->acl($user->data); this will setup the users permission. This $auth->acl function checks to work out if the user_permission field we mentioned early needs updated. When permissions are updated via the ACP this field is cleared. If you only set a user permission then only that user has it clear otherwise it is cleared for all users. So on next login the acl function has to repopulate it with new permission options for user. It first checks the cache for _acl_options and updates if needed and then rebuilds the users permissions. Else if the cache is OK but the user permissions is empty it rebuilds just the users permissions. If the cache is OK and the user permissions is OK the field is left alone. The field is then turned from a bitstring into an array and it is this array we check against when checking a users permissions.

So what does the acl_options cache contain?
This cache contains an array which has two elements - local & global. Each of these is an array that contains each of the acl options of that type. As with all cache it checks if the cache is within a valid time frame, if the time frame is OK it will setup the array else just return.

So now the page has my users permissions setup how do I check if a user has a single permission option?
You call the $auth->acl_get('u_garage_browse'); and the argument is the option you want to check for If it was specific to a forum (i.e local) then you do it as $auth->acl_get('u_garage_browse', 3); where 3 is the forum id

I have created a forum specific option. How do I find out which forums a user has this set for?
You call the $auth->acl_getf('f_your_permission');

Can I check for more than one option?
Yes. By using $auth->acl_gets(option1[, option2, ..., optionN, forum]);

How do I add a permission on my own for a MOD?
Firstly you need to understand there are two parts to adding a permission.
* Database
* Language

To add to the DB you should always use the native functions. As they handle cache etc..

Code: Select all

        <?php
        define
('IN_PHPBB'true);
        
$phpbb_root_path './';
        
$phpEx substr(strrchr(__FILE__'.'), 1);
        include(
$phpbb_root_path 'common.' $phpEx);
        
$user->session_begin();
        
$auth->acl($user->data);
        
$user->setup();
        include(
$phpbb_root_path 'includes/acp/auth.' $phpEx);
        
$auth_admin = new auth_admin();

        
$auth_admin->acl_add_option(array(
            
'local'      => array(),
            
'global'   => array('u_your_mod''m_your_mod')
        ));
        
?>
This code will setup two new global permission, one a user permission and the other a moderator permission. Now you need to setup the language side.

Code: Select all

        <?php
        
if (empty($lang) || !is_array($lang))
        {
            
$lang = array();
        }

        
$lang['permission_cat']['your_mod'] = 'My amazing MOD';

        
$lang array_merge($lang, array(
            
'acl_u_your_mod'    => array('lang' => 'Can use amazing MOD''cat' => 'your_mod'),
            
'acl_m_your_mod'    => array('lang' => 'Can moderate amazing MOD''cat' => 'your_mod'),
        ));
        
?>


How do I make my MOD installer setup permission automatically?
By default you can not. As we learnt above when phpBB updates permissions for users/groups/roles it works out the complete permissions and updates as a multi-insert. This approach is just too much for a MOD to try do. Please note this is not standard phpBB. A simple approach is to use functions such as the ones below. The functions check if the user/group/role already has the permission and if so does not insert it, if not it inserts the option and clears the cache. There are three functions provided below, one for user, group, role. Each works in the same way. First is whether you are granting or removing, then you pass a username, group name or role name as the second variable and an array of permissions you want to assign/remove as the third, a four variable sets the ACL_YES|ACL_NO|ACL_NEVER that we also talked about early.

Code: Select all

        <?php
        
//examples of granting user, group & role
        
update_user_permissions('grant'$username, array('u_your_mod''m_your_mod'));
        
update_group_permissions('grant',$group_name, array('u_your_mod''m_your_mod') );
        
update_role_permissions('grant',$role_name, array('u_your_mod''m_your_mod') );
        
//examples of removing user, group & role
        
update_user_permissions('remove'$username, array('u_your_mod''m_your_mod'));
        
update_group_permissions('remove',$group_name, array('u_your_mod''m_your_mod') );
        
update_role_permissions('remove',$role_name, array('u_your_mod''m_your_mod') );
        
?>
So now here are each of the functions, you can include them in your installation scripts and call them as above

User Permission Update

Code: Select all

        <?php
        
/**
        * Update role-specific ACL options. Function can grant or remove options. If option already granted it will NOT be updated.
        *
        * @param grant|remove $mode defines whether roles are granted to removed
        * @param strong $role_name role name to update
        * @param mixed $options auth_options to grant (a auth_option has to be specified)
        * @param ACL_YES|ACL_NO|ACL_NEVER $auth_setting defines the mode acl_options are getting set with
        *
        */
        
function update_user_permissions($mode 'grant'$username$options = array(), $auth_setting ACL_YES)
        {
            global 
$db$auth$cache;

            
//First We Get User ID
            
$sql "SELECT u.user_id
                FROM " 
USERS_TABLE " u
                WHERE username = '$username'"
;
            
$result $db->sql_query($sql);
            
$user_id = (int) $db->sql_fetchfield('user_id');
            
$db->sql_freeresult($result);

            
//Now Lets Get All Current Options For User
            
$user_options = array();
            
$sql "SELECT auth_option_id
                FROM " 
ACL_USERS_TABLE "
                WHERE user_id = " 
. (int) $user_id "
                GROUP BY auth_option_id"
;
            
$result $db->sql_query($sql);
            while (
$row $db->sql_fetchrow($result))
            {
                
$user_options[] = $row;
            }
            
$db->sql_freeresult($result);

            
//Get Option ID Values For Options Granting Or Removing
            
$acl_options_ids = array();
            
$sql "SELECT auth_option_id
                FROM " 
ACL_OPTIONS_TABLE "
                WHERE " 
$db->sql_in_set('auth_option'$options) . "
                GROUP BY auth_option_id"
;
            
$result $db->sql_query($sql);
            while (
$row $db->sql_fetchrow($result))
            {
                
$acl_options_ids[] = $row;
            }
            
$db->sql_freeresult($result);


            
//If Granting Permissions
            
if ($mode == 'grant')
            {
                
//Make Sure We Have Option IDs
                
if (empty($acl_options_ids))
                {
                    return 
false;
                }
                
                
//Build SQL Array For Query
                
$sql_ary = array();
                for (
$i 0$count sizeof($acl_options_ids);$i $count$i++)
                {

                    
//If Option Already Granted To User Then Skip It
                    
if (in_array($acl_options_ids[$i]['auth_option_id'], $user_options))
                    {
                        continue;
                    }
                    
$sql_ary[] = array(
                        
'user_id'        => (int) $user_id,
                        
'auth_option_id'    => (int) $acl_options_ids[$i]['auth_option_id'],
                        
'auth_setting'        => $auth_setting,
                    );
                }

                
$db->sql_multi_insert(ACL_USERS_TABLE$sql_ary);
                
$cache->destroy('acl_options');
                
$auth->acl_clear_prefetch();
            }

            
//If Removing Permissions
            
if ($mode == 'remove')
            {
                
//Make Sure We Have Option IDs
                
if (empty($acl_options_ids))
                {
                    return 
false;
                }
                
                
//Process Each Option To Remove
                
for ($i 0$count sizeof($acl_options_ids);$i $count$i++)
                {
                    
$sql "DELETE
                        FROM " 
ACL_USERS_TABLE "
                        WHERE auth_option_id = " 
$acl_options_ids[$i]['auth_option_id'];

                    
$db->sql_query($sql);
                }

                
$cache->destroy('acl_options');
                
$auth->acl_clear_prefetch();
            }

            return;
        }
        
?>


Group Permission Update

Code: Select all

        <?php
        
/**
        * Update group-specific ACL options. Function can grant or remove options. If option already granted it will NOT be updated.
        *
        * @param grant|remove $mode defines whether roles are granted to removed
        * @param string $group_name group name to update
        * @param mixed $options auth_options to grant (a auth_option has to be specified)
        * @param ACL_YES|ACL_NO|ACL_NEVER $auth_setting defines the mode acl_options are getting set with
        *
        */
        
function update_group_permissions($mode 'grant'$group_name$options = array(), $auth_setting ACL_YES)
        {
            global 
$db$auth$cache;

            
//First We Get Role ID
            
$sql "SELECT g.role_id
                FROM " 
GROUPS_TABLE " g
                WHERE group_name = '$group_name'"
;
            
$result $db->sql_query($sql);
            
$group_id = (int) $db->sql_fetchfield('group_id');
            
$db->sql_freeresult($result);

            
//Now Lets Get All Current Options For Role
            
$group_options = array();
            
$sql "SELECT auth_option_id
                FROM " 
ACL_GROUPS_TABLE "
                WHERE group_id = " 
. (int) $group_id "
                GROUP BY auth_option_id"
;
            
$result $db->sql_query($sql);
            while (
$row $db->sql_fetchrow($result))
            {
                
$group_options[] = $row;
            }
            
$db->sql_freeresult($result);

            
//Get Option ID Values For Options Granting Or Removing
            
$sql "SELECT auth_option_id
                FROM " 
ACL_OPTIONS_TABLE "
                WHERE " 
$db->sql_in_set('auth_option'$options) . "
                GROUP BY auth_option_id"
;
            
$result $db->sql_query($sql);
            while (
$row $db->sql_fetchrow($result))
            {
                
$acl_options_ids[] = $row;
            }
            
$db->sql_freeresult($result);


            
//If Granting Permissions
            
if ($mode == 'grant')
            {
                
//Make Sure We Have Option IDs
                
if (empty($acl_options_ids))
                {
                    return 
false;
                }
                
                
//Build SQL Array For Query
                
$sql_ary = array();
                for (
$i 0$count sizeof($acl_options_ids);$i $count$i++)
                {

                    
//If Option Already Granted To Role Then Skip It
                    
if (in_array($acl_options_ids[$i]['auth_option_id'], $group_options))
                    {
                        continue;
                    }
                    
$sql_ary[] = array(
                        
'group_id'        => (int) $group_id,
                        
'auth_option_id'    => (int) $acl_options_ids[$i]['auth_option_id'],
                        
'auth_setting'        => $auth_setting,
                    );
                }

                
$db->sql_multi_insert(ACL_GROUPS_TABLE$sql_ary);
                
$cache->destroy('acl_options');
                
$auth->acl_clear_prefetch();
            }

            
//If Removing Permissions
            
if ($mode == 'remove')
            {
                
//Make Sure We Have Option IDs
                
if (empty($acl_options_ids))
                {
                    return 
false;
                }
                
                
//Process Each Option To Remove
                
for ($i 0$count sizeof($acl_options_ids);$i $count$i++)
                {
                    
$sql "DELETE
                        FROM " 
ACL_GROUPS_TABLE "
                        WHERE auth_option_id = " 
$acl_options_ids[$i]['auth_option_id'];

                    
$db->sql_query($sql);
                }

                
$cache->destroy('acl_options');
                
$auth->acl_clear_prefetch();
            }

            return;
        }
        
?>


Role Permission Update

Code: Select all

        <?php
        
/**
        * Update role-specific ACL options. Function can grant or remove options. If option already granted it will NOT be updated.
        *
        * @param grant|remove $mode defines whether roles are granted to removed
        * @param strong $role_name role name to update
        * @param mixed $options auth_options to grant (a auth_option has to be specified)
        * @param ACL_YES|ACL_NO|ACL_NEVER $auth_setting defines the mode acl_options are getting set with
        *
        */
        
function update_role_permissions($mode 'grant'$role_name$options = array(), $auth_setting ACL_YES)
        {
            global 
$db$auth$cache;

            
//First We Get Role ID
            
$sql "SELECT r.role_id
                FROM " 
ACL_ROLES_TABLE " r
                WHERE role_name = '$role_name'"
;
            
$result $db->sql_query($sql);
            
$role_id = (int) $db->sql_fetchfield('role_id');
            
$db->sql_freeresult($result);

            
//Now Lets Get All Current Options For Role
            
$role_options = array();
            
$sql "SELECT auth_option_id
                FROM " 
ACL_ROLES_DATA_TABLE "
                WHERE role_id = " 
. (int) $role_id "
                GROUP BY auth_option_id"
;
            
$result $db->sql_query($sql);
            while (
$row $db->sql_fetchrow($result))
            {
                
$role_options[] = $row;
            }
            
$db->sql_freeresult($result);

            
//Get Option ID Values For Options Granting Or Removing
            
$acl_options_ids = array();
            
$sql "SELECT auth_option_id
                FROM " 
ACL_OPTIONS_TABLE "
                WHERE " 
$db->sql_in_set('auth_option'$options) . "
                GROUP BY auth_option_id"
;
            
$result $db->sql_query($sql);
            while (
$row $db->sql_fetchrow($result))
            {
                
$acl_options_ids[] = $row;
            }
            
$db->sql_freeresult($result);


            
//If Granting Permissions
            
if ($mode == 'grant')
            {
                
//Make Sure We Have Option IDs
                
if (empty($acl_options_ids))
                {
                    return 
false;
                }
                
                
//Build SQL Array For Query
                
$sql_ary = array();
                for (
$i 0$count sizeof($acl_options_ids);$i $count$i++)
                {

                    
//If Option Already Granted To Role Then Skip It
                    
if (in_array($acl_options_ids[$i]['auth_option_id'], $role_options))
                    {
                        continue;
                    }
                    
$sql_ary[] = array(
                        
'role_id'        => (int) $role_id,
                        
'auth_option_id'    => (int) $acl_options_ids[$i]['auth_option_id'],
                        
'auth_setting'        => $auth_setting,
                    );
                }

                
$db->sql_multi_insert(ACL_ROLES_DATA_TABLE$sql_ary);
                
$cache->destroy('acl_options');
                
$auth->acl_clear_prefetch();
            }

            
//If Removing Permissions
            
if ($mode == 'remove')
            {
                
//Make Sure We Have Option IDs
                
if (empty($acl_options_ids))
                {
                    return 
false;
                }
                
                
//Process Each Option To Remove
                
for ($i 0$count sizeof($acl_options_ids);$i $count$i++)
                {
                    
$sql "DELETE
                        FROM " 
ACL_ROLES_DATA_TABLE "
                        WHERE auth_option_id = " 
$acl_options_ids[$i]['auth_option_id'];

                    
$db->sql_query($sql);
                }

                
$cache->destroy('acl_options');
                
$auth->acl_clear_prefetch();
            }

            return;
        }
        
?>