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