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