Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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: 09.10.2024, 12:51 - Dateigröße: 31.25 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 p_master($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 $auth, $db, $user, $cache;
 0086          global $config, $phpbb_root_path, $phpEx, $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 3.2.x...
 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 = sizeof($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'] && sizeof($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 = sizeof($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          $icat = false;
 0484          $this->active_module = false;
 0485   
 0486          if (request_var('icat', ''))
 0487          {
 0488              $icat = $id;
 0489              $id = request_var('icat', '');
 0490          }
 0491   
 0492          // Restore the backslashes in class names
 0493          if (strpos($id, '-') !== false)
 0494          {
 0495              $id = str_replace('-', '\\', $id);
 0496          }
 0497   
 0498          if ($id && !is_numeric($id) && !$this->is_full_class($id))
 0499          {
 0500              $id = $this->p_class . '_' . $id;
 0501          }
 0502   
 0503          $category = false;
 0504          foreach ($this->module_ary as $row_id => $item_ary)
 0505          {
 0506              // If this is a module and it's selected, active
 0507              // If this is a category and the module is the first within it, active
 0508              // If this is a module and no mode selected, select first mode
 0509              // If no category or module selected, go active for first module in first category
 0510              if (
 0511                  (($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']))) ||
 0512                  ($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat && $item_ary['display']) ||
 0513                  (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) ||
 0514                  (!$id && !$mode && !$item_ary['cat'] && $item_ary['display'])
 0515                  )
 0516              {
 0517                  if ($item_ary['cat'])
 0518                  {
 0519                      $id = $icat;
 0520                      $icat = false;
 0521   
 0522                      continue;
 0523                  }
 0524   
 0525                  $this->p_id        = $item_ary['id'];
 0526                  $this->p_parent    = $item_ary['parent'];
 0527                  $this->p_name    = $item_ary['name'];
 0528                  $this->p_mode     = $item_ary['mode'];
 0529                  $this->p_left    = $item_ary['left'];
 0530                  $this->p_right    = $item_ary['right'];
 0531   
 0532                  $this->module_cache['parents'] = $this->module_cache['parents'][$this->p_id];
 0533                  $this->active_module = $item_ary['id'];
 0534                  $this->active_module_row_id = $row_id;
 0535   
 0536                  break;
 0537              }
 0538              else if (($item_ary['cat'] && $item_ary['id'] === (int) $id) || ($item_ary['parent'] === $category && $item_ary['cat']))
 0539              {
 0540                  $category = $item_ary['id'];
 0541              }
 0542          }
 0543      }
 0544   
 0545      /**
 0546      * Loads currently active module
 0547      *
 0548      * This method loads a given module, passing it the relevant id and mode.
 0549      *
 0550      * @param string|false $mode mode, as passed through to the module
 0551      * @param string|false $module_url If supplied, we use this module url
 0552      * @param bool $execute_module If true, at the end we execute the main method for the new instance
 0553      */
 0554      function load_active($mode = false, $module_url = false, $execute_module = true)
 0555      {
 0556          global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template;
 0557   
 0558          $module_path = $this->include_path . $this->p_class;
 0559          $icat = request_var('icat', '');
 0560   
 0561          if ($this->active_module === false)
 0562          {
 0563              trigger_error('MODULE_NOT_ACCESS', E_USER_ERROR);
 0564          }
 0565   
 0566          // new modules use the full class names, old ones are always called <type>_<name>, e.g. acp_board
 0567          if (!class_exists($this->p_name))
 0568          {
 0569              if (!file_exists("$module_path/{$this->p_name}.$phpEx"))
 0570              {
 0571                  trigger_error($user->lang('MODULE_NOT_FIND', "$module_path/{$this->p_name}.$phpEx"), E_USER_ERROR);
 0572              }
 0573   
 0574              include("$module_path/{$this->p_name}.$phpEx");
 0575   
 0576              if (!class_exists($this->p_name))
 0577              {
 0578                  trigger_error($user->lang('MODULE_FILE_INCORRECT_CLASS', "$module_path/{$this->p_name}.$phpEx", $this->p_name), E_USER_ERROR);
 0579              }
 0580          }
 0581   
 0582          if (!empty($mode))
 0583          {
 0584              $this->p_mode = $mode;
 0585          }
 0586   
 0587          // Create a new instance of the desired module ...
 0588          $class_name = $this->p_name;
 0589   
 0590          $this->module = new $class_name($this);
 0591   
 0592          // We pre-define the action parameter we are using all over the place
 0593          if (defined('IN_ADMIN'))
 0594          {
 0595              /*
 0596              * If this is an extension module, we'll try to automatically set
 0597              * the style paths for the extension (the ext author can change them
 0598              * if necessary).
 0599              */
 0600              $module_dir = explode('\\', get_class($this->module));
 0601   
 0602              // 0 vendor, 1 extension name, ...
 0603              if (isset($module_dir[1]))
 0604              {
 0605                  $module_style_dir = $phpbb_root_path . 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/adm/style';
 0606   
 0607                  if (is_dir($module_style_dir))
 0608                  {
 0609                      $template->set_custom_style(array(
 0610                          array(
 0611                              'name'         => 'adm',
 0612                              'ext_path'     => 'adm/style/',
 0613                          ),
 0614                      ), array($module_style_dir, $phpbb_admin_path . 'style'));
 0615                  }
 0616              }
 0617   
 0618              // Is first module automatically enabled a duplicate and the category not passed yet?
 0619              if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate'])
 0620              {
 0621                  $icat = $this->module_ary[$this->active_module_row_id]['parent'];
 0622              }
 0623   
 0624              // Not being able to overwrite ;)
 0625              $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}";
 0626          }
 0627          else
 0628          {
 0629              /*
 0630              * If this is an extension module, we'll try to automatically set
 0631              * the style paths for the extension (the ext author can change them
 0632              * if necessary).
 0633              */
 0634              $module_dir = explode('\\', get_class($this->module));
 0635   
 0636              // 0 vendor, 1 extension name, ...
 0637              if (isset($module_dir[1]))
 0638              {
 0639                  $module_style_dir = 'ext/' . $module_dir[0] . '/' . $module_dir[1] . '/styles';
 0640   
 0641                  if (is_dir($phpbb_root_path . $module_style_dir))
 0642                  {
 0643                      $template->set_style(array($module_style_dir, 'styles'));
 0644                  }
 0645              }
 0646   
 0647              // If user specified the module url we will use it...
 0648              if ($module_url !== false)
 0649              {
 0650                  $this->module->u_action = $module_url;
 0651              }
 0652              else
 0653              {
 0654                  $this->module->u_action = $phpbb_root_path . (($user->page['page_dir']) ? $user->page['page_dir'] . '/' : '') . $user->page['page_name'];
 0655              }
 0656   
 0657              $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}";
 0658          }
 0659   
 0660          // Add url_extra parameter to u_action url
 0661          if (!empty($this->module_ary) && $this->active_module !== false && $this->module_ary[$this->active_module_row_id]['url_extra'])
 0662          {
 0663              $this->module->u_action .= $this->module_ary[$this->active_module_row_id]['url_extra'];
 0664          }
 0665   
 0666          // Assign the module path for re-usage
 0667          $this->module->module_path = $module_path . '/';
 0668   
 0669          // Execute the main method for the new instance, we send the module id and mode as parameters
 0670          // Users are able to call the main method after this function to be able to assign additional parameters manually
 0671          if ($execute_module)
 0672          {
 0673              $short_name = preg_replace("#^{$this->p_class}_#", '', $this->p_name);
 0674              $this->module->main($short_name, $this->p_mode);
 0675          }
 0676      }
 0677   
 0678      /**
 0679      * Appending url parameter to the currently active module.
 0680      *
 0681      * This function is called for adding specific url parameters while executing the current module.
 0682      * It is doing the same as the _module_{name}_url() function, apart from being able to be called after
 0683      * having dynamically parsed specific parameters. This allows more freedom in choosing additional parameters.
 0684      * One example can be seen in /includes/mcp/mcp_notes.php - $this->p_master->adjust_url() call.
 0685      *
 0686      * @param string $url_extra Extra url parameters, e.g.: &amp;u=$user_id
 0687      *
 0688      */
 0689      function adjust_url($url_extra)
 0690      {
 0691          if (empty($this->module_ary[$this->active_module_row_id]))
 0692          {
 0693              return;
 0694          }
 0695   
 0696          $row = &$this->module_ary[$this->active_module_row_id];
 0697   
 0698          // We check for the same url_extra in $row['url_extra'] to overcome doubled additions...
 0699          if (strpos($row['url_extra'], $url_extra) === false)
 0700          {
 0701              $row['url_extra'] .= $url_extra;
 0702          }
 0703      }
 0704   
 0705      /**
 0706      * Check if a module is active
 0707      */
 0708      function is_active($id, $mode = false)
 0709      {
 0710          // If we find a name by this id and being enabled we have our active one...
 0711          foreach ($this->module_ary as $row_id => $item_ary)
 0712          {
 0713              if (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && $item_ary['display'] || $item_ary['name'] === $this->p_class . '_' . $id)
 0714              {
 0715                  if ($mode === false || $mode === $item_ary['mode'])
 0716                  {
 0717                      return true;
 0718                  }
 0719              }
 0720          }
 0721   
 0722          return false;
 0723      }
 0724   
 0725      /**
 0726      * Get parents
 0727      */
 0728      function get_parents($parent_id, $left_id, $right_id, &$all_parents)
 0729      {
 0730          global $db;
 0731   
 0732          $parents = array();
 0733   
 0734          if ($parent_id > 0)
 0735          {
 0736              foreach ($all_parents as $module_id => $row)
 0737              {
 0738                  if ($row['left_id'] < $left_id && $row['right_id'] > $right_id)
 0739                  {
 0740                      $parents[$module_id] = $row['parent_id'];
 0741                  }
 0742   
 0743                  if ($row['left_id'] > $left_id)
 0744                  {
 0745                      break;
 0746                  }
 0747              }
 0748          }
 0749   
 0750          return $parents;
 0751      }
 0752   
 0753      /**
 0754      * Get tree branch
 0755      */
 0756      function get_branch($left_id, $right_id, $remaining)
 0757      {
 0758          $branch = array();
 0759   
 0760          foreach ($remaining as $key => $row)
 0761          {
 0762              if ($row['left_id'] > $left_id && $row['left_id'] < $right_id)
 0763              {
 0764                  $branch[] = $row;
 0765                  continue;
 0766              }
 0767              break;
 0768          }
 0769   
 0770          return $branch;
 0771      }
 0772   
 0773      /**
 0774      * Build true binary tree from given array
 0775      * Not in use
 0776      */
 0777      function build_tree(&$modules, &$parents)
 0778      {
 0779          $tree = array();
 0780   
 0781          foreach ($modules as $row)
 0782          {
 0783              $branch = &$tree;
 0784   
 0785              if ($row['parent_id'])
 0786              {
 0787                  // Go through the tree to find our branch
 0788                  $parent_tree = $parents[$row['module_id']];
 0789   
 0790                  foreach ($parent_tree as $id => $value)
 0791                  {
 0792                      if (!isset($branch[$id]) && isset($branch['child']))
 0793                      {
 0794                          $branch = &$branch['child'];
 0795                      }
 0796                      $branch = &$branch[$id];
 0797                  }
 0798                  $branch = &$branch['child'];
 0799              }
 0800   
 0801              $branch[$row['module_id']] = $row;
 0802              if (!isset($branch[$row['module_id']]['child']))
 0803              {
 0804                  $branch[$row['module_id']]['child'] = array();
 0805              }
 0806          }
 0807   
 0808          return $tree;
 0809      }
 0810   
 0811      /**
 0812      * Build navigation structure
 0813      */
 0814      function assign_tpl_vars($module_url)
 0815      {
 0816          global $template;
 0817   
 0818          $current_id = $right_id = false;
 0819   
 0820          // Make sure the module_url has a question mark set, effectively determining the delimiter to use
 0821          $delim = (strpos($module_url, '?') === false) ? '?' : '&amp;';
 0822   
 0823          $current_padding = $current_depth = 0;
 0824          $linear_offset     = 'l_block1';
 0825          $tabular_offset = 't_block2';
 0826   
 0827          // Generate the list of modules, we'll do this in two ways ...
 0828          // 1) In a linear fashion
 0829          // 2) In a combined tabbed + linear fashion ... tabs for the categories
 0830          //    and a linear list for subcategories/items
 0831          foreach ($this->module_ary as $row_id => $item_ary)
 0832          {
 0833              // Skip hidden modules
 0834              if (!$item_ary['display'])
 0835              {
 0836                  continue;
 0837              }
 0838   
 0839              // Skip branch
 0840              if ($right_id !== false)
 0841              {
 0842                  if ($item_ary['left'] < $right_id)
 0843                  {
 0844                      continue;
 0845                  }
 0846   
 0847                  $right_id = false;
 0848              }
 0849   
 0850              // Category with no members on their way down (we have to check every level)
 0851              if (!$item_ary['name'])
 0852              {
 0853                  $empty_category = true;
 0854   
 0855                  // We go through the branch and look for an activated module
 0856                  foreach (array_slice($this->module_ary, $row_id + 1) as $temp_row)
 0857                  {
 0858                      if ($temp_row['left'] > $item_ary['left'] && $temp_row['left'] < $item_ary['right'])
 0859                      {
 0860                          // Module there and displayed?
 0861                          if ($temp_row['name'] && $temp_row['display'])
 0862                          {
 0863                              $empty_category = false;
 0864                              break;
 0865                          }
 0866                          continue;
 0867                      }
 0868                      break;
 0869                  }
 0870   
 0871                  // Skip the branch
 0872                  if ($empty_category)
 0873                  {
 0874                      $right_id = $item_ary['right'];
 0875                      continue;
 0876                  }
 0877              }
 0878   
 0879              // Select first id we can get
 0880              if (!$current_id && (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id))
 0881              {
 0882                  $current_id = $item_ary['id'];
 0883              }
 0884   
 0885              $depth = $item_ary['depth'];
 0886   
 0887              if ($depth > $current_depth)
 0888              {
 0889                  $linear_offset = $linear_offset . '.l_block' . ($depth + 1);
 0890                  $tabular_offset = ($depth + 1 > 2) ? $tabular_offset . '.t_block' . ($depth + 1) : $tabular_offset;
 0891              }
 0892              else if ($depth < $current_depth)
 0893              {
 0894                  for ($i = $current_depth - $depth; $i > 0; $i--)
 0895                  {
 0896                      $linear_offset = substr($linear_offset, 0, strrpos($linear_offset, '.'));
 0897                      $tabular_offset = ($i + $depth > 1) ? substr($tabular_offset, 0, strrpos($tabular_offset, '.')) : $tabular_offset;
 0898                  }
 0899              }
 0900   
 0901              $u_title = $module_url . $delim . 'i=';
 0902              // if the item has a name use it, else use its id
 0903              if (empty($item_ary['name']))
 0904              {
 0905                  $u_title .= $item_ary['id'];
 0906              }
 0907              else
 0908              {
 0909                  // if the category has a name, then use it.
 0910                  $u_title .= $this->get_module_identifier($item_ary['name']);
 0911              }
 0912              // If the item is not a category append the mode
 0913              if (!$item_ary['cat'])
 0914              {
 0915                  if ($item_ary['is_duplicate'])
 0916                  {
 0917                      $u_title .= '&amp;icat=' . $current_id;
 0918                  }
 0919                  $u_title .= '&amp;mode=' . $item_ary['mode'];
 0920              }
 0921   
 0922              // Was not allowed in categories before - /*!$item_ary['cat'] && */
 0923              $u_title .= (isset($item_ary['url_extra'])) ? $item_ary['url_extra'] : '';
 0924   
 0925              // Only output a categories items if it's currently selected
 0926              if (!$depth || ($depth && (in_array($item_ary['parent'], array_values($this->module_cache['parents'])) || $item_ary['parent'] == $this->p_parent)))
 0927              {
 0928                  $use_tabular_offset = (!$depth) ? 't_block1' : $tabular_offset;
 0929   
 0930                  $tpl_ary = array(
 0931                      'L_TITLE'        => $item_ary['lang'],
 0932                      'S_SELECTED'    => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false,
 0933                      'U_TITLE'        => $u_title
 0934                  );
 0935   
 0936                  $template->assign_block_vars($use_tabular_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER)));
 0937              }
 0938   
 0939              $tpl_ary = array(
 0940                  'L_TITLE'        => $item_ary['lang'],
 0941                  'S_SELECTED'    => (isset($this->module_cache['parents'][$item_ary['id']]) || $item_ary['id'] == $this->p_id) ? true : false,
 0942                  'U_TITLE'        => $u_title
 0943              );
 0944   
 0945              $template->assign_block_vars($linear_offset, array_merge($tpl_ary, array_change_key_case($item_ary, CASE_UPPER)));
 0946   
 0947              $current_depth = $depth;
 0948          }
 0949      }
 0950   
 0951      /**
 0952      * Returns desired template name
 0953      */
 0954      function get_tpl_name()
 0955      {
 0956          return $this->module->tpl_name . '.html';
 0957      }
 0958   
 0959      /**
 0960      * Returns the desired page title
 0961      */
 0962      function get_page_title()
 0963      {
 0964          global $user;
 0965   
 0966          if (!isset($this->module->page_title))
 0967          {
 0968              return '';
 0969          }
 0970   
 0971          return (isset($user->lang[$this->module->page_title])) ? $user->lang[$this->module->page_title] : $this->module->page_title;
 0972      }
 0973   
 0974      /**
 0975      * Load module as the current active one without the need for registering it
 0976      *
 0977      * @param string $class module class (acp/mcp/ucp)
 0978      * @param string $name module name (class name of the module, or its basename
 0979      *                     phpbb_ext_foo_acp_bar_module, ucp_zebra or zebra)
 0980      * @param string $mode mode, as passed through to the module
 0981      *
 0982      */
 0983      function load($class, $name, $mode = false)
 0984      {
 0985          // new modules use the full class names, old ones are always called <class>_<name>, e.g. acp_board
 0986          // in the latter case this function may be called as load('acp', 'board')
 0987          if (!class_exists($name) && substr($name, 0, strlen($class) + 1) !== $class . '_')
 0988          {
 0989              $name = $class . '_' . $name;
 0990          }
 0991   
 0992          $this->p_class = $class;
 0993          $this->p_name = $name;
 0994   
 0995          // Set active module to true instead of using the id
 0996          $this->active_module = true;
 0997   
 0998          $this->load_active($mode);
 0999      }
 1000   
 1001      /**
 1002      * Display module
 1003      */
 1004      function display($page_title, $display_online_list = false)
 1005      {
 1006          global $template, $user;
 1007   
 1008          // Generate the page
 1009          if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
 1010          {
 1011              adm_page_header($page_title);
 1012          }
 1013          else
 1014          {
 1015              page_header($page_title, $display_online_list);
 1016          }
 1017   
 1018          $template->set_filenames(array(
 1019              'body' => $this->get_tpl_name())
 1020          );
 1021   
 1022          if (defined('IN_ADMIN') && isset($user->data['session_admin']) && $user->data['session_admin'])
 1023          {
 1024              adm_page_footer();
 1025          }
 1026          else
 1027          {
 1028              page_footer();
 1029          }
 1030      }
 1031   
 1032      /**
 1033      * Toggle whether this module will be displayed or not
 1034      */
 1035      function set_display($id, $mode = false, $display = true)
 1036      {
 1037          foreach ($this->module_ary as $row_id => $item_ary)
 1038          {
 1039              if (($item_ary['name'] === $id || $item_ary['name'] === $this->p_class . '_' . $id || $item_ary['id'] === (int) $id) && (!$mode || $item_ary['mode'] === $mode))
 1040              {
 1041                  $this->module_ary[$row_id]['display'] = (int) $display;
 1042              }
 1043          }
 1044      }
 1045   
 1046      /**
 1047      * Add custom MOD info language file
 1048      */
 1049      function add_mod_info($module_class)
 1050      {
 1051          global $config, $user, $phpEx, $phpbb_extension_manager;
 1052   
 1053          $finder = $phpbb_extension_manager->get_finder();
 1054   
 1055          // We grab the language files from the default, English and user's language.
 1056          // So we can fall back to the other files like we do when using add_lang()
 1057          $default_lang_files = $english_lang_files = $user_lang_files = array();
 1058   
 1059          // Search for board default language if it's not the user language
 1060          if ($config['default_lang'] != $user->lang_name)
 1061          {
 1062              $default_lang_files = $finder
 1063                  ->prefix('info_' . strtolower($module_class) . '_')
 1064                  ->suffix(".$phpEx")
 1065                  ->extension_directory('/language/' . basename($config['default_lang']))
 1066                  ->core_path('language/' . basename($config['default_lang']) . '/mods/')
 1067                  ->find();
 1068          }
 1069   
 1070          // Search for english, if its not the default or user language
 1071          if ($config['default_lang'] != 'en' && $user->lang_name != 'en')
 1072          {
 1073              $english_lang_files = $finder
 1074                  ->prefix('info_' . strtolower($module_class) . '_')
 1075                  ->suffix(".$phpEx")
 1076                  ->extension_directory('/language/en')
 1077                  ->core_path('language/en/mods/')
 1078                  ->find();
 1079          }
 1080   
 1081          // Find files in the user's language
 1082          $user_lang_files = $finder
 1083              ->prefix('info_' . strtolower($module_class) . '_')
 1084              ->suffix(".$phpEx")
 1085              ->extension_directory('/language/' . $user->lang_name)
 1086              ->core_path('language/' . $user->lang_name . '/mods/')
 1087              ->find();
 1088   
 1089          $lang_files = array_unique(array_merge($user_lang_files, $english_lang_files, $default_lang_files));
 1090          foreach ($lang_files as $lang_file => $ext_name)
 1091          {
 1092              $user->add_lang_ext($ext_name, $lang_file);
 1093          }
 1094      }
 1095   
 1096      /**
 1097      * Retrieve shortened module basename for legacy basenames (with xcp_ prefix)
 1098      *
 1099      * @param string $basename A module basename
 1100      * @return string The basename if it starts with phpbb_ or the basename with
 1101      *                the current p_class (e.g. acp_) stripped.
 1102      */
 1103      protected function get_short_name($basename)
 1104      {
 1105          if (substr($basename, 0, 6) === 'phpbb\\' || strpos($basename, '\\') !== false)
 1106          {
 1107              return $basename;
 1108          }
 1109   
 1110          // strip xcp_ prefix from old classes
 1111          return substr($basename, strlen($this->p_class) + 1);
 1112      }
 1113   
 1114      /**
 1115      * If the basename contains a \ we don't use that for the URL.
 1116      *
 1117      * Firefox is currently unable to correctly copy a urlencoded \
 1118      * so users will be unable to post links to modules.
 1119      * However we can replace them with dashes and re-replace them later
 1120      *
 1121      * @param    string    $basename    Basename of the module
 1122      * @return        string    Identifier that should be used for
 1123      *                        module link creation
 1124      */
 1125      protected function get_module_identifier($basename)
 1126      {
 1127          if (strpos($basename, '\\') === false)
 1128          {
 1129              return $basename;
 1130          }
 1131   
 1132          return str_replace('\\', '-', $basename);
 1133      }
 1134   
 1135      /**
 1136      * Checks whether the given module basename is a correct class name
 1137      *
 1138      * @param string $basename A module basename
 1139      * @return bool True if the basename starts with phpbb_ or (x)cp_, false otherwise
 1140      */
 1141      protected function is_full_class($basename)
 1142      {
 1143          return (strpos($basename, '\\') !== false || preg_match('/^(ucp|mcp|acp)_/', $basename));
 1144      }
 1145  }
 1146