Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

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

manager.php

Zuletzt modifiziert: 09.10.2024, 12:52 - Dateigröße: 17.44 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\extension;
 015   
 016  use phpbb\exception\runtime_exception;
 017  use phpbb\file_downloader;
 018  use Symfony\Component\DependencyInjection\ContainerInterface;
 019   
 020  /**
 021  * The extension manager provides means to activate/deactivate extensions.
 022  */
 023  class manager
 024  {
 025      /** @var ContainerInterface */
 026      protected $container;
 027   
 028      protected $db;
 029      protected $config;
 030      protected $cache;
 031      protected $php_ext;
 032      protected $extensions;
 033      protected $extension_table;
 034      protected $phpbb_root_path;
 035      protected $cache_name;
 036   
 037      /**
 038      * Creates a manager and loads information from database
 039      *
 040      * @param ContainerInterface $container A container
 041      * @param \phpbb\db\driver\driver_interface $db A database connection
 042      * @param \phpbb\config\config $config Config object
 043      * @param \phpbb\filesystem\filesystem_interface $filesystem
 044      * @param string $extension_table The name of the table holding extensions
 045      * @param string $phpbb_root_path Path to the phpbb includes directory.
 046      * @param string $php_ext php file extension, defaults to php
 047      * @param \phpbb\cache\service $cache A cache instance or null
 048      * @param string $cache_name The name of the cache variable, defaults to _ext
 049      */
 050      public function __construct(ContainerInterface $container, \phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, \phpbb\filesystem\filesystem_interface $filesystem, $extension_table, $phpbb_root_path, $php_ext = 'php', \phpbb\cache\service $cache = null, $cache_name = '_ext')
 051      {
 052          $this->cache = $cache;
 053          $this->cache_name = $cache_name;
 054          $this->config = $config;
 055          $this->container = $container;
 056          $this->db = $db;
 057          $this->extension_table = $extension_table;
 058          $this->filesystem = $filesystem;
 059          $this->phpbb_root_path = $phpbb_root_path;
 060          $this->php_ext = $php_ext;
 061   
 062          $this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false;
 063   
 064          if ($this->extensions === false)
 065          {
 066              $this->load_extensions();
 067          }
 068      }
 069   
 070      /**
 071      * Loads all extension information from the database
 072      *
 073      * @return null
 074      */
 075      public function load_extensions()
 076      {
 077          $this->extensions = array();
 078   
 079          // Do not try to load any extensions if the extension table
 080          // does not exist or when installing or updating.
 081          // Note: database updater invokes this code, and in 3.0
 082          // there is no extension table therefore the rest of this function
 083          // fails
 084          if (defined('IN_INSTALL') || version_compare($this->config['version'], '3.1.0-dev', '<'))
 085          {
 086              return;
 087          }
 088   
 089          $sql = 'SELECT *
 090              FROM ' . $this->extension_table;
 091   
 092          $result = $this->db->sql_query($sql);
 093          $extensions = $this->db->sql_fetchrowset($result);
 094          $this->db->sql_freeresult($result);
 095   
 096          foreach ($extensions as $extension)
 097          {
 098              $extension['ext_path'] = $this->get_extension_path($extension['ext_name']);
 099              $this->extensions[$extension['ext_name']] = $extension;
 100          }
 101   
 102          ksort($this->extensions);
 103   
 104          if ($this->cache)
 105          {
 106              $this->cache->put($this->cache_name, $this->extensions);
 107          }
 108      }
 109   
 110      /**
 111      * Generates the path to an extension
 112      *
 113      * @param string $name The name of the extension
 114      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 115      * @return string Path to an extension
 116      */
 117      public function get_extension_path($name, $phpbb_relative = false)
 118      {
 119          $name = str_replace('.', '', $name);
 120   
 121          return (($phpbb_relative) ? $this->phpbb_root_path : '') . 'ext/' . $name . '/';
 122      }
 123   
 124      /**
 125      * Instantiates the extension meta class for the extension with the given name
 126      *
 127      * @param string $name The extension name
 128      * @return \phpbb\extension\extension_interface Instance of the extension meta class or
 129      *                     \phpbb\extension\base if the class does not exist
 130      */
 131      public function get_extension($name)
 132      {
 133          $extension_class_name = str_replace('/', '\\', $name) . '\\ext';
 134   
 135          $migrator = $this->container->get('migrator');
 136   
 137          if (class_exists($extension_class_name))
 138          {
 139              return new $extension_class_name($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true));
 140          }
 141          else
 142          {
 143              return new \phpbb\extension\base($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true));
 144          }
 145      }
 146   
 147      /**
 148      * Instantiates the metadata manager for the extension with the given name
 149      *
 150      * @param string $name The extension name
 151      * @return \phpbb\extension\metadata_manager Instance of the metadata manager
 152      */
 153      public function create_extension_metadata_manager($name)
 154      {
 155          return new \phpbb\extension\metadata_manager($name, $this->config, $this, $this->phpbb_root_path);
 156      }
 157   
 158      /**
 159      * Runs a step of the extension enabling process.
 160      *
 161      * Allows the exentension to enable in a long running script that works
 162      * in multiple steps across requests. State is kept for the extension
 163      * in the extensions table.
 164      *
 165      * @param    string    $name    The extension's name
 166      * @return    bool            False if enabling is finished, true otherwise
 167      */
 168      public function enable_step($name)
 169      {
 170          // ignore extensions that are already enabled
 171          if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'])
 172          {
 173              return false;
 174          }
 175   
 176          $old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false;
 177   
 178          $extension = $this->get_extension($name);
 179   
 180          if (!$extension->is_enableable())
 181          {
 182              return false;
 183          }
 184   
 185          $state = $extension->enable_step($old_state);
 186   
 187          $active = ($state === false);
 188   
 189          $extension_data = array(
 190              'ext_name'        => $name,
 191              'ext_active'    => $active,
 192              'ext_state'        => serialize($state),
 193          );
 194   
 195          $this->extensions[$name] = $extension_data;
 196          $this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']);
 197          ksort($this->extensions);
 198   
 199          $sql = 'SELECT COUNT(ext_name) as row_count
 200              FROM ' . $this->extension_table . "
 201              WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 202          $result = $this->db->sql_query($sql);
 203          $count = $this->db->sql_fetchfield('row_count');
 204          $this->db->sql_freeresult($result);
 205   
 206          if ($count)
 207          {
 208              $sql = 'UPDATE ' . $this->extension_table . '
 209                  SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
 210                  WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 211              $this->db->sql_query($sql);
 212          }
 213          else
 214          {
 215              $sql = 'INSERT INTO ' . $this->extension_table . '
 216                  ' . $this->db->sql_build_array('INSERT', $extension_data);
 217              $this->db->sql_query($sql);
 218          }
 219   
 220          if ($this->cache)
 221          {
 222              $this->cache->purge();
 223          }
 224   
 225          if ($active)
 226          {
 227              $this->config->increment('assets_version', 1);
 228          }
 229   
 230          return !$active;
 231      }
 232   
 233      /**
 234      * Enables an extension
 235      *
 236      * This method completely enables an extension. But it could be long running
 237      * so never call this in a script that has a max_execution time.
 238      *
 239      * @param string $name The extension's name
 240      * @return null
 241      */
 242      public function enable($name)
 243      {
 244          // @codingStandardsIgnoreStart
 245          while ($this->enable_step($name));
 246          // @codingStandardsIgnoreEnd
 247      }
 248   
 249      /**
 250      * Disables an extension
 251      *
 252      * Calls the disable method on the extension's meta class to allow it to
 253      * process the event.
 254      *
 255      * @param string $name The extension's name
 256      * @return bool False if disabling is finished, true otherwise
 257      */
 258      public function disable_step($name)
 259      {
 260          // ignore extensions that are already disabled
 261          if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active'])
 262          {
 263              return false;
 264          }
 265   
 266          $old_state = unserialize($this->extensions[$name]['ext_state']);
 267   
 268          $extension = $this->get_extension($name);
 269          $state = $extension->disable_step($old_state);
 270   
 271          // continue until the state is false
 272          if ($state !== false)
 273          {
 274              $extension_data = array(
 275                  'ext_state'        => serialize($state),
 276              );
 277              $this->extensions[$name]['ext_state'] = serialize($state);
 278   
 279              $sql = 'UPDATE ' . $this->extension_table . '
 280                  SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
 281                  WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 282              $this->db->sql_query($sql);
 283   
 284              if ($this->cache)
 285              {
 286                  $this->cache->purge();
 287              }
 288   
 289              return true;
 290          }
 291   
 292          $extension_data = array(
 293              'ext_active'    => false,
 294              'ext_state'        => serialize(false),
 295          );
 296          $this->extensions[$name]['ext_active'] = false;
 297          $this->extensions[$name]['ext_state'] = serialize(false);
 298   
 299          $sql = 'UPDATE ' . $this->extension_table . '
 300              SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
 301              WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 302          $this->db->sql_query($sql);
 303   
 304          if ($this->cache)
 305          {
 306              $this->cache->purge();
 307          }
 308   
 309          return false;
 310      }
 311   
 312      /**
 313      * Disables an extension
 314      *
 315      * Disables an extension completely at once. This process could run for a
 316      * while so never call this in a script that has a max_execution time.
 317      *
 318      * @param string $name The extension's name
 319      * @return null
 320      */
 321      public function disable($name)
 322      {
 323          // @codingStandardsIgnoreStart
 324          while ($this->disable_step($name));
 325          // @codingStandardsIgnoreEnd
 326      }
 327   
 328      /**
 329      * Purge an extension
 330      *
 331      * Disables the extension first if active, and then calls purge on the
 332      * extension's meta class to delete the extension's database content.
 333      *
 334      * @param string $name The extension's name
 335      * @return bool False if purging is finished, true otherwise
 336      */
 337      public function purge_step($name)
 338      {
 339          // ignore extensions that do not exist
 340          if (!isset($this->extensions[$name]))
 341          {
 342              return false;
 343          }
 344   
 345          // disable first if necessary
 346          if ($this->extensions[$name]['ext_active'])
 347          {
 348              $this->disable($name);
 349          }
 350   
 351          $old_state = unserialize($this->extensions[$name]['ext_state']);
 352   
 353          $extension = $this->get_extension($name);
 354          $state = $extension->purge_step($old_state);
 355   
 356          // continue until the state is false
 357          if ($state !== false)
 358          {
 359              $extension_data = array(
 360                  'ext_state'        => serialize($state),
 361              );
 362              $this->extensions[$name]['ext_state'] = serialize($state);
 363   
 364              $sql = 'UPDATE ' . $this->extension_table . '
 365                  SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
 366                  WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 367              $this->db->sql_query($sql);
 368   
 369              if ($this->cache)
 370              {
 371                  $this->cache->purge();
 372              }
 373   
 374              return true;
 375          }
 376   
 377          unset($this->extensions[$name]);
 378   
 379          $sql = 'DELETE FROM ' . $this->extension_table . "
 380              WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 381          $this->db->sql_query($sql);
 382   
 383          if ($this->cache)
 384          {
 385              $this->cache->purge();
 386          }
 387   
 388          return false;
 389      }
 390   
 391      /**
 392      * Purge an extension
 393      *
 394      * Purges an extension completely at once. This process could run for a while
 395      * so never call this in a script that has a max_execution time.
 396      *
 397      * @param string $name The extension's name
 398      * @return null
 399      */
 400      public function purge($name)
 401      {
 402          // @codingStandardsIgnoreStart
 403          while ($this->purge_step($name));
 404          // @codingStandardsIgnoreEnd
 405      }
 406   
 407      /**
 408      * Retrieves a list of all available extensions on the filesystem
 409      *
 410      * @return array An array with extension names as keys and paths to the
 411      *               extension as values
 412      */
 413      public function all_available()
 414      {
 415          $available = array();
 416          if (!is_dir($this->phpbb_root_path . 'ext/'))
 417          {
 418              return $available;
 419          }
 420   
 421          $iterator = new \RecursiveIteratorIterator(
 422              new \phpbb\recursive_dot_prefix_filter_iterator(
 423                  new \RecursiveDirectoryIterator($this->phpbb_root_path . 'ext/', \FilesystemIterator::NEW_CURRENT_AND_KEY | \FilesystemIterator::FOLLOW_SYMLINKS)
 424              ),
 425              \RecursiveIteratorIterator::SELF_FIRST
 426          );
 427          $iterator->setMaxDepth(2);
 428   
 429          foreach ($iterator as $file_info)
 430          {
 431              if ($file_info->isFile() && $file_info->getFilename() == 'composer.json')
 432              {
 433                  $ext_name = $iterator->getInnerIterator()->getSubPath();
 434                  $composer_file = $iterator->getPath() . '/composer.json';
 435   
 436                  // Ignore the extension if there is no composer.json.
 437                  if (!is_readable($composer_file) || !($ext_info = file_get_contents($composer_file)))
 438                  {
 439                      continue;
 440                  }
 441   
 442                  $ext_info = json_decode($ext_info, true);
 443                  $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name);
 444   
 445                  // Ignore the extension if directory depth is not correct or if the directory structure
 446                  // does not match the name value specified in composer.json.
 447                  if (substr_count($ext_name, '/') !== 1 || !isset($ext_info['name']) || $ext_name != $ext_info['name'])
 448                  {
 449                      continue;
 450                  }
 451   
 452                  $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/';
 453              }
 454          }
 455          ksort($available);
 456          return $available;
 457      }
 458   
 459      /**
 460      * Retrieves all configured extensions.
 461      *
 462      * All enabled and disabled extensions are considered configured. A purged
 463      * extension that is no longer in the database is not configured.
 464      *
 465      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 466      *
 467      * @return array An array with extension names as keys and and the
 468      *               database stored extension information as values
 469      */
 470      public function all_configured($phpbb_relative = true)
 471      {
 472          $configured = array();
 473          foreach ($this->extensions as $name => $data)
 474          {
 475              $data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
 476              $configured[$name] = $data;
 477          }
 478          return $configured;
 479      }
 480   
 481      /**
 482      * Retrieves all enabled extensions.
 483      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 484      *
 485      * @return array An array with extension names as keys and and the
 486      *               database stored extension information as values
 487      */
 488      public function all_enabled($phpbb_relative = true)
 489      {
 490          $enabled = array();
 491          foreach ($this->extensions as $name => $data)
 492          {
 493              if ($data['ext_active'])
 494              {
 495                  $enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
 496              }
 497          }
 498          return $enabled;
 499      }
 500   
 501      /**
 502      * Retrieves all disabled extensions.
 503      *
 504      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 505      *
 506      * @return array An array with extension names as keys and and the
 507      *               database stored extension information as values
 508      */
 509      public function all_disabled($phpbb_relative = true)
 510      {
 511          $disabled = array();
 512          foreach ($this->extensions as $name => $data)
 513          {
 514              if (!$data['ext_active'])
 515              {
 516                  $disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
 517              }
 518          }
 519          return $disabled;
 520      }
 521   
 522      /**
 523      * Check to see if a given extension is available on the filesystem
 524      *
 525      * @param string $name Extension name to check NOTE: Can be user input
 526      * @return bool Depending on whether or not the extension is available
 527      */
 528      public function is_available($name)
 529      {
 530          return file_exists($this->get_extension_path($name, true));
 531      }
 532   
 533      /**
 534      * Check to see if a given extension is enabled
 535      *
 536      * @param string $name Extension name to check
 537      * @return bool Depending on whether or not the extension is enabled
 538      */
 539      public function is_enabled($name)
 540      {
 541          return isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'];
 542      }
 543   
 544      /**
 545      * Check to see if a given extension is disabled
 546      *
 547      * @param string $name Extension name to check
 548      * @return bool Depending on whether or not the extension is disabled
 549      */
 550      public function is_disabled($name)
 551      {
 552          return isset($this->extensions[$name]) && !$this->extensions[$name]['ext_active'];
 553      }
 554   
 555      /**
 556      * Check to see if a given extension is configured
 557      *
 558      * All enabled and disabled extensions are considered configured. A purged
 559      * extension that is no longer in the database is not configured.
 560      *
 561      * @param string $name Extension name to check
 562      * @return bool Depending on whether or not the extension is configured
 563      */
 564      public function is_configured($name)
 565      {
 566          return isset($this->extensions[$name]);
 567      }
 568   
 569      /**
 570      * Check the version and return the available updates (for an extension).
 571      *
 572      * @param \phpbb\extension\metadata_manager $md_manager The metadata manager for the version to check.
 573      * @param bool $force_update Ignores cached data. Defaults to false.
 574      * @param bool $force_cache Force the use of the cache. Override $force_update.
 575      * @param string $stability Force the stability (null by default).
 576      * @return string
 577      * @throws runtime_exception
 578      */
 579      public function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false, $stability = null)
 580      {
 581          $meta = $md_manager->get_metadata('all');
 582   
 583          if (!isset($meta['extra']['version-check']))
 584          {
 585              throw new runtime_exception('NO_VERSIONCHECK');
 586          }
 587   
 588          $version_check = $meta['extra']['version-check'];
 589   
 590          $version_helper = new \phpbb\version_helper($this->cache, $this->config, new file_downloader());
 591          $version_helper->set_current_version($meta['version']);
 592          $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename']);
 593          $version_helper->force_stability($stability);
 594   
 595          return $updates = $version_helper->get_suggested_updates($force_update, $force_cache);
 596      }
 597   
 598      /**
 599      * Check to see if a given extension is purged
 600      *
 601      * An extension is purged if it is available, not enabled and not disabled.
 602      *
 603      * @param string $name Extension name to check
 604      * @return bool Depending on whether or not the extension is purged
 605      */
 606      public function is_purged($name)
 607      {
 608          return $this->is_available($name) && !$this->is_configured($name);
 609      }
 610   
 611      /**
 612      * Instantiates a \phpbb\finder.
 613      *
 614      * @param bool $use_all_available Should we load all extensions, or just enabled ones
 615      * @return \phpbb\finder An extension finder instance
 616      */
 617      public function get_finder($use_all_available = false)
 618      {
 619          $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder');
 620          if ($use_all_available)
 621          {
 622              $finder->set_extensions(array_keys($this->all_available()));
 623          }
 624          else
 625          {
 626              $finder->set_extensions(array_keys($this->all_enabled()));
 627          }
 628          return $finder;
 629      }
 630  }
 631