Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


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

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

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

module.php

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


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb\db\migration\tool;
015   
016  use phpbb\module\exception\module_exception;
017   
018  /**
019  * Migration module management tool
020  */
021  class module implements \phpbb\db\migration\tool\tool_interface
022  {
023      /** @var \phpbb\cache\service */
024      protected $cache;
025   
026      /** @var \phpbb\db\driver\driver_interface */
027      protected $db;
028   
029      /** @var \phpbb\user */
030      protected $user;
031   
032      /** @var \phpbb\module\module_manager */
033      protected $module_manager;
034   
035      /** @var string */
036      protected $phpbb_root_path;
037   
038      /** @var string */
039      protected $php_ext;
040   
041      /** @var string */
042      protected $modules_table;
043   
044      /** @var array */
045      protected $module_categories = array();
046   
047      /**
048      * Constructor
049      *
050      * @param \phpbb\db\driver\driver_interface $db
051      * @param \phpbb\cache\service $cache
052      * @param \phpbb\user $user
053      * @param \phpbb\module\module_manager    $module_manager
054      * @param string $phpbb_root_path
055      * @param string $php_ext
056      * @param string $modules_table
057      */
058      public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\cache\service $cache, \phpbb\user $user, \phpbb\module\module_manager $module_manager, $phpbb_root_path, $php_ext, $modules_table)
059      {
060          $this->db = $db;
061          $this->cache = $cache;
062          $this->user = $user;
063          $this->module_manager = $module_manager;
064          $this->phpbb_root_path = $phpbb_root_path;
065          $this->php_ext = $php_ext;
066          $this->modules_table = $modules_table;
067      }
068   
069      /**
070      * {@inheritdoc}
071      */
072      public function get_name()
073      {
074          return 'module';
075      }
076   
077      /**
078      * Module Exists
079      *
080      * Check if a module exists
081      *
082      * @param string $class The module class(acp|mcp|ucp)
083      * @param int|string|bool $parent The parent module_id|module_langname (0 for no parent).
084      *        Use false to ignore the parent check and check class wide.
085      * @param int|string $module The module_id|module_langname you would like to
086      *         check for to see if it exists
087      * @param bool $lazy Checks lazily if the module exists. Returns true if it exists in at
088      *       least one given parent.
089      * @return bool true if module exists in *all* given parents, false if not in any given parent;
090       *      true if ignoring parent check and module exists class wide, false if not found at all.
091      */
092      public function exists($class, $parent, $module, $lazy = false)
093      {
094          // the main root directory should return true
095          if (!$module)
096          {
097              return true;
098          }
099   
100          $parent_sqls = [];
101          if ($parent !== false)
102          {
103              $parents = $this->get_parent_module_id($parent, $module, false);
104              if ($parents === false)
105              {
106                  return false;
107              }
108   
109              foreach ((array) $parents as $parent_id)
110              {
111                  $parent_sqls[] = 'AND parent_id = ' . (int) $parent_id;
112              }
113          }
114          else
115          {
116              $parent_sqls[] = '';
117          }
118   
119          foreach ($parent_sqls as $parent_sql)
120          {
121              $sql = 'SELECT module_id
122                  FROM ' . $this->modules_table . "
123                  WHERE module_class = '" . $this->db->sql_escape($class) . "'
124                      $parent_sql
125                      AND " . ((is_numeric($module)) ? 'module_id = ' . (int) $module : "module_langname = '" . $this->db->sql_escape($module) . "'");
126              $result = $this->db->sql_query($sql);
127              $module_id = $this->db->sql_fetchfield('module_id');
128              $this->db->sql_freeresult($result);
129   
130              if (!$lazy && !$module_id)
131              {
132                  return false;
133              }
134              if ($lazy && $module_id)
135              {
136                  return true;
137              }
138          }
139   
140          // Returns true, if modules exist in all parents and false otherwise
141          return !$lazy;
142      }
143   
144      /**
145      * Module Add
146      *
147      * Add a new module
148      *
149      * @param string $class The module class(acp|mcp|ucp)
150      * @param int|string $parent The parent module_id|module_langname (0 for no parent)
151      * @param array $data an array of the data on the new \module.
152      *     This can be setup in two different ways.
153      *    1. The "manual" way.  For inserting a category or one at a time.
154      *        It will be merged with the base array shown a bit below,
155      *            but at the least requires 'module_langname' to be sent, and,
156      *            if you want to create a module (instead of just a category) you must
157      *            send module_basename and module_mode.
158      *        array(
159      *            'module_enabled'    => 1,
160      *            'module_display'    => 1,
161      *               'module_basename'    => '',
162      *            'module_class'        => $class,
163      *               'parent_id'            => (int) $parent,
164      *            'module_langname'    => '',
165      *               'module_mode'        => '',
166      *               'module_auth'        => '',
167      *        )
168      *    2. The "automatic" way.  For inserting multiple at a time based on the
169      *            specs in the info file for the module(s).  For this to work the
170      *            modules must be correctly setup in the info file.
171      *        An example follows (this would insert the settings, log, and flag
172      *            modes from the includes/acp/info/acp_asacp.php file):
173      *         array(
174      *             'module_basename'    => 'asacp',
175      *             'modes'                => array('settings', 'log', 'flag'),
176      *         )
177      *         Optionally you may not send 'modes' and it will insert all of the
178      *             modules in that info file.
179      *     path, specify that here
180      * @return null
181      * @throws \phpbb\db\migration\exception
182      */
183      public function add($class, $parent = 0, $data = array())
184      {
185          global $user, $phpbb_log;
186   
187          // allow sending the name as a string in $data to create a category
188          if (!is_array($data))
189          {
190              $data = array('module_langname' => $data);
191          }
192   
193          $parents = (array) $this->get_parent_module_id($parent, $data);
194   
195          if (!isset($data['module_langname']))
196          {
197              // The "automatic" way
198              $basename = (isset($data['module_basename'])) ? $data['module_basename'] : '';
199              $module = $this->get_module_info($class, $basename);
200   
201              foreach ($module['modes'] as $mode => $module_info)
202              {
203                  if (!isset($data['modes']) || in_array($mode, $data['modes']))
204                  {
205                      $new_module = array(
206                          'module_basename'    => $basename,
207                          'module_langname'    => $module_info['title'],
208                          'module_mode'        => $mode,
209                          'module_auth'        => $module_info['auth'],
210                          'module_display'    => (isset($module_info['display'])) ? $module_info['display'] : true,
211                          'before'            => (isset($module_info['before'])) ? $module_info['before'] : false,
212                          'after'                => (isset($module_info['after'])) ? $module_info['after'] : false,
213                      );
214   
215                      // Run the "manual" way with the data we've collected.
216                      foreach ($parents as $parent)
217                      {
218                          $this->add($class, $parent, $new_module);
219                      }
220                  }
221              }
222   
223              return;
224          }
225   
226          foreach ($parents as $parent)
227          {
228              $data['parent_id'] = $parent;
229   
230              // The "manual" way
231              if (!$this->exists($class, false, $parent))
232              {
233                  throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent);
234              }
235   
236              if ($this->exists($class, $parent, $data['module_langname']))
237              {
238                  throw new \phpbb\db\migration\exception('MODULE_EXISTS', $data['module_langname']);
239              }
240   
241              $module_data = array(
242                  'module_enabled'    => (isset($data['module_enabled'])) ? $data['module_enabled'] : 1,
243                  'module_display'    => (isset($data['module_display'])) ? $data['module_display'] : 1,
244                  'module_basename'    => (isset($data['module_basename'])) ? $data['module_basename'] : '',
245                  'module_class'        => $class,
246                  'parent_id'            => (int) $parent,
247                  'module_langname'    => (isset($data['module_langname'])) ? $data['module_langname'] : '',
248                  'module_mode'        => (isset($data['module_mode'])) ? $data['module_mode'] : '',
249                  'module_auth'        => (isset($data['module_auth'])) ? $data['module_auth'] : '',
250              );
251   
252              try
253              {
254                  $this->module_manager->update_module_data($module_data);
255   
256                  // Success
257                  $module_log_name = ((isset($this->user->lang[$data['module_langname']])) ? $this->user->lang[$data['module_langname']] : $data['module_langname']);
258                  $phpbb_log->add('admin', (isset($user->data['user_id'])) ? $user->data['user_id'] : ANONYMOUS, $user->ip, 'LOG_MODULE_ADD', false, array($module_log_name));
259   
260                  // Move the module if requested above/below an existing one
261                  if (isset($data['before']) && $data['before'])
262                  {
263                      $before_mode = $before_langname = '';
264                      if (is_array($data['before']))
265                      {
266                          // Restore legacy-legacy behaviour from phpBB 3.0
267                          list($before_mode, $before_langname) = $data['before'];
268                      }
269                      else
270                      {
271                          // Legacy behaviour from phpBB 3.1+
272                          $before_langname = $data['before'];
273                      }
274   
275                      $sql = 'SELECT left_id
276                      FROM ' . $this->modules_table . "
277                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
278                          AND parent_id = " . (int) $parent . "
279                          AND module_langname = '" . $this->db->sql_escape($before_langname) . "'"
280                          . (($before_mode) ? " AND module_mode = '" . $this->db->sql_escape($before_mode) . "'" : '');
281                      $result = $this->db->sql_query($sql);
282                      $to_left = (int) $this->db->sql_fetchfield('left_id');
283                      $this->db->sql_freeresult($result);
284   
285                      $sql = 'UPDATE ' . $this->modules_table . "
286                      SET left_id = left_id + 2, right_id = right_id + 2
287                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
288                          AND left_id >= $to_left
289                          AND left_id < {$module_data['left_id']}";
290                      $this->db->sql_query($sql);
291   
292                      $sql = 'UPDATE ' . $this->modules_table . "
293                      SET left_id = $to_left, right_id = " . ($to_left + 1) . "
294                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
295                          AND module_id = {$module_data['module_id']}";
296                      $this->db->sql_query($sql);
297                  }
298                  else if (isset($data['after']) && $data['after'])
299                  {
300                      $after_mode = $after_langname = '';
301                      if (is_array($data['after']))
302                      {
303                          // Restore legacy-legacy behaviour from phpBB 3.0
304                          list($after_mode, $after_langname) = $data['after'];
305                      }
306                      else
307                      {
308                          // Legacy behaviour from phpBB 3.1+
309                          $after_langname = $data['after'];
310                      }
311   
312                      $sql = 'SELECT right_id
313                      FROM ' . $this->modules_table . "
314                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
315                          AND parent_id = " . (int) $parent . "
316                          AND module_langname = '" . $this->db->sql_escape($after_langname) . "'"
317                          . (($after_mode) ? " AND module_mode = '" . $this->db->sql_escape($after_mode) . "'" : '');
318                      $result = $this->db->sql_query($sql);
319                      $to_right = (int) $this->db->sql_fetchfield('right_id');
320                      $this->db->sql_freeresult($result);
321   
322                      $sql = 'UPDATE ' . $this->modules_table . "
323                      SET left_id = left_id + 2, right_id = right_id + 2
324                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
325                          AND left_id >= $to_right
326                          AND left_id < {$module_data['left_id']}";
327                      $this->db->sql_query($sql);
328   
329                      $sql = 'UPDATE ' . $this->modules_table . '
330                      SET left_id = ' . ($to_right + 1) . ', right_id = ' . ($to_right + 2) . "
331                      WHERE module_class = '" . $this->db->sql_escape($class) . "'
332                          AND module_id = {$module_data['module_id']}";
333                      $this->db->sql_query($sql);
334                  }
335              }
336              catch (module_exception $e)
337              {
338                  // Error
339                  throw new \phpbb\db\migration\exception('MODULE_ERROR', $e->getMessage());
340              }
341          }
342   
343          // Clear the Modules Cache
344          $this->module_manager->remove_cache_file($class);
345      }
346   
347      /**
348      * Module Remove
349      *
350      * Remove a module
351      *
352      * @param string $class The module class(acp|mcp|ucp)
353      * @param int|string|bool $parent The parent module_id|module_langname(0 for no parent).
354      *     Use false to ignore the parent check and check class wide.
355      * @param int|string $module The module id|module_langname
356      *     specify that here
357      * @return null
358      * @throws \phpbb\db\migration\exception
359      */
360      public function remove($class, $parent = 0, $module = '')
361      {
362          // Imitation of module_add's "automatic" and "manual" method so the uninstaller works from the same set of instructions for umil_auto
363          if (is_array($module))
364          {
365              if (isset($module['module_langname']))
366              {
367                  // Manual Method
368                  return $this->remove($class, $parent, $module['module_langname']);
369              }
370   
371              // Failed.
372              if (!isset($module['module_basename']))
373              {
374                  throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST');
375              }
376   
377              // Automatic method
378              $basename = $module['module_basename'];
379              $module_info = $this->get_module_info($class, $basename);
380   
381              foreach ($module_info['modes'] as $mode => $info)
382              {
383                  if (!isset($module['modes']) || in_array($mode, $module['modes']))
384                  {
385                      $this->remove($class, $parent, $info['title']);
386                  }
387              }
388          }
389          else
390          {
391              if (!$this->exists($class, $parent, $module, true))
392              {
393                  return;
394              }
395   
396              $parent_sql = '';
397              if ($parent !== false)
398              {
399                  $parents = (array) $this->get_parent_module_id($parent, $module);
400                  $parent_sql = 'AND ' . $this->db->sql_in_set('parent_id', $parents);
401              }
402   
403              $module_ids = array();
404              if (!is_numeric($module))
405              {
406                  $sql = 'SELECT module_id
407                      FROM ' . $this->modules_table . "
408                      WHERE module_langname = '" . $this->db->sql_escape($module) . "'
409                          AND module_class = '" . $this->db->sql_escape($class) . "'
410                          $parent_sql";
411                  $result = $this->db->sql_query($sql);
412                  while ($module_id = $this->db->sql_fetchfield('module_id'))
413                  {
414                      $module_ids[] = (int) $module_id;
415                  }
416                  $this->db->sql_freeresult($result);
417              }
418              else
419              {
420                  $module_ids[] = (int) $module;
421              }
422   
423              foreach ($module_ids as $module_id)
424              {
425                  $this->module_manager->delete_module($module_id, $class);
426              }
427   
428              $this->module_manager->remove_cache_file($class);
429          }
430      }
431   
432      /**
433      * {@inheritdoc}
434      */
435      public function reverse()
436      {
437          $arguments = func_get_args();
438          $original_call = array_shift($arguments);
439   
440          $call = false;
441          switch ($original_call)
442          {
443              case 'add':
444                  $call = 'remove';
445              break;
446   
447              case 'remove':
448                  $call = 'add';
449              break;
450   
451              case 'reverse':
452                  // Reversing a reverse is just the call itself
453                  $call = array_shift($arguments);
454              break;
455          }
456   
457          if ($call)
458          {
459              return call_user_func_array(array(&$this, $call), $arguments);
460          }
461      }
462   
463      /**
464      * Wrapper for \acp_modules::get_module_infos()
465      *
466      * @param string $class Module Class
467      * @param string $basename Module Basename
468      * @return array Module Information
469      * @throws \phpbb\db\migration\exception
470      */
471      protected function get_module_info($class, $basename)
472      {
473          $module = $this->module_manager->get_module_infos($class, $basename, true);
474   
475          if (empty($module))
476          {
477              throw new \phpbb\db\migration\exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename);
478          }
479   
480          return array_pop($module);
481      }
482   
483      /**
484      * Get the list of installed module categories
485      *    key - module_id
486      *    value - module_langname
487      *
488      * @return null
489      */
490      protected function get_categories_list()
491      {
492          // Select the top level categories
493          // and 2nd level [sub]categories
494          $sql = 'SELECT m2.module_id, m2.module_langname
495              FROM ' . $this->modules_table . ' m1, ' . $this->modules_table . " m2
496              WHERE m1.parent_id = 0
497                  AND (m1.module_id = m2.module_id OR m2.parent_id = m1.module_id)
498              ORDER BY m1.module_id, m2.module_id ASC";
499   
500          $result = $this->db->sql_query($sql);
501          while ($row = $this->db->sql_fetchrow($result))
502          {
503              $this->module_categories[(int) $row['module_id']] = $row['module_langname'];
504          }
505          $this->db->sql_freeresult($result);
506      }
507   
508      /**
509      * Get parent module id
510      *
511      * @param string|int $parent_id The parent module_id|module_langname
512      * @param int|string|array $data The module_id, module_langname for existence checking or module data array for adding
513      * @param bool $throw_exception The flag indicating if exception should be thrown on error
514      * @return mixed The int parent module_id, an array of int parent module_id values or false
515      * @throws \phpbb\db\migration\exception
516      */
517      public function get_parent_module_id($parent_id, $data = '', $throw_exception = true)
518      {
519          // Allow '' to be sent as 0
520          $parent_id = $parent_id ?: 0;
521   
522          if (!is_numeric($parent_id))
523          {
524              // Refresh the $module_categories array
525              $this->get_categories_list();
526   
527              // Search for the parent module_langname
528              $ids = array_keys($this->module_categories, $parent_id);
529   
530              switch (count($ids))
531              {
532                  // No parent with the given module_langname exist
533                  case 0:
534                      if ($throw_exception)
535                      {
536                          throw new \phpbb\db\migration\exception('MODULE_NOT_EXIST', $parent_id);
537                      }
538   
539                      return false;
540                  break;
541   
542                  // Return the module id
543                  case 1:
544                      return (int) $ids[0];
545                  break;
546   
547                  default:
548                      // This represents the old behaviour of phpBB 3.0
549                      return $ids;
550                  break;
551              }
552          }
553   
554          return $parent_id;
555      }
556  }
557