[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

/phpbb/extension/ -> manager.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  namespace phpbb\extension;
  15  
  16  use phpbb\exception\runtime_exception;
  17  use phpbb\file_downloader;
  18  use Symfony\Component\DependencyInjection\ContainerInterface;
  19  
  20  /**
  21  * The extension manager provides means to activate/deactivate extensions.
  22  */
  23  class manager
  24  {
  25      /** @var ContainerInterface */
  26      protected $container;
  27  
  28      protected $db;
  29      protected $config;
  30      protected $cache;
  31      protected $php_ext;
  32      protected $extensions;
  33      protected $extension_table;
  34      protected $filesystem;
  35      protected $phpbb_root_path;
  36      protected $cache_name;
  37  
  38      /**
  39      * Creates a manager and loads information from database
  40      *
  41      * @param ContainerInterface $container A container
  42      * @param \phpbb\db\driver\driver_interface $db A database connection
  43      * @param \phpbb\config\config $config Config object
  44      * @param \phpbb\filesystem\filesystem_interface $filesystem
  45      * @param string $extension_table The name of the table holding extensions
  46      * @param string $phpbb_root_path Path to the phpbb includes directory.
  47      * @param string $php_ext php file extension, defaults to php
  48      * @param \phpbb\cache\service $cache A cache instance or null
  49      * @param string $cache_name The name of the cache variable, defaults to _ext
  50      */
  51  	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')
  52      {
  53          $this->cache = $cache;
  54          $this->cache_name = $cache_name;
  55          $this->config = $config;
  56          $this->container = $container;
  57          $this->db = $db;
  58          $this->extension_table = $extension_table;
  59          $this->filesystem = $filesystem;
  60          $this->phpbb_root_path = $phpbb_root_path;
  61          $this->php_ext = $php_ext;
  62  
  63          $this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false;
  64  
  65          if ($this->extensions === false)
  66          {
  67              $this->load_extensions();
  68          }
  69      }
  70  
  71      /**
  72      * Loads all extension information from the database
  73      *
  74      * @return null
  75      */
  76  	public function load_extensions()
  77      {
  78          $this->extensions = array();
  79  
  80          // Do not try to load any extensions if the extension table
  81          // does not exist or when installing or updating.
  82          // Note: database updater invokes this code, and in 3.0
  83          // there is no extension table therefore the rest of this function
  84          // fails
  85          if (defined('IN_INSTALL') || version_compare($this->config['version'], '3.1.0-dev', '<'))
  86          {
  87              return;
  88          }
  89  
  90          $sql = 'SELECT *
  91              FROM ' . $this->extension_table;
  92  
  93          $result = $this->db->sql_query($sql);
  94          $extensions = $this->db->sql_fetchrowset($result);
  95          $this->db->sql_freeresult($result);
  96  
  97          foreach ($extensions as $extension)
  98          {
  99              $extension['ext_path'] = $this->get_extension_path($extension['ext_name']);
 100              $this->extensions[$extension['ext_name']] = $extension;
 101          }
 102  
 103          ksort($this->extensions);
 104  
 105          if ($this->cache)
 106          {
 107              $this->cache->put($this->cache_name, $this->extensions);
 108          }
 109      }
 110  
 111      /**
 112      * Generates the path to an extension
 113      *
 114      * @param string $name The name of the extension
 115      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 116      * @return string Path to an extension
 117      */
 118  	public function get_extension_path($name, $phpbb_relative = false)
 119      {
 120          $name = str_replace('.', '', $name);
 121  
 122          return (($phpbb_relative) ? $this->phpbb_root_path : '') . 'ext/' . $name . '/';
 123      }
 124  
 125      /**
 126      * Instantiates the extension meta class for the extension with the given name
 127      *
 128      * @param string $name The extension name
 129      * @return \phpbb\extension\extension_interface Instance of the extension meta class or
 130      *                     \phpbb\extension\base if the class does not exist
 131      */
 132  	public function get_extension($name)
 133      {
 134          $extension_class_name = str_replace('/', '\\', $name) . '\\ext';
 135  
 136          $migrator = $this->container->get('migrator');
 137  
 138          if (class_exists($extension_class_name))
 139          {
 140              return new $extension_class_name($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true));
 141          }
 142          else
 143          {
 144              return new \phpbb\extension\base($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true));
 145          }
 146      }
 147  
 148      /**
 149      * Instantiates the metadata manager for the extension with the given name
 150      *
 151      * @param string $name The extension name
 152      * @return \phpbb\extension\metadata_manager Instance of the metadata manager
 153      */
 154  	public function create_extension_metadata_manager($name)
 155      {
 156          if (!isset($this->extensions[$name]['metadata']))
 157          {
 158              $metadata = new \phpbb\extension\metadata_manager($name, $this->get_extension_path($name, true));
 159              $this->extensions[$name]['metadata'] = $metadata;
 160          }
 161          return $this->extensions[$name]['metadata'];
 162      }
 163  
 164      /**
 165      * Update the database entry for an extension
 166      *
 167      * @param string $name Extension name to update
 168      * @param array    $data Data to update in the database
 169      * @param string    $action Action to perform, by default 'update', may be also 'insert' or 'delete'
 170      */
 171  	protected function update_state($name, $data, $action = 'update')
 172      {
 173          switch ($action)
 174          {
 175              case 'insert':
 176                  $this->extensions[$name] = $data;
 177                  $this->extensions[$name]['ext_path'] = $this->get_extension_path($name);
 178                  ksort($this->extensions);
 179                  $sql = 'INSERT INTO ' . $this->extension_table . ' ' . $this->db->sql_build_array('INSERT', $data);
 180                  $this->db->sql_query($sql);
 181              break;
 182  
 183              case 'update':
 184                  $this->extensions[$name] = array_merge($this->extensions[$name], $data);
 185                  $sql = 'UPDATE ' . $this->extension_table . '
 186                      SET ' . $this->db->sql_build_array('UPDATE', $data) . "
 187                      WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 188                  $this->db->sql_query($sql);
 189              break;
 190  
 191              case 'delete':
 192                  unset($this->extensions[$name]);
 193                  $sql = 'DELETE FROM ' . $this->extension_table . "
 194                      WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
 195                  $this->db->sql_query($sql);
 196              break;
 197          }
 198  
 199          if ($this->cache)
 200          {
 201              $this->cache->deferred_purge();
 202          }
 203      }
 204  
 205      /**
 206      * Runs a step of the extension enabling process.
 207      *
 208      * Allows the exentension to enable in a long running script that works
 209      * in multiple steps across requests. State is kept for the extension
 210      * in the extensions table.
 211      *
 212      * @param    string    $name    The extension's name
 213      * @return    bool            False if enabling is finished, true otherwise
 214      */
 215  	public function enable_step($name)
 216      {
 217          // ignore extensions that are already enabled
 218          if ($this->is_enabled($name))
 219          {
 220              return false;
 221          }
 222  
 223          $old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false;
 224  
 225          $extension = $this->get_extension($name);
 226  
 227          if (!$extension->is_enableable())
 228          {
 229              return false;
 230          }
 231  
 232          $state = $extension->enable_step($old_state);
 233  
 234          $active = ($state === false);
 235  
 236          $extension_data = array(
 237              'ext_name'        => $name,
 238              'ext_active'    => $active,
 239              'ext_state'        => serialize($state),
 240          );
 241  
 242          $this->update_state($name, $extension_data, $this->is_configured($name) ? 'update' : 'insert');
 243  
 244          if ($active)
 245          {
 246              $this->config->increment('assets_version', 1);
 247          }
 248  
 249          return !$active;
 250      }
 251  
 252      /**
 253      * Enables an extension
 254      *
 255      * This method completely enables an extension. But it could be long running
 256      * so never call this in a script that has a max_execution time.
 257      *
 258      * @param string $name The extension's name
 259      * @return null
 260      */
 261  	public function enable($name)
 262      {
 263          // @codingStandardsIgnoreStart
 264          while ($this->enable_step($name));
 265          // @codingStandardsIgnoreEnd
 266      }
 267  
 268      /**
 269      * Disables an extension
 270      *
 271      * Calls the disable method on the extension's meta class to allow it to
 272      * process the event.
 273      *
 274      * @param string $name The extension's name
 275      * @return bool False if disabling is finished, true otherwise
 276      */
 277  	public function disable_step($name)
 278      {
 279          // ignore extensions that are not enabled
 280          if (!$this->is_enabled($name))
 281          {
 282              return false;
 283          }
 284  
 285          $old_state = unserialize($this->extensions[$name]['ext_state']);
 286  
 287          $extension = $this->get_extension($name);
 288          $state = $extension->disable_step($old_state);
 289          $active = ($state !== false);
 290  
 291          $extension_data = array(
 292              'ext_active'    => $active,
 293              'ext_state'        => serialize($state),
 294          );
 295          $this->update_state($name, $extension_data);
 296  
 297          return $active;
 298      }
 299  
 300      /**
 301      * Disables an extension
 302      *
 303      * Disables an extension completely at once. This process could run for a
 304      * while so never call this in a script that has a max_execution time.
 305      *
 306      * @param string $name The extension's name
 307      * @return null
 308      */
 309  	public function disable($name)
 310      {
 311          // @codingStandardsIgnoreStart
 312          while ($this->disable_step($name));
 313          // @codingStandardsIgnoreEnd
 314      }
 315  
 316      /**
 317      * Purge an extension
 318      *
 319      * Disables the extension first if active, and then calls purge on the
 320      * extension's meta class to delete the extension's database content.
 321      *
 322      * @param string $name The extension's name
 323      * @return bool False if purging is finished, true otherwise
 324      */
 325  	public function purge_step($name)
 326      {
 327          // ignore extensions that are not configured
 328          if (!$this->is_configured($name))
 329          {
 330              return false;
 331          }
 332  
 333          // disable first if necessary
 334          if ($this->extensions[$name]['ext_active'])
 335          {
 336              $this->disable($name);
 337          }
 338  
 339          $old_state = unserialize($this->extensions[$name]['ext_state']);
 340  
 341          $extension = $this->get_extension($name);
 342          $state = $extension->purge_step($old_state);
 343          $purged = ($state === false);
 344  
 345          $extension_data = array(
 346              'ext_state'    => serialize($state),
 347          );
 348  
 349          $this->update_state($name, $extension_data, $purged ? 'delete' : 'update');
 350  
 351          // continue until the state is false
 352          return !$purged;
 353      }
 354  
 355      /**
 356      * Purge an extension
 357      *
 358      * Purges an extension completely at once. This process could run for a while
 359      * so never call this in a script that has a max_execution time.
 360      *
 361      * @param string $name The extension's name
 362      * @return null
 363      */
 364  	public function purge($name)
 365      {
 366          // @codingStandardsIgnoreStart
 367          while ($this->purge_step($name));
 368          // @codingStandardsIgnoreEnd
 369      }
 370  
 371      /**
 372      * Retrieves a list of all available extensions on the filesystem
 373      *
 374      * @return array An array with extension names as keys and paths to the
 375      *               extension as values
 376      */
 377  	public function all_available()
 378      {
 379          $available = array();
 380          if (!is_dir($this->phpbb_root_path . 'ext/'))
 381          {
 382              return $available;
 383          }
 384  
 385          $iterator = new \RecursiveIteratorIterator(
 386              new \phpbb\recursive_dot_prefix_filter_iterator(
 387                  new \RecursiveDirectoryIterator($this->phpbb_root_path . 'ext/', \FilesystemIterator::NEW_CURRENT_AND_KEY | \FilesystemIterator::FOLLOW_SYMLINKS)
 388              ),
 389              \RecursiveIteratorIterator::SELF_FIRST
 390          );
 391          $iterator->setMaxDepth(2);
 392  
 393          foreach ($iterator as $file_info)
 394          {
 395              if ($file_info->isFile() && $file_info->getFilename() == 'composer.json')
 396              {
 397                  $ext_name = $iterator->getInnerIterator()->getSubPath();
 398                  $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name);
 399                  if ($this->is_available($ext_name))
 400                  {
 401                      $available[$ext_name] = $this->get_extension_path($ext_name, true);
 402                  }
 403              }
 404          }
 405          ksort($available);
 406          return $available;
 407      }
 408  
 409      /**
 410      * Retrieves all configured extensions.
 411      *
 412      * All enabled and disabled extensions are considered configured. A purged
 413      * extension that is no longer in the database is not configured.
 414      *
 415      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 416      *
 417      * @return array An array with extension names as keys and and the
 418      *               database stored extension information as values
 419      */
 420  	public function all_configured($phpbb_relative = true)
 421      {
 422          $configured = array();
 423          foreach ($this->extensions as $name => $data)
 424          {
 425              if ($this->is_configured($name))
 426              {
 427                  unset($data['metadata']);
 428                  $data['ext_path'] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
 429                  $configured[$name] = $data;
 430              }
 431          }
 432          return $configured;
 433      }
 434  
 435      /**
 436      * Retrieves all enabled extensions.
 437      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 438      *
 439      * @return array An array with extension names as keys and and the
 440      *               database stored extension information as values
 441      */
 442  	public function all_enabled($phpbb_relative = true)
 443      {
 444          $enabled = array();
 445          foreach ($this->extensions as $name => $data)
 446          {
 447              if ($this->is_enabled($name))
 448              {
 449                  $enabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
 450              }
 451          }
 452          return $enabled;
 453      }
 454  
 455      /**
 456      * Retrieves all disabled extensions.
 457      *
 458      * @param bool $phpbb_relative Whether the path should be relative to phpbb root
 459      *
 460      * @return array An array with extension names as keys and and the
 461      *               database stored extension information as values
 462      */
 463  	public function all_disabled($phpbb_relative = true)
 464      {
 465          $disabled = array();
 466          foreach ($this->extensions as $name => $data)
 467          {
 468              if ($this->is_disabled($name))
 469              {
 470                  $disabled[$name] = ($phpbb_relative ? $this->phpbb_root_path : '') . $data['ext_path'];
 471              }
 472          }
 473          return $disabled;
 474      }
 475  
 476      /**
 477      * Check to see if a given extension is available on the filesystem
 478      *
 479      * @param string $name Extension name to check NOTE: Can be user input
 480      * @return bool Depending on whether or not the extension is available
 481      */
 482  	public function is_available($name)
 483      {
 484          $md_manager = $this->create_extension_metadata_manager($name);
 485          try
 486          {
 487              return $md_manager->get_metadata('all') && $md_manager->validate_enable();
 488          }
 489          catch (\phpbb\extension\exception $e)
 490          {
 491              return false;
 492          }
 493      }
 494  
 495      /**
 496      * Check to see if a given extension is enabled
 497      *
 498      * @param string $name Extension name to check
 499      * @return bool Depending on whether or not the extension is enabled
 500      */
 501  	public function is_enabled($name)
 502      {
 503          return isset($this->extensions[$name]['ext_active']) && $this->extensions[$name]['ext_active'];
 504      }
 505  
 506      /**
 507      * Check to see if a given extension is disabled
 508      *
 509      * @param string $name Extension name to check
 510      * @return bool Depending on whether or not the extension is disabled
 511      */
 512  	public function is_disabled($name)
 513      {
 514          return isset($this->extensions[$name]['ext_active']) && !$this->extensions[$name]['ext_active'];
 515      }
 516  
 517      /**
 518      * Check to see if a given extension is configured
 519      *
 520      * All enabled and disabled extensions are considered configured. A purged
 521      * extension that is no longer in the database is not configured.
 522      *
 523      * @param string $name Extension name to check
 524      * @return bool Depending on whether or not the extension is configured
 525      */
 526  	public function is_configured($name)
 527      {
 528          return isset($this->extensions[$name]['ext_active']);
 529      }
 530  
 531      /**
 532      * Check the version and return the available updates (for an extension).
 533      *
 534      * @param \phpbb\extension\metadata_manager $md_manager The metadata manager for the version to check.
 535      * @param bool $force_update Ignores cached data. Defaults to false.
 536      * @param bool $force_cache Force the use of the cache. Override $force_update.
 537      * @param string $stability Force the stability (null by default).
 538      * @return array
 539      * @throws runtime_exception
 540      */
 541  	public function version_check(\phpbb\extension\metadata_manager $md_manager, $force_update = false, $force_cache = false, $stability = null)
 542      {
 543          $meta = $md_manager->get_metadata('all');
 544  
 545          if (!isset($meta['extra']['version-check']))
 546          {
 547              throw new runtime_exception('NO_VERSIONCHECK');
 548          }
 549  
 550          $version_check = $meta['extra']['version-check'];
 551  
 552          $version_helper = new \phpbb\version_helper($this->cache, $this->config, new file_downloader());
 553          $version_helper->set_current_version($meta['version']);
 554          $version_helper->set_file_location($version_check['host'], $version_check['directory'], $version_check['filename'], isset($version_check['ssl']) ? $version_check['ssl'] : false);
 555          $version_helper->force_stability($stability);
 556  
 557          return $version_helper->get_ext_update_on_branch($force_update, $force_cache);
 558      }
 559  
 560      /**
 561      * Check to see if a given extension is purged
 562      *
 563      * An extension is purged if it is available, not enabled and not disabled.
 564      *
 565      * @param string $name Extension name to check
 566      * @return bool Depending on whether or not the extension is purged
 567      */
 568  	public function is_purged($name)
 569      {
 570          return $this->is_available($name) && !$this->is_configured($name);
 571      }
 572  
 573      /**
 574      * Instantiates a \phpbb\finder.
 575      *
 576      * @param bool $use_all_available Should we load all extensions, or just enabled ones
 577      * @return \phpbb\finder An extension finder instance
 578      */
 579  	public function get_finder($use_all_available = false)
 580      {
 581          $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder');
 582          if ($use_all_available)
 583          {
 584              $finder->set_extensions(array_keys($this->all_available()));
 585          }
 586          else
 587          {
 588              $finder->set_extensions(array_keys($this->all_enabled()));
 589          }
 590          return $finder;
 591      }
 592  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1