Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

auth.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 38.15 KiB


0001  <?php
0002  /**
0003  *
0004  * This file is part of the phpBB Forum Software package.
0005  *
0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
0007  * @license GNU General Public License, version 2 (GPL-2.0)
0008  *
0009  * For full copyright and license information, please see
0010  * the docs/CREDITS.txt file.
0011  *
0012  */
0013   
0014  /**
0015  * @ignore
0016  */
0017  if (!defined('IN_PHPBB'))
0018  {
0019      exit;
0020  }
0021   
0022  /**
0023  * ACP Permission/Auth class
0024  */
0025  class auth_admin extends \phpbb\auth\auth
0026  {
0027      /**
0028      * Init auth settings
0029      */
0030      function __construct()
0031      {
0032          global $db, $cache;
0033   
0034          if (($this->acl_options = $cache->get('_acl_options')) === false)
0035          {
0036              $sql = 'SELECT auth_option_id, auth_option, is_global, is_local
0037                  FROM ' . ACL_OPTIONS_TABLE . '
0038                  ORDER BY auth_option_id';
0039              $result = $db->sql_query($sql);
0040   
0041              $global = $local = 0;
0042              $this->acl_options = array();
0043              while ($row = $db->sql_fetchrow($result))
0044              {
0045                  if ($row['is_global'])
0046                  {
0047                      $this->acl_options['global'][$row['auth_option']] = $global++;
0048                  }
0049   
0050                  if ($row['is_local'])
0051                  {
0052                      $this->acl_options['local'][$row['auth_option']] = $local++;
0053                  }
0054   
0055                  $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id'];
0056                  $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option'];
0057              }
0058              $db->sql_freeresult($result);
0059   
0060              $cache->put('_acl_options', $this->acl_options);
0061          }
0062      }
0063   
0064      /**
0065      * Get permission mask
0066      * This function only supports getting permissions of one type (for example a_)
0067      *
0068      * @param set|view $mode defines the permissions we get, view gets effective permissions (checking user AND group permissions), set only gets the user or group permission set alone
0069      * @param mixed $user_id user ids to search for (a user_id or a group_id has to be specified at least)
0070      * @param mixed $group_id group ids to search for, return group related settings (a user_id or a group_id has to be specified at least)
0071      * @param mixed $forum_id forum_ids to search for. Defining a forum id also means getting local settings
0072      * @param string $auth_option the auth_option defines the permission setting to look for (a_ for example)
0073      * @param local|global $scope the scope defines the permission scope. If local, a forum_id is additionally required
0074      * @param ACL_NEVER|ACL_NO|ACL_YES $acl_fill defines the mode those permissions not set are getting filled with
0075      */
0076      function get_mask($mode, $user_id = false, $group_id = false, $forum_id = false, $auth_option = false, $scope = false, $acl_fill = ACL_NEVER)
0077      {
0078          global $db, $user;
0079   
0080          $hold_ary = array();
0081          $view_user_mask = ($mode == 'view' && $group_id === false) ? true : false;
0082   
0083          if ($auth_option === false || $scope === false)
0084          {
0085              return array();
0086          }
0087   
0088          $acl_user_function = ($mode == 'set') ? 'acl_user_raw_data' : 'acl_raw_data';
0089   
0090          if (!$view_user_mask)
0091          {
0092              if ($forum_id !== false)
0093              {
0094                  $hold_ary = ($group_id !== false) ? $this->acl_group_raw_data($group_id, $auth_option . '%', $forum_id) : $this->$acl_user_function($user_id, $auth_option . '%', $forum_id);
0095              }
0096              else
0097              {
0098                  $hold_ary = ($group_id !== false) ? $this->acl_group_raw_data($group_id, $auth_option . '%') : $this->$acl_user_function($user_id, $auth_option . '%', ($scope == 'global') ? 0 : false);
0099              }
0100          }
0101   
0102          // Make sure hold_ary is filled with every setting (prevents missing forums/users/groups)
0103          $ug_id = ($group_id !== false) ? ((!is_array($group_id)) ? array($group_id) : $group_id) : ((!is_array($user_id)) ? array($user_id) : $user_id);
0104          $forum_ids = ($forum_id !== false) ? ((!is_array($forum_id)) ? array($forum_id) : $forum_id) : (($scope == 'global') ? array(0) : array());
0105   
0106          // Only those options we need
0107          $compare_options = array_diff(preg_replace('/^((?!' . $auth_option . ').+)|(' . $auth_option . ')$/', '', array_keys($this->acl_options[$scope])), array(''));
0108   
0109          // If forum_ids is false and the scope is local we actually want to have all forums within the array
0110          if ($scope == 'local' && !count($forum_ids))
0111          {
0112              $sql = 'SELECT forum_id
0113                  FROM ' . FORUMS_TABLE;
0114              $result = $db->sql_query($sql, 120);
0115   
0116              while ($row = $db->sql_fetchrow($result))
0117              {
0118                  $forum_ids[] = (int) $row['forum_id'];
0119              }
0120              $db->sql_freeresult($result);
0121          }
0122   
0123          if ($view_user_mask)
0124          {
0125              $auth2 = null;
0126   
0127              $sql = 'SELECT user_id, user_permissions, user_type
0128                  FROM ' . USERS_TABLE . '
0129                  WHERE ' . $db->sql_in_set('user_id', $ug_id);
0130              $result = $db->sql_query($sql);
0131   
0132              while ($userdata = $db->sql_fetchrow($result))
0133              {
0134                  if ($user->data['user_id'] != $userdata['user_id'])
0135                  {
0136                      $auth2 = new \phpbb\auth\auth();
0137                      $auth2->acl($userdata);
0138                  }
0139                  else
0140                  {
0141                      global $auth;
0142                      $auth2 = &$auth;
0143                  }
0144   
0145                  $hold_ary[$userdata['user_id']] = array();
0146                  foreach ($forum_ids as $f_id)
0147                  {
0148                      $hold_ary[$userdata['user_id']][$f_id] = array();
0149                      foreach ($compare_options as $option)
0150                      {
0151                          $hold_ary[$userdata['user_id']][$f_id][$option] = $auth2->acl_get($option, $f_id);
0152                      }
0153                  }
0154              }
0155              $db->sql_freeresult($result);
0156   
0157              unset($userdata);
0158              unset($auth2);
0159          }
0160   
0161          foreach ($ug_id as $_id)
0162          {
0163              if (!isset($hold_ary[$_id]))
0164              {
0165                  $hold_ary[$_id] = array();
0166              }
0167   
0168              foreach ($forum_ids as $f_id)
0169              {
0170                  if (!isset($hold_ary[$_id][$f_id]))
0171                  {
0172                      $hold_ary[$_id][$f_id] = array();
0173                  }
0174              }
0175          }
0176   
0177          // Now, we need to fill the gaps with $acl_fill. ;)
0178   
0179          // Now switch back to keys
0180          if (count($compare_options))
0181          {
0182              $compare_options = array_combine($compare_options, array_fill(1, count($compare_options), $acl_fill));
0183          }
0184   
0185          // Defining the user-function here to save some memory
0186          $return_acl_fill = function () use ($acl_fill)
0187          {
0188              return $acl_fill;
0189          };
0190   
0191          // Actually fill the gaps
0192          if (count($hold_ary))
0193          {
0194              foreach ($hold_ary as $ug_id => $row)
0195              {
0196                  foreach ($row as $id => $options)
0197                  {
0198                      // Do not include the global auth_option
0199                      unset($options[$auth_option]);
0200   
0201                      // Not a "fine" solution, but at all it's a 1-dimensional
0202                      // array_diff_key function filling the resulting array values with zeros
0203                      // The differences get merged into $hold_ary (all permissions having $acl_fill set)
0204                      $hold_ary[$ug_id][$id] = array_merge($options,
0205   
0206                          array_map($return_acl_fill,
0207                              array_flip(
0208                                  array_diff(
0209                                      array_keys($compare_options), array_keys($options)
0210                                  )
0211                              )
0212                          )
0213                      );
0214                  }
0215              }
0216          }
0217          else
0218          {
0219              $hold_ary[($group_id !== false) ? $group_id : $user_id][(int) $forum_id] = $compare_options;
0220          }
0221   
0222          return $hold_ary;
0223      }
0224   
0225      /**
0226      * Get permission mask for roles
0227      * This function only supports getting masks for one role
0228      */
0229      function get_role_mask($role_id)
0230      {
0231          global $db;
0232   
0233          $hold_ary = array();
0234   
0235          // Get users having this role set...
0236          $sql = 'SELECT user_id, forum_id
0237              FROM ' . ACL_USERS_TABLE . '
0238              WHERE auth_role_id = ' . $role_id . '
0239              ORDER BY forum_id';
0240          $result = $db->sql_query($sql);
0241   
0242          while ($row = $db->sql_fetchrow($result))
0243          {
0244              $hold_ary[$row['forum_id']]['users'][] = $row['user_id'];
0245          }
0246          $db->sql_freeresult($result);
0247   
0248          // Now grab groups...
0249          $sql = 'SELECT group_id, forum_id
0250              FROM ' . ACL_GROUPS_TABLE . '
0251              WHERE auth_role_id = ' . $role_id . '
0252              ORDER BY forum_id';
0253          $result = $db->sql_query($sql);
0254   
0255          while ($row = $db->sql_fetchrow($result))
0256          {
0257              $hold_ary[$row['forum_id']]['groups'][] = $row['group_id'];
0258          }
0259          $db->sql_freeresult($result);
0260   
0261          return $hold_ary;
0262      }
0263   
0264      /**
0265      * Display permission mask (assign to template)
0266      */
0267      function display_mask($mode, $permission_type, &$hold_ary, $user_mode = 'user', $local = false, $group_display = true)
0268      {
0269          global $template, $user, $db, $phpbb_container;
0270   
0271          /* @var $phpbb_permissions \phpbb\permissions */
0272          $phpbb_permissions = $phpbb_container->get('acl.permissions');
0273   
0274          /** @var \phpbb\group\helper $group_helper */
0275          $group_helper = $phpbb_container->get('group_helper');
0276   
0277          // Define names for template loops, might be able to be set
0278          $tpl_pmask = 'p_mask';
0279          $tpl_fmask = 'f_mask';
0280          $tpl_category = 'category';
0281          $tpl_mask = 'mask';
0282   
0283          $l_acl_type = $phpbb_permissions->get_type_lang($permission_type, (($local) ? 'local' : 'global'));
0284   
0285          // Allow trace for viewing permissions and in user mode
0286          $show_trace = ($mode == 'view' && $user_mode == 'user') ? true : false;
0287   
0288          // Get names
0289          if ($user_mode == 'user')
0290          {
0291              $sql = 'SELECT user_id as ug_id, username as ug_name
0292                  FROM ' . USERS_TABLE . '
0293                  WHERE ' . $db->sql_in_set('user_id', array_keys($hold_ary)) . '
0294                  ORDER BY username_clean ASC';
0295          }
0296          else
0297          {
0298              $sql = 'SELECT group_id as ug_id, group_name as ug_name, group_type
0299                  FROM ' . GROUPS_TABLE . '
0300                  WHERE ' . $db->sql_in_set('group_id', array_keys($hold_ary)) . '
0301                  ORDER BY group_type DESC, group_name ASC';
0302          }
0303          $result = $db->sql_query($sql);
0304   
0305          $ug_names_ary = array();
0306          while ($row = $db->sql_fetchrow($result))
0307          {
0308              $ug_names_ary[$row['ug_id']] = ($user_mode == 'user') ? $row['ug_name'] : $group_helper->get_name($row['ug_name']);
0309          }
0310          $db->sql_freeresult($result);
0311   
0312          // Get used forums
0313          $forum_ids = array();
0314          foreach ($hold_ary as $ug_id => $row)
0315          {
0316              $forum_ids = array_merge($forum_ids, array_keys($row));
0317          }
0318          $forum_ids = array_unique($forum_ids);
0319   
0320          $forum_names_ary = array();
0321          if ($local)
0322          {
0323              $forum_names_ary = make_forum_select(false, false, true, false, false, false, true);
0324   
0325              // Remove the disabled ones, since we do not create an option field here...
0326              foreach ($forum_names_ary as $key => $value)
0327              {
0328                  if (!$value['disabled'])
0329                  {
0330                      continue;
0331                  }
0332                  unset($forum_names_ary[$key]);
0333              }
0334          }
0335          else
0336          {
0337              $forum_names_ary[0] = $l_acl_type;
0338          }
0339   
0340          // Get available roles
0341          $sql = 'SELECT *
0342              FROM ' . ACL_ROLES_TABLE . "
0343              WHERE role_type = '" . $db->sql_escape($permission_type) . "'
0344              ORDER BY role_order ASC";
0345          $result = $db->sql_query($sql);
0346   
0347          $roles = array();
0348          while ($row = $db->sql_fetchrow($result))
0349          {
0350              $roles[$row['role_id']] = $row;
0351          }
0352          $db->sql_freeresult($result);
0353   
0354          $cur_roles = $this->acl_role_data($user_mode, $permission_type, array_keys($hold_ary));
0355   
0356          // Build js roles array (role data assignments)
0357          $s_role_js_array = '';
0358   
0359          if (count($roles))
0360          {
0361              $s_role_js_array = array();
0362   
0363              // Make sure every role (even if empty) has its array defined
0364              foreach ($roles as $_role_id => $null)
0365              {
0366                  $s_role_js_array[$_role_id] = "\n" . 'role_options[' . $_role_id . '] = new Array();' . "\n";
0367              }
0368   
0369              $sql = 'SELECT r.role_id, o.auth_option, r.auth_setting
0370                  FROM ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' o
0371                  WHERE o.auth_option_id = r.auth_option_id
0372                      AND ' . $db->sql_in_set('r.role_id', array_keys($roles));
0373              $result = $db->sql_query($sql);
0374   
0375              while ($row = $db->sql_fetchrow($result))
0376              {
0377                  $flag = substr($row['auth_option'], 0, strpos($row['auth_option'], '_') + 1);
0378                  if ($flag == $row['auth_option'])
0379                  {
0380                      continue;
0381                  }
0382   
0383                  $s_role_js_array[$row['role_id']] .= 'role_options[' . $row['role_id'] . '][\'' . addslashes($row['auth_option']) . '\'] = ' . $row['auth_setting'] . '; ';
0384              }
0385              $db->sql_freeresult($result);
0386   
0387              $s_role_js_array = implode('', $s_role_js_array);
0388          }
0389   
0390          $template->assign_var('S_ROLE_JS_ARRAY', $s_role_js_array);
0391          unset($s_role_js_array);
0392   
0393          // Now obtain memberships
0394          $user_groups_default = $user_groups_custom = array();
0395          if ($user_mode == 'user' && $group_display)
0396          {
0397              $sql = 'SELECT group_id, group_name, group_type
0398                  FROM ' . GROUPS_TABLE . '
0399                  ORDER BY group_type DESC, group_name ASC';
0400              $result = $db->sql_query($sql);
0401   
0402              $groups = array();
0403              while ($row = $db->sql_fetchrow($result))
0404              {
0405                  $groups[$row['group_id']] = $row;
0406              }
0407              $db->sql_freeresult($result);
0408   
0409              $memberships = group_memberships(false, array_keys($hold_ary), false);
0410   
0411              // User is not a member of any group? Bad admin, bad bad admin...
0412              if ($memberships)
0413              {
0414                  foreach ($memberships as $row)
0415                  {
0416                      $user_groups_default[$row['user_id']][] = $group_helper->get_name($groups[$row['group_id']]['group_name']);
0417                  }
0418              }
0419              unset($memberships, $groups);
0420          }
0421   
0422          // If we only have one forum id to display or being in local mode and more than one user/group to display,
0423          // we switch the complete interface to group by user/usergroup instead of grouping by forum
0424          // To achieve this, we need to switch the array a bit
0425          if (count($forum_ids) == 1 || ($local && count($ug_names_ary) > 1))
0426          {
0427              $hold_ary_temp = $hold_ary;
0428              $hold_ary = array();
0429              foreach ($hold_ary_temp as $ug_id => $row)
0430              {
0431                  foreach ($forum_names_ary as $forum_id => $forum_row)
0432                  {
0433                      if (isset($row[$forum_id]))
0434                      {
0435                          $hold_ary[$forum_id][$ug_id] = $row[$forum_id];
0436                      }
0437                  }
0438              }
0439              unset($hold_ary_temp);
0440   
0441              foreach ($hold_ary as $forum_id => $forum_array)
0442              {
0443                  $content_array = $categories = array();
0444                  $this->build_permission_array($hold_ary[$forum_id], $content_array, $categories, array_keys($ug_names_ary));
0445   
0446                  $template->assign_block_vars($tpl_pmask, array(
0447                      'NAME'            => ($forum_id == 0) ? $forum_names_ary[0] : $forum_names_ary[$forum_id]['forum_name'],
0448                      'PADDING'        => ($forum_id == 0) ? '' : $forum_names_ary[$forum_id]['padding'],
0449   
0450                      'CATEGORIES'    => implode('</th><th>', $categories),
0451   
0452                      'L_ACL_TYPE'    => $l_acl_type,
0453   
0454                      'S_LOCAL'        => ($local) ? true : false,
0455                      'S_GLOBAL'        => (!$local) ? true : false,
0456                      'S_NUM_CATS'    => count($categories),
0457                      'S_VIEW'        => ($mode == 'view') ? true : false,
0458                      'S_NUM_OBJECTS'    => count($content_array),
0459                      'S_USER_MODE'    => ($user_mode == 'user') ? true : false,
0460                      'S_GROUP_MODE'    => ($user_mode == 'group') ? true : false)
0461                  );
0462   
0463                  foreach ($content_array as $ug_id => $ug_array)
0464                  {
0465                      // Build role dropdown options
0466                      $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
0467   
0468                      $role_options = array();
0469   
0470                      $s_role_options = '';
0471                      $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
0472   
0473                      foreach ($roles as $role_id => $role_row)
0474                      {
0475                          $role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']);
0476                          $role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
0477   
0478                          $title = ($role_description) ? ' title="' . $role_description . '"' : '';
0479                          $s_role_options .= '<option value="' . $role_id . '"' . (($role_id == $current_role_id) ? ' selected="selected"' : '') . $title . '>' . $role_name . '</option>';
0480   
0481                          $role_options[] = array(
0482                              'ID'    => $role_id,
0483                              'ROLE_NAME'    => $role_name,
0484                              'TITLE'        => $role_description,
0485                              'SELECTED'    => $role_id == $current_role_id,
0486                          );
0487                      }
0488   
0489                      if ($s_role_options)
0490                      {
0491                          $s_role_options = '<option value="0"' . ((!$current_role_id) ? ' selected="selected"' : '') . ' title="' . htmlspecialchars($user->lang['NO_ROLE_ASSIGNED_EXPLAIN'], ENT_COMPAT) . '">' . $user->lang['NO_ROLE_ASSIGNED'] . '</option>' . $s_role_options;
0492                      }
0493   
0494                      if (!$current_role_id && $mode != 'view')
0495                      {
0496                          $s_custom_permissions = false;
0497   
0498                          foreach ($ug_array as $key => $value)
0499                          {
0500                              if ($value['S_NEVER'] || $value['S_YES'])
0501                              {
0502                                  $s_custom_permissions = true;
0503                                  break;
0504                              }
0505                          }
0506                      }
0507                      else
0508                      {
0509                          $s_custom_permissions = false;
0510                      }
0511   
0512                      $template->assign_block_vars($tpl_pmask . '.' . $tpl_fmask, array(
0513                          'NAME'                => $ug_names_ary[$ug_id],
0514                          'UG_ID'                => $ug_id,
0515                          'S_ROLE_OPTIONS'    => $s_role_options,
0516                          'S_CUSTOM'            => $s_custom_permissions,
0517                          'FORUM_ID'            => $forum_id,
0518                          'S_ROLE_ID'            => $current_role_id,
0519                      ));
0520   
0521                      $template->assign_block_vars_array($tpl_pmask . '.' . $tpl_fmask . '.role_options', $role_options);
0522   
0523                      $this->assign_cat_array($ug_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace);
0524   
0525                      unset($content_array[$ug_id]);
0526                  }
0527   
0528                  unset($hold_ary[$forum_id]);
0529              }
0530          }
0531          else
0532          {
0533              foreach ($ug_names_ary as $ug_id => $ug_name)
0534              {
0535                  if (!isset($hold_ary[$ug_id]))
0536                  {
0537                      continue;
0538                  }
0539   
0540                  $content_array = $categories = array();
0541                  $this->build_permission_array($hold_ary[$ug_id], $content_array, $categories, array_keys($forum_names_ary));
0542   
0543                  $template->assign_block_vars($tpl_pmask, array(
0544                      'NAME'            => $ug_name,
0545                      'CATEGORIES'    => implode('</th><th>', $categories),
0546   
0547                      'USER_GROUPS_DEFAULT'    => ($user_mode == 'user' && isset($user_groups_default[$ug_id]) && count($user_groups_default[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_default[$ug_id]) : '',
0548                      'USER_GROUPS_CUSTOM'    => ($user_mode == 'user' && isset($user_groups_custom[$ug_id]) && count($user_groups_custom[$ug_id])) ? implode($user->lang['COMMA_SEPARATOR'], $user_groups_custom[$ug_id]) : '',
0549                      'L_ACL_TYPE'            => $l_acl_type,
0550   
0551                      'S_LOCAL'        => ($local) ? true : false,
0552                      'S_GLOBAL'        => (!$local) ? true : false,
0553                      'S_NUM_CATS'    => count($categories),
0554                      'S_VIEW'        => ($mode == 'view') ? true : false,
0555                      'S_NUM_OBJECTS'    => count($content_array),
0556                      'S_USER_MODE'    => ($user_mode == 'user') ? true : false,
0557                      'S_GROUP_MODE'    => ($user_mode == 'group') ? true : false)
0558                  );
0559   
0560                  foreach ($content_array as $forum_id => $forum_array)
0561                  {
0562                      // Build role dropdown options
0563                      $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
0564   
0565                      $role_options = array();
0566   
0567                      $current_role_id = (isset($cur_roles[$ug_id][$forum_id])) ? $cur_roles[$ug_id][$forum_id] : 0;
0568                      $s_role_options = '';
0569   
0570                      foreach ($roles as $role_id => $role_row)
0571                      {
0572                          $role_description = (!empty($user->lang[$role_row['role_description']])) ? $user->lang[$role_row['role_description']] : nl2br($role_row['role_description']);
0573                          $role_name = (!empty($user->lang[$role_row['role_name']])) ? $user->lang[$role_row['role_name']] : $role_row['role_name'];
0574   
0575                          $title = ($role_description) ? ' title="' . $role_description . '"' : '';
0576                          $s_role_options .= '<option value="' . $role_id . '"' . (($role_id == $current_role_id) ? ' selected="selected"' : '') . $title . '>' . $role_name . '</option>';
0577   
0578                          $role_options[] = array(
0579                              'ID'    => $role_id,
0580                              'ROLE_NAME'    => $role_name,
0581                              'TITLE'        => $role_description,
0582                              'SELECTED'    => $role_id == $current_role_id,
0583                          );
0584                      }
0585   
0586                      if ($s_role_options)
0587                      {
0588                          $s_role_options = '<option value="0"' . ((!$current_role_id) ? ' selected="selected"' : '') . ' title="' . htmlspecialchars($user->lang['NO_ROLE_ASSIGNED_EXPLAIN'], ENT_COMPAT) . '">' . $user->lang['NO_ROLE_ASSIGNED'] . '</option>' . $s_role_options;
0589                      }
0590   
0591                      if (!$current_role_id && $mode != 'view')
0592                      {
0593                          $s_custom_permissions = false;
0594   
0595                          foreach ($forum_array as $key => $value)
0596                          {
0597                              if ($value['S_NEVER'] || $value['S_YES'])
0598                              {
0599                                  $s_custom_permissions = true;
0600                                  break;
0601                              }
0602                          }
0603                      }
0604                      else
0605                      {
0606                          $s_custom_permissions = false;
0607                      }
0608   
0609                      $template->assign_block_vars($tpl_pmask . '.' . $tpl_fmask, array(
0610                          'NAME'                => ($forum_id == 0) ? $forum_names_ary[0] : $forum_names_ary[$forum_id]['forum_name'],
0611                          'PADDING'            => ($forum_id == 0) ? '' : $forum_names_ary[$forum_id]['padding'],
0612                          'S_CUSTOM'            => $s_custom_permissions,
0613                          'UG_ID'                => $ug_id,
0614                          'S_ROLE_OPTIONS'    => $s_role_options,
0615                          'FORUM_ID'            => $forum_id)
0616                      );
0617   
0618                      $template->assign_block_vars_array($tpl_pmask . '.' . $tpl_fmask . '.role_options', $role_options);
0619   
0620                      $this->assign_cat_array($forum_array, $tpl_pmask . '.' . $tpl_fmask . '.' . $tpl_category, $tpl_mask, $ug_id, $forum_id, ($mode == 'view'), $show_trace);
0621                  }
0622   
0623                  unset($hold_ary[$ug_id], $ug_names_ary[$ug_id]);
0624              }
0625          }
0626      }
0627   
0628      /**
0629      * Display permission mask for roles
0630      */
0631      function display_role_mask(&$hold_ary)
0632      {
0633          global $db, $template, $user, $phpbb_root_path, $phpEx;
0634          global $phpbb_container;
0635   
0636          if (!count($hold_ary))
0637          {
0638              return;
0639          }
0640   
0641          /** @var \phpbb\group\helper $group_helper */
0642          $group_helper = $phpbb_container->get('group_helper');
0643   
0644          // Get forum names
0645          $sql = 'SELECT forum_id, forum_name
0646              FROM ' . FORUMS_TABLE . '
0647              WHERE ' . $db->sql_in_set('forum_id', array_keys($hold_ary)) . '
0648              ORDER BY left_id';
0649          $result = $db->sql_query($sql);
0650   
0651          // If the role is used globally, then reflect that
0652          $forum_names = (isset($hold_ary[0])) ? array(0 => '') : array();
0653          while ($row = $db->sql_fetchrow($result))
0654          {
0655              $forum_names[$row['forum_id']] = $row['forum_name'];
0656          }
0657          $db->sql_freeresult($result);
0658   
0659          foreach ($forum_names as $forum_id => $forum_name)
0660          {
0661              $auth_ary = $hold_ary[$forum_id];
0662   
0663              $template->assign_block_vars('role_mask', array(
0664                  'NAME'                => ($forum_id == 0) ? $user->lang['GLOBAL_MASK'] : $forum_name,
0665                  'FORUM_ID'            => $forum_id)
0666              );
0667   
0668              if (isset($auth_ary['users']) && count($auth_ary['users']))
0669              {
0670                  $sql = 'SELECT user_id, username
0671                      FROM ' . USERS_TABLE . '
0672                      WHERE ' . $db->sql_in_set('user_id', $auth_ary['users']) . '
0673                      ORDER BY username_clean ASC';
0674                  $result = $db->sql_query($sql);
0675   
0676                  while ($row = $db->sql_fetchrow($result))
0677                  {
0678                      $template->assign_block_vars('role_mask.users', array(
0679                          'USER_ID'        => $row['user_id'],
0680                          'USERNAME'        => get_username_string('username', $row['user_id'], $row['username']),
0681                          'U_PROFILE'        => get_username_string('profile', $row['user_id'], $row['username']),
0682                      ));
0683                  }
0684                  $db->sql_freeresult($result);
0685              }
0686   
0687              if (isset($auth_ary['groups']) && count($auth_ary['groups']))
0688              {
0689                  $sql = 'SELECT group_id, group_name, group_type
0690                      FROM ' . GROUPS_TABLE . '
0691                      WHERE ' . $db->sql_in_set('group_id', $auth_ary['groups']) . '
0692                      ORDER BY group_type ASC, group_name';
0693                  $result = $db->sql_query($sql);
0694   
0695                  while ($row = $db->sql_fetchrow($result))
0696                  {
0697                      $template->assign_block_vars('role_mask.groups', array(
0698                          'GROUP_ID'        => $row['group_id'],
0699                          'GROUP_NAME'    => $group_helper->get_name($row['group_name']),
0700                          'U_PROFILE'        => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=group&amp;g={$row['group_id']}"))
0701                      );
0702                  }
0703                  $db->sql_freeresult($result);
0704              }
0705          }
0706      }
0707   
0708      /**
0709      * NOTE: this function is not in use atm
0710      * Add a new option to the list ... $options is a hash of form ->
0711      * $options = array(
0712      *    'local'        => array('option1', 'option2', ...),
0713      *    'global'    => array('optionA', 'optionB', ...)
0714      * );
0715      */
0716      function acl_add_option($options)
0717      {
0718          global $db, $cache;
0719   
0720          if (!is_array($options))
0721          {
0722              return false;
0723          }
0724   
0725          $cur_options = array();
0726   
0727          // Determine current options
0728          $sql = 'SELECT auth_option, is_global, is_local
0729              FROM ' . ACL_OPTIONS_TABLE . '
0730              ORDER BY auth_option_id';
0731          $result = $db->sql_query($sql);
0732   
0733          while ($row = $db->sql_fetchrow($result))
0734          {
0735              $cur_options[$row['auth_option']] = ($row['is_global'] && $row['is_local']) ? 'both' : (($row['is_global']) ? 'global' : 'local');
0736          }
0737          $db->sql_freeresult($result);
0738   
0739          // Here we need to insert new options ... this requires discovering whether
0740          // an options is global, local or both and whether we need to add an permission
0741          // set flag (x_)
0742          $new_options = array('local' => array(), 'global' => array());
0743   
0744          foreach ($options as $type => $option_ary)
0745          {
0746              $option_ary = array_unique($option_ary);
0747   
0748              foreach ($option_ary as $option_value)
0749              {
0750                  $new_options[$type][] = $option_value;
0751   
0752                  $flag = substr($option_value, 0, strpos($option_value, '_') + 1);
0753   
0754                  if (!in_array($flag, $new_options[$type]))
0755                  {
0756                      $new_options[$type][] = $flag;
0757                  }
0758              }
0759          }
0760          unset($options);
0761   
0762          $options = array();
0763          $options['local'] = array_diff($new_options['local'], $new_options['global']);
0764          $options['global'] = array_diff($new_options['global'], $new_options['local']);
0765          $options['both'] = array_intersect($new_options['local'], $new_options['global']);
0766   
0767          // Now check which options to add/update
0768          $add_options = $update_options = array();
0769   
0770          // First local ones...
0771          foreach ($options as $type => $option_ary)
0772          {
0773              foreach ($option_ary as $option)
0774              {
0775                  if (!isset($cur_options[$option]))
0776                  {
0777                      $add_options[] = array(
0778                          'auth_option'    => (string) $option,
0779                          'is_global'        => ($type == 'global' || $type == 'both') ? 1 : 0,
0780                          'is_local'        => ($type == 'local' || $type == 'both') ? 1 : 0
0781                      );
0782   
0783                      continue;
0784                  }
0785   
0786                  // Else, update existing entry if it is changed...
0787                  if ($type === $cur_options[$option])
0788                  {
0789                      continue;
0790                  }
0791   
0792                  // New type is always both:
0793                  // If is now both, we set both.
0794                  // If it was global the new one is local and we need to set it to both
0795                  // If it was local the new one is global and we need to set it to both
0796                  $update_options[] = $option;
0797              }
0798          }
0799   
0800          if (!empty($add_options))
0801          {
0802              $db->sql_multi_insert(ACL_OPTIONS_TABLE, $add_options);
0803          }
0804   
0805          if (!empty($update_options))
0806          {
0807              $sql = 'UPDATE ' . ACL_OPTIONS_TABLE . '
0808                  SET is_global = 1, is_local = 1
0809                  WHERE ' . $db->sql_in_set('auth_option', $update_options);
0810              $db->sql_query($sql);
0811          }
0812   
0813          $cache->destroy('_acl_options');
0814          $this->acl_clear_prefetch();
0815   
0816          // Because we just changed the options and also purged the options cache, we instantly update/regenerate it for later calls to succeed.
0817          $this->acl_options = array();
0818          $this->__construct();
0819   
0820          return true;
0821      }
0822   
0823      /**
0824      * Set a user or group ACL record
0825      */
0826      function acl_set($ug_type, $forum_id, $ug_id, $auth, $role_id = 0, $clear_prefetch = true)
0827      {
0828          global $db;
0829   
0830          // One or more forums
0831          if (!is_array($forum_id))
0832          {
0833              $forum_id = array($forum_id);
0834          }
0835   
0836          // One or more users
0837          if (!is_array($ug_id))
0838          {
0839              $ug_id = array($ug_id);
0840          }
0841   
0842          $ug_id_sql = $db->sql_in_set($ug_type . '_id', array_map('intval', $ug_id));
0843          $forum_sql = $db->sql_in_set('forum_id', array_map('intval', $forum_id));
0844   
0845          // Instead of updating, inserting, removing we just remove all current settings and re-set everything...
0846          $table = ($ug_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE;
0847          $id_field = $ug_type . '_id';
0848   
0849          // Get any flags as required
0850          reset($auth);
0851          $flag = key($auth);
0852          $flag = substr($flag, 0, strpos($flag, '_') + 1);
0853   
0854          // This ID (the any-flag) is set if one or more permissions are true...
0855          $any_option_id = (int) $this->acl_options['id'][$flag];
0856   
0857          // Remove any-flag from auth ary
0858          if (isset($auth[$flag]))
0859          {
0860              unset($auth[$flag]);
0861          }
0862   
0863          // Remove current auth options...
0864          $auth_option_ids = array((int) $any_option_id);
0865          foreach ($auth as $auth_option => $auth_setting)
0866          {
0867              $auth_option_ids[] = (int) $this->acl_options['id'][$auth_option];
0868          }
0869   
0870          $sql = "DELETE FROM $table
0871              WHERE $forum_sql
0872                  AND $ug_id_sql
0873                  AND " . $db->sql_in_set('auth_option_id', $auth_option_ids);
0874          $db->sql_query($sql);
0875   
0876          // Remove those having a role assigned... the correct type of course...
0877          $sql = 'SELECT role_id
0878              FROM ' . ACL_ROLES_TABLE . "
0879              WHERE role_type = '" . $db->sql_escape($flag) . "'";
0880          $result = $db->sql_query($sql);
0881   
0882          $role_ids = array();
0883          while ($row = $db->sql_fetchrow($result))
0884          {
0885              $role_ids[] = $row['role_id'];
0886          }
0887          $db->sql_freeresult($result);
0888   
0889          if (count($role_ids))
0890          {
0891              $sql = "DELETE FROM $table
0892                  WHERE $forum_sql
0893                      AND $ug_id_sql
0894                      AND auth_option_id = 0
0895                      AND " . $db->sql_in_set('auth_role_id', $role_ids);
0896              $db->sql_query($sql);
0897          }
0898   
0899          // Ok, include the any-flag if one or more auth options are set to yes...
0900          foreach ($auth as $auth_option => $setting)
0901          {
0902              if ($setting == ACL_YES && (!isset($auth[$flag]) || $auth[$flag] == ACL_NEVER))
0903              {
0904                  $auth[$flag] = ACL_YES;
0905              }
0906          }
0907   
0908          $sql_ary = array();
0909          foreach ($forum_id as $forum)
0910          {
0911              $forum = (int) $forum;
0912   
0913              if ($role_id)
0914              {
0915                  foreach ($ug_id as $id)
0916                  {
0917                      $sql_ary[] = array(
0918                          $id_field            => (int) $id,
0919                          'forum_id'            => (int) $forum,
0920                          'auth_option_id'    => 0,
0921                          'auth_setting'        => 0,
0922                          'auth_role_id'        => (int) $role_id,
0923                      );
0924                  }
0925              }
0926              else
0927              {
0928                  foreach ($auth as $auth_option => $setting)
0929                  {
0930                      $auth_option_id = (int) $this->acl_options['id'][$auth_option];
0931   
0932                      if ($setting != ACL_NO)
0933                      {
0934                          foreach ($ug_id as $id)
0935                          {
0936                              $sql_ary[] = array(
0937                                  $id_field            => (int) $id,
0938                                  'forum_id'            => (int) $forum,
0939                                  'auth_option_id'    => (int) $auth_option_id,
0940                                  'auth_setting'        => (int) $setting
0941                              );
0942                          }
0943                      }
0944                  }
0945              }
0946          }
0947   
0948          $db->sql_multi_insert($table, $sql_ary);
0949   
0950          if ($clear_prefetch)
0951          {
0952              $this->acl_clear_prefetch();
0953          }
0954      }
0955   
0956      /**
0957      * Set a role-specific ACL record
0958      */
0959      function acl_set_role($role_id, $auth)
0960      {
0961          global $db;
0962   
0963          // Get any-flag as required
0964          reset($auth);
0965          $flag = key($auth);
0966          $flag = substr($flag, 0, strpos($flag, '_') + 1);
0967   
0968          // Remove any-flag from auth ary
0969          if (isset($auth[$flag]))
0970          {
0971              unset($auth[$flag]);
0972          }
0973   
0974          // Re-set any flag...
0975          foreach ($auth as $auth_option => $setting)
0976          {
0977              if ($setting == ACL_YES && (!isset($auth[$flag]) || $auth[$flag] == ACL_NEVER))
0978              {
0979                  $auth[$flag] = ACL_YES;
0980              }
0981          }
0982   
0983          $sql_ary = array();
0984          foreach ($auth as $auth_option => $setting)
0985          {
0986              $auth_option_id = (int) $this->acl_options['id'][$auth_option];
0987   
0988              if ($setting != ACL_NO)
0989              {
0990                  $sql_ary[] = array(
0991                      'role_id'            => (int) $role_id,
0992                      'auth_option_id'    => (int) $auth_option_id,
0993                      'auth_setting'        => (int) $setting
0994                  );
0995              }
0996          }
0997   
0998          // If no data is there, we set the any-flag to ACL_NEVER...
0999          if (!count($sql_ary))
1000          {
1001              $sql_ary[] = array(
1002                  'role_id'            => (int) $role_id,
1003                  'auth_option_id'    => (int) $this->acl_options['id'][$flag],
1004                  'auth_setting'        => ACL_NEVER
1005              );
1006          }
1007   
1008          // Remove current auth options...
1009          $sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . '
1010              WHERE role_id = ' . $role_id;
1011          $db->sql_query($sql);
1012   
1013          // Now insert the new values
1014          $db->sql_multi_insert(ACL_ROLES_DATA_TABLE, $sql_ary);
1015   
1016          $this->acl_clear_prefetch();
1017      }
1018   
1019      /**
1020      * Remove local permission
1021      */
1022      function acl_delete($mode, $ug_id = false, $forum_id = false, $permission_type = false)
1023      {
1024          global $db;
1025   
1026          if ($ug_id === false && $forum_id === false)
1027          {
1028              return;
1029          }
1030   
1031          $option_id_ary = array();
1032          $table = ($mode == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE;
1033          $id_field = $mode . '_id';
1034   
1035          $where_sql = array();
1036   
1037          if ($forum_id !== false)
1038          {
1039              $where_sql[] = (!is_array($forum_id)) ? 'forum_id = ' . (int) $forum_id : $db->sql_in_set('forum_id', array_map('intval', $forum_id));
1040          }
1041   
1042          if ($ug_id !== false)
1043          {
1044              $where_sql[] = (!is_array($ug_id)) ? $id_field . ' = ' . (int) $ug_id : $db->sql_in_set($id_field, array_map('intval', $ug_id));
1045          }
1046   
1047          // There seem to be auth options involved, therefore we need to go through the list and make sure we capture roles correctly
1048          if ($permission_type !== false)
1049          {
1050              // Get permission type
1051              $sql = 'SELECT auth_option, auth_option_id
1052                  FROM ' . ACL_OPTIONS_TABLE . "
1053                  WHERE auth_option " . $db->sql_like_expression($permission_type . $db->get_any_char());
1054              $result = $db->sql_query($sql);
1055   
1056              $auth_id_ary = array();
1057              while ($row = $db->sql_fetchrow($result))
1058              {
1059                  $option_id_ary[] = $row['auth_option_id'];
1060                  $auth_id_ary[$row['auth_option']] = ACL_NO;
1061              }
1062              $db->sql_freeresult($result);
1063   
1064              // First of all, lets grab the items having roles with the specified auth options assigned
1065              $sql = "SELECT auth_role_id, $id_field, forum_id
1066                  FROM $table" . ACL_ROLES_TABLE . " r
1067                  WHERE auth_role_id <> 0
1068                      AND auth_role_id = r.role_id
1069                      AND r.role_type = '{$permission_type}'
1070                      AND " . implode(' AND ', $where_sql) . '
1071                  ORDER BY auth_role_id';
1072              $result = $db->sql_query($sql);
1073   
1074              $cur_role_auth = array();
1075              while ($row = $db->sql_fetchrow($result))
1076              {
1077                  $cur_role_auth[$row['auth_role_id']][$row['forum_id']][] = $row[$id_field];
1078              }
1079              $db->sql_freeresult($result);
1080   
1081              // Get role data for resetting data
1082              if (count($cur_role_auth))
1083              {
1084                  $sql = 'SELECT ao.auth_option, rd.role_id, rd.auth_setting
1085                      FROM ' . ACL_OPTIONS_TABLE . ' ao, ' . ACL_ROLES_DATA_TABLE . ' rd
1086                      WHERE ao.auth_option_id = rd.auth_option_id
1087                          AND ' . $db->sql_in_set('rd.role_id', array_keys($cur_role_auth));
1088                  $result = $db->sql_query($sql);
1089   
1090                  $auth_settings = array();
1091                  while ($row = $db->sql_fetchrow($result))
1092                  {
1093                      // We need to fill all auth_options, else setting it will fail...
1094                      if (!isset($auth_settings[$row['role_id']]))
1095                      {
1096                          $auth_settings[$row['role_id']] = $auth_id_ary;
1097                      }
1098                      $auth_settings[$row['role_id']][$row['auth_option']] = $row['auth_setting'];
1099                  }
1100                  $db->sql_freeresult($result);
1101   
1102                  // Set the options
1103                  foreach ($cur_role_auth as $role_id => $auth_row)
1104                  {
1105                      foreach ($auth_row as $f_id => $ug_row)
1106                      {
1107                          $this->acl_set($mode, $f_id, $ug_row, $auth_settings[$role_id], 0, false);
1108                      }
1109                  }
1110              }
1111          }
1112   
1113          // Now, normally remove permissions...
1114          if ($permission_type !== false)
1115          {
1116              $where_sql[] = $db->sql_in_set('auth_option_id', array_map('intval', $option_id_ary));
1117          }
1118   
1119          $sql = "DELETE FROM $table
1120              WHERE " . implode(' AND ', $where_sql);
1121          $db->sql_query($sql);
1122   
1123          $this->acl_clear_prefetch();
1124      }
1125   
1126      /**
1127      * Assign category to template
1128      * used by display_mask()
1129      */
1130      function assign_cat_array(&$category_array, $tpl_cat, $tpl_mask, $ug_id, $forum_id, $s_view, $show_trace = false)
1131      {
1132          global $template, $phpbb_admin_path, $phpEx, $phpbb_container;
1133   
1134          /** @var \phpbb\permissions $phpbb_permissions */
1135          $phpbb_permissions = $phpbb_container->get('acl.permissions');
1136   
1137          $order = array_flip(array_keys($phpbb_permissions->get_permissions()));
1138   
1139          foreach ($category_array as $cat => $cat_array)
1140          {
1141              if (!$phpbb_permissions->category_defined($cat))
1142              {
1143                  continue;
1144              }
1145   
1146              $template->assign_block_vars($tpl_cat, array(
1147                  'S_YES'        => ($cat_array['S_YES'] && !$cat_array['S_NEVER'] && !$cat_array['S_NO']) ? true : false,
1148                  'S_NEVER'    => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false,
1149                  'S_NO'        => ($cat_array['S_NO'] && !$cat_array['S_NEVER'] && !$cat_array['S_YES']) ? true : false,
1150   
1151                  'CAT_NAME'    => $phpbb_permissions->get_category_lang($cat),
1152              ));
1153   
1154              $permissions = array_filter($cat_array['permissions'], [$phpbb_permissions, 'permission_defined'], ARRAY_FILTER_USE_KEY);
1155   
1156              uksort($permissions, function($a, $b) use ($order) {
1157                  return $order[$a] <=> $order[$b];
1158              });
1159   
1160              foreach ($permissions as $permission => $allowed)
1161              {
1162                  if ($s_view)
1163                  {
1164                      $template->assign_block_vars($tpl_cat . '.' . $tpl_mask, array(
1165                          'S_YES'        => ($allowed == ACL_YES) ? true : false,
1166                          'S_NEVER'    => ($allowed == ACL_NEVER) ? true : false,
1167   
1168                          'UG_ID'            => $ug_id,
1169                          'FORUM_ID'        => $forum_id,
1170                          'FIELD_NAME'    => $permission,
1171                          'S_FIELD_NAME'    => 'setting[' . $ug_id . '][' . $forum_id . '][' . $permission . ']',
1172   
1173                          'U_TRACE'        => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&amp;mode=trace&amp;u=$ug_id&amp;f=$forum_id&amp;auth=$permission") : '',
1174                          'UA_TRACE'        => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '',
1175   
1176                          'PERMISSION'    => $phpbb_permissions->get_permission_lang($permission),
1177                      ));
1178                  }
1179                  else
1180                  {
1181                      $template->assign_block_vars($tpl_cat . '.' . $tpl_mask, array(
1182                          'S_YES'        => ($allowed == ACL_YES) ? true : false,
1183                          'S_NEVER'    => ($allowed == ACL_NEVER) ? true : false,
1184                          'S_NO'        => ($allowed == ACL_NO) ? true : false,
1185   
1186                          'UG_ID'            => $ug_id,
1187                          'FORUM_ID'        => $forum_id,
1188                          'FIELD_NAME'    => $permission,
1189                          'S_FIELD_NAME'    => 'setting[' . $ug_id . '][' . $forum_id . '][' . $permission . ']',
1190   
1191                          'U_TRACE'        => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&amp;mode=trace&amp;u=$ug_id&amp;f=$forum_id&amp;auth=$permission") : '',
1192                          'UA_TRACE'        => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '',
1193   
1194                          'PERMISSION'    => $phpbb_permissions->get_permission_lang($permission),
1195                      ));
1196                  }
1197              }
1198          }
1199      }
1200   
1201      /**
1202      * Building content array from permission rows with explicit key ordering
1203      * used by display_mask()
1204      */
1205      function build_permission_array(&$permission_row, &$content_array, &$categories, $key_sort_array)
1206      {
1207          global $phpbb_container;
1208   
1209          /** @var \phpbb\permissions $phpbb_permissions */
1210          $phpbb_permissions = $phpbb_container->get('acl.permissions');
1211   
1212          $order = array_flip(array_keys($phpbb_permissions->get_permissions()));
1213   
1214          foreach ($key_sort_array as $forum_id)
1215          {
1216              if (!isset($permission_row[$forum_id]))
1217              {
1218                  continue;
1219              }
1220   
1221              $permissions = array_filter($permission_row[$forum_id], [$phpbb_permissions, 'permission_defined'], ARRAY_FILTER_USE_KEY);
1222   
1223              uksort($permissions, function($a, $b) use ($order) {
1224                  return $order[$a] <=> $order[$b];
1225              });
1226   
1227              foreach ($permissions as $permission => $auth_setting)
1228              {
1229                  $cat = $phpbb_permissions->get_permission_category($permission);
1230   
1231                  // Build our categories array
1232                  if (!isset($categories[$cat]))
1233                  {
1234                      $categories[$cat] = $phpbb_permissions->get_category_lang($cat);
1235                  }
1236   
1237                  // Build our content array
1238                  if (!isset($content_array[$forum_id]))
1239                  {
1240                      $content_array[$forum_id] = array();
1241                  }
1242   
1243                  if (!isset($content_array[$forum_id][$cat]))
1244                  {
1245                      $content_array[$forum_id][$cat] = array(
1246                          'S_YES'            => false,
1247                          'S_NEVER'        => false,
1248                          'S_NO'            => false,
1249                          'permissions'    => array(),
1250                      );
1251                  }
1252   
1253                  $content_array[$forum_id][$cat]['S_YES'] |= ($auth_setting == ACL_YES) ? true : false;
1254                  $content_array[$forum_id][$cat]['S_NEVER'] |= ($auth_setting == ACL_NEVER) ? true : false;
1255                  $content_array[$forum_id][$cat]['S_NO'] |= ($auth_setting == ACL_NO) ? true : false;
1256   
1257                  $content_array[$forum_id][$cat]['permissions'][$permission] = $auth_setting;
1258              }
1259          }
1260      }
1261   
1262      /**
1263      * Use permissions from another user. This transferes a permission set from one user to another.
1264      * The other user is always able to revert back to his permission set.
1265      * This function does not check for lower/higher permissions, it is possible for the user to gain
1266      * "more" permissions by this.
1267      * Admin permissions will not be copied.
1268      */
1269      function ghost_permissions($from_user_id, $to_user_id)
1270      {
1271          global $db;
1272   
1273          if ($to_user_id == ANONYMOUS)
1274          {
1275              return false;
1276          }
1277   
1278          $hold_ary = $this->acl_raw_data_single_user($from_user_id);
1279   
1280          // Key 0 in $hold_ary are global options, all others are forum_ids
1281   
1282          // We disallow copying admin permissions
1283          foreach ($this->acl_options['global'] as $opt => $id)
1284          {
1285              if (strpos($opt, 'a_') === 0)
1286              {
1287                  $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_NEVER;
1288              }
1289          }
1290   
1291          // Force a_switchperm to be allowed
1292          $hold_ary[0][$this->acl_options['id']['a_switchperm']] = ACL_YES;
1293   
1294          $user_permissions = $this->build_bitstring($hold_ary);
1295   
1296          if (!$user_permissions)
1297          {
1298              return false;
1299          }
1300   
1301          $sql = 'UPDATE ' . USERS_TABLE . "
1302              SET user_permissions = '" . $db->sql_escape($user_permissions) . "',
1303                  user_perm_from = $from_user_id
1304              WHERE user_id = " . $to_user_id;
1305          $db->sql_query($sql);
1306   
1307          return true;
1308      }
1309  }
1310