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

functions_module.php

Zuletzt modifiziert: 02.04.2025, 15:01 - Dateigröße: 31.72 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  * Class handling all types of 'plugins' (a future term)
0024  */
0025  class p_master
0026  {
0027      var $p_id;
0028      var $p_class;
0029      var $p_name;
0030      var $p_mode;
0031      var $p_parent;
0032   
0033      var $include_path = false;
0034      var $active_module = false;
0035      var $active_module_row_id = false;
0036      var $acl_forum_id = false;
0037      var $module_ary = array();
0038   
0039      /**
0040      * Constuctor
0041      * Set module include path
0042      */
0043      function __construct($include_path = false)
0044      {
0045          global $phpbb_root_path;
0046   
0047          $this->include_path = ($include_path !== false) ? $include_path : $phpbb_root_path . 'includes/';
0048   
0049          // Make sure the path ends with /
0050          if (substr($this->include_path, -1) !== '/')
0051          {
0052              $this->include_path .= '/';
0053          }
0054      }
0055   
0056      /**
0057      * Set custom include path for modules
0058      * Schema for inclusion is include_path . modulebase
0059      *
0060      * @param string $include_path include path to be used.
0061      * @access public
0062      */
0063      function set_custom_include_path($include_path)
0064      {
0065          $this->include_path = $include_path;
0066   
0067          // Make sure the path ends with /
0068          if (substr($this->include_path, -1) !== '/')
0069          {
0070              $this->include_path .= '/';
0071          }
0072      }
0073   
0074      /**
0075      * List modules
0076      *
0077      * This creates a list, stored in $this->module_ary of all available
0078      * modules for the given class (ucp, mcp and acp). Additionally
0079      * $this->module_y_ary is created with indentation information for
0080      * displaying the module list appropriately. Only modules for which
0081      * the user has access rights are included in these lists.
0082      */
0083      function list_modules($p_class)
0084      {
0085          global $db, $user, $cache;
0086          global $phpbb_dispatcher;
0087   
0088          // Sanitise for future path use, it's escaped as appropriate for queries
0089          $this->p_class = str_replace(array('.', '/', '\\'), '', basename($p_class));
0090   
0091          // Get cached modules
0092          if (($this->module_cache = $cache->get('_modules_' . $this->p_class)) === false)
0093          {
0094              // Get modules
0095              $sql = 'SELECT *
0096                  FROM ' . MODULES_TABLE . "
0097                  WHERE module_class = '" . $db->sql_escape($this->p_class) . "'
0098                  ORDER BY left_id ASC";
0099              $result = $db->sql_query($sql);
0100   
0101              $rows = array();
0102              while ($row = $db->sql_fetchrow($result))
0103              {
0104                  $rows[$row['module_id']] = $row;
0105              }
0106              $db->sql_freeresult($result);
0107   
0108              $this->module_cache = array();
0109              foreach ($rows as $module_id => $row)
0110              {
0111                  $this->module_cache['modules'][] = $row;
0112                  $this->module_cache['parents'][$row['module_id']] = $this->get_parents($row['parent_id'], $row['left_id'], $row['right_id'], $rows);
0113              }
0114              unset($rows);
0115   
0116              $cache->put('_modules_' . $this->p_class, $this->module_cache);
0117          }
0118   
0119          if (empty($this->module_cache))
0120          {
0121              $this->module_cache = array('modules' => array(), 'parents' => array());
0122          }
0123   
0124          // We "could" build a true tree with this function - maybe mod authors want to use this...
0125          // Functions for traversing and manipulating the tree are not available though
0126          // We might re-structure the module system to use true trees in 4.0
0127          // $tree = $this->build_tree($this->module_cache['modules'], $this->module_cache['parents']);
0128   
0129          // Clean up module cache array to only let survive modules the user can access
0130          $right_id = false;
0131   
0132          $hide_categories = array();
0133          foreach ($this->module_cache['modules'] as $key => $row)
0134          {
0135              // When the module has no mode (category) we check whether it has visible children
0136              // before listing it as well.
0137              if (!$row['module_mode'])
0138              {
0139                  $hide_categories[(int) $row['module_id']] = $key;
0140              }
0141   
0142              // Not allowed to view module?
0143              if (!$this->module_auth_self($row['module_auth']))
0144              {
0145                  unset($this->module_cache['modules'][$key]);
0146                  continue;
0147              }
0148   
0149              // Category with no members, ignore
0150              if (!$row['module_basename'] && ($row['left_id'] + 1 == $row['right_id']))
0151              {
0152                  unset($this->module_cache['modules'][$key]);
0153                  continue;
0154              }
0155   
0156              // Skip branch
0157              if ($right_id !== false)
0158              {
0159                  if ($row['left_id'] < $right_id)
0160                  {
0161                      unset($this->module_cache['modules'][$key]);
0162                      continue;
0163                  }
0164   
0165                  $right_id = false;
0166              }
0167   
0168              // Not enabled?
0169              if (!$row['module_enabled'])
0170              {
0171                  // If category is disabled then disable every child too
0172                  unset($this->module_cache['modules'][$key]);
0173                  $right_id = $row['right_id'];
0174                  continue;
0175              }
0176   
0177              if ($row['module_mode'])
0178              {
0179                  // The parent category has a visible child
0180                  // So remove it and all its parents from the hide array
0181                  unset($hide_categories[(int) $row['parent_id']]);
0182                  foreach ($this->module_cache['parents'][$row['module_id']] as $module_id => $row_id)
0183                  {
0184                      unset($hide_categories[$module_id]);
0185                  }
0186              }
0187          }
0188   
0189          foreach ($hide_categories as $module_id => $row_id)
0190          {
0191              unset($this->module_cache['modules'][$row_id]);
0192          }
0193   
0194          // Re-index (this is needed, else we are not able to array_slice later)
0195          $this->module_cache['modules'] = array_merge($this->module_cache['modules']);
0196   
0197          // Include MOD _info files for populating language entries within the menus
0198          $this->add_mod_info($this->p_class);
0199   
0200          // Now build the module array, but exclude completely empty categories...
0201          $right_id = false;
0202          $names = array();
0203   
0204          foreach ($this->module_cache['modules'] as $key => $row)
0205          {
0206              // Skip branch
0207              if ($right_id !== false)
0208              {
0209                  if ($row['left_id'] < $right_id)
0210                  {
0211                      continue;
0212                  }
0213   
0214                  $right_id = false;
0215              }
0216   
0217              // Category with no members on their way down (we have to check every level)
0218              if (!$row['module_basename'])
0219              {
0220                  $empty_category = true;
0221   
0222                  // We go through the branch and look for an activated module
0223                  foreach (array_slice($this->module_cache['modules'], $key + 1) as $temp_row)
0224                  {
0225                      if ($temp_row['left_id'] > $row['left_id'] && $temp_row['left_id'] < $row['right_id'])
0226                      {
0227                          // Module there
0228                          if ($temp_row['module_basename'] && $temp_row['module_enabled'])
0229                          {
0230                              $empty_category = false;
0231                              break;
0232                          }
0233                          continue;
0234                      }
0235                      break;
0236                  }
0237   
0238                  // Skip the branch
0239                  if ($empty_category)
0240                  {
0241                      $right_id = $row['right_id'];
0242                      continue;
0243                  }
0244              }
0245   
0246              $depth = count($this->module_cache['parents'][$row['module_id']]);
0247   
0248              // We need to prefix the functions to not create a naming conflict
0249   
0250              // Function for building 'url_extra'
0251              $short_name = $this->get_short_name($row['module_basename']);
0252   
0253              $url_func = 'phpbb_module_' . $short_name . '_url';
0254              if (!function_exists($url_func))
0255              {
0256                  $url_func = '_module_' . $short_name . '_url';
0257              }
0258   
0259              // Function for building the language name
0260              $lang_func = 'phpbb_module_' . $short_name . '_lang';
0261              if (!function_exists($lang_func))
0262              {
0263                  $lang_func = '_module_' . $short_name . '_lang';
0264              }
0265   
0266              // Custom function for calling parameters on module init (for example assigning template variables)
0267              $custom_func = 'phpbb_module_' . $short_name;
0268              if (!function_exists($custom_func))
0269              {
0270                  $custom_func = '_module_' . $short_name;
0271              }
0272   
0273              $names[$row['module_basename'] . '_' . $row['module_mode']][] = true;
0274   
0275              $module_row = array(
0276                  'depth'        => $depth,
0277   
0278                  'id'        => (int) $row['module_id'],
0279                  'parent'    => (int) $row['parent_id'],
0280                  'cat'        => ($row['right_id'] > $row['left_id'] + 1) ? true : false,
0281   
0282                  'is_duplicate'    => ($row['module_basename'] && count($names[$row['module_basename'] . '_' . $row['module_mode']]) > 1) ? true : false,
0283   
0284                  'name'        => (string) $row['module_basename'],
0285                  'mode'        => (string) $row['module_mode'],
0286                  'display'    => (int) $row['module_display'],
0287   
0288                  'url_extra'    => (function_exists($url_func)) ? $url_func($row['module_mode'], $row) : '',
0289   
0290                  'lang'        => ($row['module_basename'] && function_exists($lang_func)) ? $lang_func($row['module_mode'], $row['module_langname']) : ((!empty($user->lang[$row['module_langname']])) ? $user->lang[$row['module_langname']] : $row['module_langname']),
0291                  'langname'    => $row['module_langname'],
0292   
0293                  'left'        => $row['left_id'],
0294                  'right'        => $row['right_id'],
0295              );
0296   
0297              if (function_exists($custom_func))
0298              {
0299                  $custom_func($row['module_mode'], $module_row);
0300              }
0301   
0302              /**
0303              * This event allows to modify parameters for building modules list
0304              *
0305              * @event core.modify_module_row
0306              * @var    string        url_func        Function for building 'url_extra'
0307              * @var    string        lang_func        Function for building the language name
0308              * @var    string        custom_func        Custom function for calling parameters on module init
0309              * @var    array        row                Array holding the basic module data
0310              * @var    array        module_row        Array holding the module display parameters
0311              * @since 3.1.0-b3
0312              */
0313              $vars = array('url_func', 'lang_func', 'custom_func', 'row', 'module_row');
0314              extract($phpbb_dispatcher->trigger_event('core.modify_module_row', compact($vars)));
0315   
0316              $this->module_ary[] = $module_row;
0317          }
0318   
0319          unset($this->module_cache['modules'], $names);
0320      }
0321   
0322      /**
0323      * Check if a certain main module is accessible/loaded
0324      * By giving the module mode you are able to additionally check for only one mode within the main module
0325      *
0326      * @param string $module_basename The module base name, for example logs, reports, main (for the mcp).
0327      * @param mixed $module_mode The module mode to check. If provided the mode will be checked in addition for presence.
0328      *
0329      * @return bool Returns true if module is loaded and accessible, else returns false
0330      */
0331      function loaded($module_basename, $module_mode = false)
0332      {
0333          if (!$this->is_full_class($module_basename))
0334          {
0335              $module_basename = $this->p_class . '_' . $module_basename;
0336          }
0337   
0338          if (empty($this->loaded_cache))
0339          {
0340              $this->loaded_cache = array();
0341   
0342              foreach ($this->module_ary as $row)
0343              {
0344                  if (!$row['name'])
0345                  {
0346                      continue;
0347                  }
0348   
0349                  if (!isset($this->loaded_cache[$row['name']]))
0350                  {
0351                      $this->loaded_cache[$row['name']] = array();
0352                  }
0353   
0354                  if (!$row['mode'])
0355                  {
0356                      continue;
0357                  }
0358   
0359                  $this->loaded_cache[$row['name']][$row['mode']] = true;
0360              }
0361          }
0362   
0363          if ($module_mode === false)
0364          {
0365              return (isset($this->loaded_cache[$module_basename])) ? true : false;
0366          }
0367   
0368          return (!empty($this->loaded_cache[$module_basename][$module_mode])) ? true : false;
0369      }
0370   
0371      /**
0372      * Check module authorisation.
0373      *
0374      * This is a non-static version that uses $this->acl_forum_id
0375      * for the forum id.
0376      */
0377      function module_auth_self($module_auth)
0378      {
0379          return self::module_auth($module_auth, $this->acl_forum_id);
0380      }
0381   
0382      /**
0383      * Check module authorisation.
0384      *
0385      * This is a static version, it must be given $forum_id.
0386      * See also module_auth_self.
0387      */
0388      static function module_auth($module_auth, $forum_id)
0389      {
0390          global $auth, $config;
0391          global $request, $phpbb_extension_manager, $phpbb_dispatcher;
0392   
0393          $module_auth = trim($module_auth);
0394   
0395          // Generally allowed to access module if module_auth is empty
0396          if (!$module_auth)
0397          {
0398              return true;
0399          }
0400   
0401          // With the code below we make sure only those elements get eval'd we really want to be checked
0402          preg_match_all('/(?:
0403              "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"         |
0404              \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'     |
0405              [(),]                                  |
0406              [^\s(),]+)/x', $module_auth, $match);
0407   
0408          // Valid tokens for auth and their replacements
0409          $valid_tokens = array(
0410              'acl_([a-z0-9_]+)(,\$id)?'        => '(int) $auth->acl_get(\'\\1\'\\2)',
0411              '\$id'                            => '(int) $forum_id',
0412              'aclf_([a-z0-9_]+)'                => '(int) $auth->acl_getf_global(\'\\1\')',
0413              'cfg_([a-z0-9_]+)'                => '(int) $config[\'\\1\']',
0414              'request_([a-zA-Z0-9_]+)'        => '$request->variable(\'\\1\', false)',
0415              'ext_([a-zA-Z0-9_/]+)'            => 'array_key_exists(\'\\1\', $phpbb_extension_manager->all_enabled())',
0416              'authmethod_([a-z0-9_\\\\]+)'        => '($config[\'auth_method\'] === \'\\1\')',
0417          );
0418   
0419          /**
0420          * Alter tokens for module authorisation check
0421          *
0422          * @event core.module_auth
0423          * @var    array    valid_tokens        Valid tokens and their auth check
0424          *                                    replacements
0425          * @var    string    module_auth            The module_auth of the current
0426          *                                     module
0427          * @var    int        forum_id            The current forum_id
0428          * @since 3.1.0-a3
0429          */
0430          $vars = array('valid_tokens', 'module_auth', 'forum_id');
0431          extract($phpbb_dispatcher->trigger_event('core.module_auth', compact($vars)));
0432   
0433          $tokens = $match[0];
0434          for ($i = 0, $size = count($tokens); $i < $size; $i++)
0435          {
0436              $token = &$tokens[$i];
0437   
0438              switch ($token)
0439              {
0440                  case ')':
0441                  case '(':
0442                  case '&&':
0443                  case '||':
0444                  case ',':
0445                  break;
0446   
0447                  default:
0448                      if (!preg_match('#(?:' . implode(')|(?:', array_keys($valid_tokens)) . ')#', $token))
0449                      {
0450                          $token = '';
0451                      }
0452                  break;
0453              }
0454          }
0455   
0456          $module_auth = implode(' ', $tokens);
0457   
0458          // Make sure $id separation is working fine
0459          $module_auth = str_replace(' , ', ',', $module_auth);
0460   
0461          $module_auth = preg_replace(
0462              // Array keys with # prepended/appended
0463              array_map(function($value) {
0464                  return '#' . $value . '#';
0465              }, array_keys($valid_tokens)),
0466              array_values($valid_tokens),
0467              $module_auth
0468          );
0469   
0470          $is_auth = false;
0471          // @codingStandardsIgnoreStart
0472          eval('$is_auth = (int) (' .    $module_auth . ');');
0473          // @codingStandardsIgnoreEnd
0474   
0475          return $is_auth;
0476      }
0477   
0478      /**
0479      * Set active module
0480      */
0481      function set_active($id = false, $mode = false)
0482      {
0483          global $auth, $request, $user;
0484   
0485          $icat = false;
0486          $this->active_module = false;
0487   
0488          if ($request->variable('icat', ''))
0489          {
0490              $icat = $id;
0491              $id = $request->variable('icat', '');
0492          }
0493   
0494          // Restore the backslashes in class names
0495          if (strpos($id, '-') !== false)
0496          {
0497              $id = str_replace('-', '\\', $id);
0498          }
0499   
0500          if ($id && !is_numeric($id) && !$this->is_full_class($id))
0501          {
0502              $id = $this->p_class . '_' . $id;
0503          }
0504   
0505          // Fallback to acp main page for special test permission mode
0506          if ($this->p_class === 'acp' && $user->data['user_perm_from'] && $auth->acl_get('a_switchperm'))
0507          {
0508              $id = '';
0509              $mode = '';
0510              $icat = false;
0511          }
0512   
0513          $category = false;
0514          foreach ($this->module_ary as $row_id => $item_ary)
0515          {
0516              // If this is a module and it's selected, active
0517              // If this is a category and the module is the first within it, active
0518              // If this is a module and no mode selected, select first mode
0519              // If no category or module selected, go active for first module in first category
0520              if (
0521                  (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) ||
0522                  ($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat && $item_ary['display']) ||
0523                  (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) ||
0524                  (!$id && !$mode && !$item_ary['cat'] && $item_ary['display'])
0525                  )
0526              {
0527                  if ($item_ary['cat'])
0528                  {
0529                      $id = $icat;
0530                      $icat = false;
0531   
0532                      continue;
0533                  }
0534   
0535                  $this->p_id        = $item_ary['id'];
0536                  $this->p_parent    = $item_ary['parent'];
0537                  $this->p_name    = $item_ary['name'];
0538                  $this->p_mode     = $item_ary['mode'];
0539                  $this->p_left    = $item_ary['left'];
0540                  $this->p_right    = $item_ary['right'];
0541   
0542                  $this->module_cache['parents'] = $this->module_cache['parents'][$this->p_id];
0543                  $this->active_module = $item_ary['id'];
0544                  $this->active_module_row_id = $row_id;
0545   
0546                  break;
0547              }
0548              else if (($item_ary['cat'] && $item_ary['id'] === (int) $id) || ($item_ary['parent'] === $category && $item_ary['cat']))
0549              {
0550                  $category = $item_ary['id'];
0551              }
0552          }
0553      }
0554   
0555      /**
0556      * Loads currently active module
0557      *
0558      * This method loads a given module, passing it the relevant id and mode.
0559      *
0560      * @param string|false $mode mode, as passed through to the module
0561      * @param string|false $module_url If supplied, we use this module url
0562      * @param bool $execute_module If true, at the end we execute the main method for the new instance
0563      */
0564      function load_active($mode = false, $module_url = false, $execute_module = true)
0565      {
0566          global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template, $request;
0567   
0568          $module_path = $this->include_path . $this->p_class;
0569          $icat = $request->variable('icat', '');
0570   
0571          if ($this->active_module === false)
0572          {
0573              trigger_error('MODULE_NOT_ACCESS', E_USER_ERROR);
0574          }
0575   
0576          // new modules use the full class names, old ones are always called <type>_<name>, e.g. acp_board
0577          if (!class_exists($this->p_name))
0578          {
0579              if (!file_exists("$module_path/{$this->p_name}.$phpEx"))
0580              {
0581                  trigger_error($user->lang('MODULE_NOT_FIND', "$module_path/{$this->p_name}.$phpEx"), E_USER_ERROR);
0582              }
0583   
0584              include("$module_path/{$this->p_name}.$phpEx");
0585   
0586              if (!class_exists($this->p_name))
0587              {
0588                  trigger_error($user->lang('MODULE_FILE_INCORRECT_CLASS', "$module_path/{$this->p_name}.$phpEx", $this->p_name), E_USER_ERROR);
0589              }
0590          }
0591   
0592          if (!empty($mode))
0593          {
0594              $this->p_mode = $mode;
0595          }
0596   
0597          // Create a new instance of the desired module ...
0598          $class_name = $this->p_name;
0599   
0600          $this->module = new $class_name($this);
0601   
0602          // We pre-define the action parameter we are using all over the place
0603          if (defined('IN_ADMIN'))
0604          {
0605              /*
0606              * If this is an extension module, we'll try to automatically set
0607              * the style paths for the extension (the ext author can change them
0608              * if necessary).
0609              */
0610              $module_dir = explode('\\', get_class($this->module));
0611   
0612              // 0 vendor, 1 extension name, ...
0613              if (isset($module_dir[1]))
0614              {
0615                  $module_style_dir = $phpbb_root_path . 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/adm/style';
0616   
0617                  if (is_dir($module_style_dir))
0618                  {
0619                      $template->set_custom_style(array(
0620                          array(
0621                              'name'         => 'adm',
0622                              'ext_path'     => 'adm/style/',
0623                          ),
0624                      ), array($module_style_dir, $phpbb_admin_path . 'style'));
0625                  }
0626              }
0627   
0628              // Is first module automatically enabled a duplicate and the category not passed yet?
0629              if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate'])
0630              {
0631                  $icat = $this->module_ary[$this->active_module_row_id]['parent'];
0632              }
0633   
0634              // Not being able to overwrite ;)
0635              $this->module->u_action = append_sid("{$phpbb_admin_path}index.$phpEx", 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&amp;icat=' . $icat : '') . "&amp;mode={$this->p_mode}";
0636          }
0637          else
0638          {
0639              /*
0640              * If this is an extension module, we'll try to automatically set
0641              * the style paths for the extension (the ext author can change them
0642              * if necessary).
0643              */
0644              $module_dir = explode('\\', get_class($this->module));
0645   
0646              // 0 vendor, 1 extension name, ...
0647              if (isset($module_dir[1]))
0648              {
0649                  $module_style_dir = 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/styles';
0650   
0651                  if (is_dir($phpbb_root_path . $module_style_dir))
0652                  {
0653                      $template->set_style(array($module_style_dir, 'styles'));
0654                  }
0655              }
0656   
0657              // If user specified the module url we will use it...
0658              if ($module_url !== false)
0659              {
0660                  $this->module->u_action = $module_url;
0661              }
0662              else
0663              {
0664                  $this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name'];
0665              }
0666   
0667              $this->module->u_action = append_sid($this->module->u_action, 'i=' . $this->get_module_identifier($this->p_name)) . (($icat) ? '&amp;icat=' . $icat : '') . "&amp;mode={$this->p_mode}";
0668          }
0669   
0670          // Add url_extra parameter to u_action url
0671          if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra'])
0672          {
0673              $this->module->u_action .= '&amp;' . $this->module_ary[$this->active_module_row_id]['url_extra'];
0674          }
0675   
0676          // Assign the module path for re-usage
0677          $this->module->module_path = $module_path . '/';
0678   
0679          // Execute the main method for the new instance, we send the module id and mode as parameters
0680          // Users are able to call the main method after this function to be able to assign additional parameters manually
0681          if ($execute_module)
0682          {
0683              $short_name = preg_replace("#^{$this->p_class}_#", '', $this->p_name);
0684              $this->module->main($short_name, $this->p_mode);
0685          }
0686      }
0687   
0688      /**
0689      * Appending url parameter to the currently active module.
0690      *
0691      * This function is called for adding specific url parameters while executing the current module.
0692      * It is doing the same as the _module_{name}_url() function, apart from being able to be called after
0693      * having dynamically parsed specific parameters. This allows more freedom in choosing additional parameters.
0694      * One example can be seen in /includes/mcp/mcp_notes.php - $this->p_master->adjust_url() call.
0695      *
0696      * @param string $url_extra Extra url parameters, e.g.: &amp;u=$user_id
0697      *
0698      */
0699      function adjust_url($url_extra)
0700      {
0701          if (empty($this->module_ary[$this->active_module_row_id]))
0702          {
0703              return;
0704          }
0705   
0706          $row = &$this->module_ary[$this->active_module_row_id];
0707   
0708          // We check for the same url_extra in $row['url_extra'] to overcome doubled additions...
0709          if (strpos($row['url_extra'], $url_extra) === false)
0710          {
0711              $row['url_extra'] .= $url_extra;
0712          }
0713      }
0714   
0715      /**
0716      * Check if a module is active
0717      */
0718      function is_active($id, $mode = false)
0719      {
0720          // If we find a name by this id and being enabled we have our active one...
0721          foreach ($this->module_ary as $row_id => $item_ary)
0722          {
0723              if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display'] || $item_ary['name'] === $this->p_class . '_' . $id)
0724              {
0725                  if ($mode === false || $mode === $item_ary['mode'])
0726                  {
0727                      return true;
0728                  }
0729              }
0730          }
0731   
0732          return false;
0733      }
0734   
0735      /**
0736      * Get parents
0737      */
0738      function get_parents($parent_id, $left_id, $right_id, &$all_parents)
0739      {
0740          $parents = array();
0741   
0742          if ($parent_id > 0)
0743          {
0744              foreach ($all_parents as $module_id => $row)
0745              {
0746                  if ($row['left_id'] < $left_id && $row['right_id'] > $right_id)
0747                  {
0748                      $parents[$module_id] = $row['parent_id'];
0749                  }
0750   
0751                  if ($row['left_id'] > $left_id)
0752                  {
0753                      break;
0754                  }
0755              }
0756          }
0757   
0758          return $parents;
0759      }
0760   
0761      /**
0762      * Get tree branch
0763      */
0764      function get_branch($left_id, $right_id, $remaining)
0765      {
0766          $branch = array();
0767   
0768          foreach ($remaining as $key => $row)
0769          {
0770              if ($row['left_id'] > $left_id && $row['left_id'] < $right_id)
0771              {
0772                  $branch[] = $row;
0773                  continue;
0774              }
0775              break;
0776          }
0777   
0778          return $branch;
0779      }
0780   
0781      /**
0782      * Build true binary tree from given array
0783      * Not in use
0784      */
0785      function build_tree(&$modules, &$parents)
0786      {
0787          $tree = array();
0788   
0789          foreach ($modules as $row)
0790          {
0791              $branch = &$tree;
0792   
0793              if ($row['parent_id'])
0794              {
0795                  // Go through the tree to find our branch
0796                  $parent_tree = $parents[$row['module_id']];
0797   
0798                  foreach ($parent_tree as $id => $value)
0799                  {
0800                      if (!isset($branch[$id]) && isset($branch['child']))
0801                      {
0802                          $branch = &$branch['child'];
0803                      }
0804                      $branch = &$branch[$id];
0805                  }
0806                  $branch = &$branch['child'];
0807              }
0808   
0809              $branch[$row['module_id']] = $row;
0810              if (!isset($branch[$row['module_id']]['child']))
0811              {
0812                  $branch[$row['module_id']]['child'] = array();
0813              }
0814          }
0815   
0816          return $tree;
0817      }
0818   
0819      /**
0820      * Build navigation structure
0821      */
0822      function assign_tpl_vars($module_url)
0823      {
0824          global $template;
0825   
0826          $current_id = $right_id = false;
0827   
0828          // Make sure the module_url has a question mark set, effectively determining the delimiter to use
0829          $delim = (strpos($module_url, '?') === false) ? '?' : '&amp;';
0830   
0831          $current_depth = 0;
0832          $linear_offset     = 'l_block1';
0833          $tabular_offset = 't_block2';
0834   
0835          // Generate the list of modules, we'll do this in two ways ...
0836          // 1) In a linear fashion
0837          // 2) In a combined tabbed + linear fashion ... tabs for the categories
0838          //    and a linear list for subcategories/items
0839          foreach ($this->module_ary as $row_id => $item_ary)
0840          {
0841              // Skip hidden modules
0842              if (!$item_ary['display'])
0843              {
0844                  continue;
0845              }
0846   
0847              // Skip branch
0848              if ($right_id !== false)
0849              {
0850                  if ($item_ary['left'] < $right_id)
0851                  {
0852                      continue;
0853                  }
0854   
0855                  $right_id = false;
0856              }
0857   
0858              // Category with no members on their way down (we have to check every level)
0859              if (!$item_ary['name'])
0860              {
0861                  $empty_category = true;
0862   
0863                  // We go through the branch and look for an activated module
0864                  foreach (array_slice($this->module_ary, $row_id + 1) as $temp_row)
0865                  {
0866                      if ($temp_row['left'] > $item_ary['left'] && $temp_row['left'] < $item_ary['right'])
0867                      {
0868                          // Module there and displayed?
0869                          if ($temp_row['name'] && $temp_row['display'])
0870                          {
0871                              $empty_category = false;
0872                              break;
0873                          }
0874                          continue;
0875                      }
0876                      break;
0877                  }
0878   
0879                  // Skip the branch
0880                  if ($empty_category)
0881                  {
0882                      $right_id = $item_ary['right'];
0883                      continue;
0884                  }
0885              }
0886   
0887              // Select first id we can get
0888              if (!$current_id && (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id))
0889              {
0890                  $current_id = $item_ary['id'];
0891              }
0892   
0893              $depth = $item_ary['depth'];
0894   
0895              if ($depth > $current_depth)
0896              {
0897                  $linear_offset = $linear_offset . '.l_block' . ($depth + 1);
0898                  $tabular_offset = ($depth + 1 > 2) ? $tabular_offset . '.t_block' . ($depth + 1) : $tabular_offset;
0899              }
0900              else if ($depth < $current_depth)
0901              {
0902                  for ($i = $current_depth - $depth; $i > 0; $i--)
0903                  {
0904                      $linear_offset = substr($linear_offset, 0, strrpos($linear_offset, '.'));
0905                      $tabular_offset = ($i + $depth > 1) ? substr($tabular_offset, 0, strrpos($tabular_offset, '.')) : $tabular_offset;
0906                  }
0907              }
0908   
0909              $u_title = $module_url . $delim . 'i=';
0910              // if the item has a name use it, else use its id
0911              if (empty($item_ary['name']))
0912              {
0913                  $u_title .= $item_ary['id'];
0914              }
0915              else
0916              {
0917                  // if the category has a name, then use it.
0918                  $u_title .= $this->get_module_identifier($item_ary['name']);
0919              }
0920              // If the item is not a category append the mode
0921              if (!$item_ary['cat'])
0922              {
0923                  if ($item_ary['is_duplicate'])
0924                  {
0925                      $u_title .= '&amp;icat=' . $current_id;
0926                  }
0927                  $u_title .= '&amp;mode=' . $item_ary['mode'];
0928              }
0929   
0930              // Was not allowed in categories before - /*!$item_ary['cat'] && */
0931              $u_title .= (isset($item_ary['url_extra']) && $item_ary['url_extra']) ? '&amp;' . $item_ary['url_extra'] : '';
0932   
0933              // Only output a categories items if it's currently selected
0934              if (!$depth || ($depth && (in_array($item_ary['parent'], array_values($this->module_cache['parents'])) || $item_ary['parent'] == $this->p_parent)))
0935              {
0936                  $use_tabular_offset = (!$depth) ? 't_block1' : $tabular_offset;
0937   
0938                  $tpl_ary = array(
0939                      'L_TITLE'        => $item_ary['lang'],
0940                      'S_SELECTED'    => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false,
0941                      'U_TITLE'        => $u_title
0942                  );
0943   
0944                  if (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id)
0945                  {
0946                      $template->assign_block_vars('navlinks', array(
0947                          'BREADCRUMB_NAME'    => $item_ary['lang'],
0948                          'U_BREADCRUMB'        => $u_title,
0949                      ));
0950                  }
0951   
0952                  $template->assign_block_vars($use_tabular_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER)));
0953              }
0954   
0955              $tpl_ary = array(
0956                  'L_TITLE'        => $item_ary['lang'],
0957                  'S_SELECTED'    => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false,
0958                  'U_TITLE'        => $u_title
0959              );
0960   
0961              $template->assign_block_vars($linear_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER)));
0962   
0963              $current_depth = $depth;
0964          }
0965      }
0966   
0967      /**
0968      * Returns desired template name
0969      */
0970      function get_tpl_name()
0971      {
0972          return $this->module->tpl_name . '.html';
0973      }
0974   
0975      /**
0976      * Returns the desired page title
0977      */
0978      function get_page_title()
0979      {
0980          global $user;
0981   
0982          if (!isset($this->module->page_title))
0983          {
0984              return '';
0985          }
0986   
0987          return (isset($user->lang[$this->module->page_title])) ? $user->lang[$this->module->page_title] : $this->module->page_title;
0988      }
0989   
0990      /**
0991      * Load module as the current active one without the need for registering it
0992      *
0993      * @param string $class module class (acp/mcp/ucp)
0994      * @param string $name module name (class name of the module, or its basename
0995      *                     phpbb_ext_foo_acp_bar_module, ucp_zebra or zebra)
0996      * @param string $mode mode, as passed through to the module
0997      *
0998      */
0999      function load($class, $name, $mode = false)
1000      {
1001          // new modules use the full class names, old ones are always called <class>_<name>, e.g. acp_board
1002          // in the latter case this function may be called as load('acp', 'board')
1003          if (!class_exists($name) && substr($name, 0, strlen($class) + 1) !== $class . '_')
1004          {
1005              $name = $class . '_' . $name;
1006          }
1007   
1008          $this->p_class = $class;
1009          $this->p_name = $name;
1010   
1011          // Set active module to true instead of using the id
1012          $this->active_module = true;
1013   
1014          $this->load_active($mode);
1015      }
1016   
1017      /**
1018      * Display module
1019      */
1020      function display($page_title, $display_online_list = false)
1021      {
1022          global $template, $user;
1023   
1024          // Generate the page
1025          if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
1026          {
1027              adm_page_header($page_title);
1028          }
1029          else
1030          {
1031              page_header($page_title, $display_online_list);
1032          }
1033   
1034          $template->set_filenames(array(
1035              'body' => $this->get_tpl_name())
1036          );
1037   
1038          if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
1039          {
1040              adm_page_footer();
1041          }
1042          else
1043          {
1044              page_footer();
1045          }
1046      }
1047   
1048      /**
1049      * Toggle whether this module will be displayed or not
1050      */
1051      function set_display($id, $mode = false, $display = true)
1052      {
1053          foreach ($this->module_ary as $row_id => $item_ary)
1054          {
1055              if (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode))
1056              {
1057                  $this->module_ary[$row_id]['display'] = (int) $display;
1058              }
1059          }
1060      }
1061   
1062      /**
1063      * Add custom MOD info language file
1064      */
1065      function add_mod_info($module_class)
1066      {
1067          global $config, $user, $phpEx, $phpbb_extension_manager;
1068   
1069          $finder = $phpbb_extension_manager->get_finder();
1070   
1071          // We grab the language files from the default, English and user's language.
1072          // So we can fall back to the other files like we do when using add_lang()
1073          $default_lang_files = $english_lang_files = $user_lang_files = array();
1074   
1075          // Search for board default language if it's not the user language
1076          if ($config['default_lang'] != $user->lang_name)
1077          {
1078              $default_lang_files = $finder
1079                  ->prefix('info_' . strtolower($module_class) . '_')
1080                  ->suffix(".$phpEx")
1081                  ->extension_directory('/language/' . basename($config['default_lang']))
1082                  ->core_path('language/' . basename($config['default_lang']) . '/mods/')
1083                  ->find();
1084          }
1085   
1086          // Search for english, if its not the default or user language
1087          if ($config['default_lang'] != 'en' && $user->lang_name != 'en')
1088          {
1089              $english_lang_files = $finder
1090                  ->prefix('info_' . strtolower($module_class) . '_')
1091                  ->suffix(".$phpEx")
1092                  ->extension_directory('/language/en')
1093                  ->core_path('language/en/mods/')
1094                  ->find();
1095          }
1096   
1097          // Find files in the user's language
1098          $user_lang_files = $finder
1099              ->prefix('info_' . strtolower($module_class) . '_')
1100              ->suffix(".$phpEx")
1101              ->extension_directory('/language/' . $user->lang_name)
1102              ->core_path('language/' . $user->lang_name . '/mods/')
1103              ->find();
1104   
1105          $lang_files = array_merge($english_lang_files, $default_lang_files, $user_lang_files);
1106          foreach ($lang_files as $lang_file => $ext_name)
1107          {
1108              $user->add_lang_ext($ext_name, $lang_file);
1109          }
1110      }
1111   
1112      /**
1113      * Retrieve shortened module basename for legacy basenames (with xcp_ prefix)
1114      *
1115      * @param string $basename A module basename
1116      * @return string The basename if it starts with phpbb_ or the basename with
1117      *                the current p_class (e.g. acp_) stripped.
1118      */
1119      protected function get_short_name($basename)
1120      {
1121          if (substr($basename, 0, 6) === 'phpbb\\' || strpos($basename, '\\') !== false)
1122          {
1123              return $basename;
1124          }
1125   
1126          // strip xcp_ prefix from old classes
1127          return substr($basename, strlen($this->p_class) + 1);
1128      }
1129   
1130      /**
1131      * If the basename contains a \ we don't use that for the URL.
1132      *
1133      * Firefox is currently unable to correctly copy a urlencoded \
1134      * so users will be unable to post links to modules.
1135      * However we can replace them with dashes and re-replace them later
1136      *
1137      * @param    string    $basename    Basename of the module
1138      * @return        string    Identifier that should be used for
1139      *                        module link creation
1140      */
1141      protected function get_module_identifier($basename)
1142      {
1143          if (strpos($basename, '\\') === false)
1144          {
1145              return $basename;
1146          }
1147   
1148          return str_replace('\\', '-', $basename);
1149      }
1150   
1151      /**
1152      * Checks whether the given module basename is a correct class name
1153      *
1154      * @param string $basename A module basename
1155      * @return bool True if the basename starts with phpbb_ or (x)cp_, false otherwise
1156      */
1157      protected function is_full_class($basename)
1158      {
1159          return (strpos($basename, '\\') !== false || preg_match('/^(ucp|mcp|acp)_/', $basename));
1160      }
1161  }
1162