Verzeichnisstruktur phpBB-3.1.0
- Veröffentlicht
- 27.10.2014
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
manager.php
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 Symfony\Component\DependencyInjection\ContainerInterface;
017
018 /**
019 * The extension manager provides means to activate/deactivate extensions.
020 */
021 class manager
022 {
023 /** @var ContainerInterface */
024 protected $container;
025
026 protected $db;
027 protected $config;
028 protected $cache;
029 protected $user;
030 protected $php_ext;
031 protected $extensions;
032 protected $extension_table;
033 protected $phpbb_root_path;
034 protected $cache_name;
035
036 /**
037 * Creates a manager and loads information from database
038 *
039 * @param ContainerInterface $container A container
040 * @param \phpbb\db\driver\driver_interface $db A database connection
041 * @param \phpbb\config\config $config Config object
042 * @param \phpbb\filesystem $filesystem
043 * @param \phpbb\user $user User object
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\driver\driver_interface $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, \phpbb\user $user, $extension_table, $phpbb_root_path, $php_ext = 'php', \phpbb\cache\driver\driver_interface $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 $this->user = $user;
062
063 $this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false;
064
065 if ($this->extensions === false)
066 {
067 $this->load_extensions();
068 }
069 }
070
071 /**
072 * Loads all extension information from the database
073 *
074 * @return null
075 */
076 public function load_extensions()
077 {
078 $this->extensions = array();
079
080 // Do not try to load any extensions if the extension table
081 // does not exist or when installing or updating.
082 // Note: database updater invokes this code, and in 3.0
083 // there is no extension table therefore the rest of this function
084 // fails
085 if (defined('IN_INSTALL') || version_compare($this->config['version'], '3.1.0-dev', '<'))
086 {
087 return;
088 }
089
090 $sql = 'SELECT *
091 FROM ' . $this->extension_table;
092
093 $result = $this->db->sql_query($sql);
094 $extensions = $this->db->sql_fetchrowset($result);
095 $this->db->sql_freeresult($result);
096
097 foreach ($extensions as $extension)
098 {
099 $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 * @param \phpbb\template\template $template The template manager
153 * @return \phpbb\extension\metadata_manager Instance of the metadata manager
154 */
155 public function create_extension_metadata_manager($name, \phpbb\template\template $template)
156 {
157 return new \phpbb\extension\metadata_manager($name, $this->config, $this, $template, $this->user, $this->phpbb_root_path);
158 }
159
160 /**
161 * Runs a step of the extension enabling process.
162 *
163 * Allows the exentension to enable in a long running script that works
164 * in multiple steps across requests. State is kept for the extension
165 * in the extensions table.
166 *
167 * @param string $name The extension's name
168 * @return bool False if enabling is finished, true otherwise
169 */
170 public function enable_step($name)
171 {
172 // ignore extensions that are already enabled
173 if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'])
174 {
175 return false;
176 }
177
178 $old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false;
179
180 $extension = $this->get_extension($name);
181
182 if (!$extension->is_enableable())
183 {
184 return false;
185 }
186
187 $state = $extension->enable_step($old_state);
188
189 $active = ($state === false);
190
191 $extension_data = array(
192 'ext_name' => $name,
193 'ext_active' => $active,
194 'ext_state' => serialize($state),
195 );
196
197 $this->extensions[$name] = $extension_data;
198 $this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']);
199 ksort($this->extensions);
200
201 $sql = 'SELECT COUNT(ext_name) as row_count
202 FROM ' . $this->extension_table . "
203 WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
204 $result = $this->db->sql_query($sql);
205 $count = $this->db->sql_fetchfield('row_count');
206 $this->db->sql_freeresult($result);
207
208 if ($count)
209 {
210 $sql = 'UPDATE ' . $this->extension_table . '
211 SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
212 WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
213 $this->db->sql_query($sql);
214 }
215 else
216 {
217 $sql = 'INSERT INTO ' . $this->extension_table . '
218 ' . $this->db->sql_build_array('INSERT', $extension_data);
219 $this->db->sql_query($sql);
220 }
221
222 if ($this->cache)
223 {
224 $this->cache->purge();
225 }
226
227 if ($active)
228 {
229 $this->config->increment('assets_version', 1);
230 }
231
232 return !$active;
233 }
234
235 /**
236 * Enables an extension
237 *
238 * This method completely enables an extension. But it could be long running
239 * so never call this in a script that has a max_execution time.
240 *
241 * @param string $name The extension's name
242 * @return null
243 */
244 public function enable($name)
245 {
246 // @codingStandardsIgnoreStart
247 while ($this->enable_step($name));
248 // @codingStandardsIgnoreEnd
249 }
250
251 /**
252 * Disables an extension
253 *
254 * Calls the disable method on the extension's meta class to allow it to
255 * process the event.
256 *
257 * @param string $name The extension's name
258 * @return bool False if disabling is finished, true otherwise
259 */
260 public function disable_step($name)
261 {
262 // ignore extensions that are already disabled
263 if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active'])
264 {
265 return false;
266 }
267
268 $old_state = unserialize($this->extensions[$name]['ext_state']);
269
270 $extension = $this->get_extension($name);
271 $state = $extension->disable_step($old_state);
272
273 // continue until the state is false
274 if ($state !== false)
275 {
276 $extension_data = array(
277 'ext_state' => serialize($state),
278 );
279 $this->extensions[$name]['ext_state'] = serialize($state);
280
281 $sql = 'UPDATE ' . $this->extension_table . '
282 SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
283 WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
284 $this->db->sql_query($sql);
285
286 if ($this->cache)
287 {
288 $this->cache->purge();
289 }
290
291 return true;
292 }
293
294 $extension_data = array(
295 'ext_active' => false,
296 'ext_state' => serialize(false),
297 );
298 $this->extensions[$name]['ext_active'] = false;
299 $this->extensions[$name]['ext_state'] = serialize(false);
300
301 $sql = 'UPDATE ' . $this->extension_table . '
302 SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
303 WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
304 $this->db->sql_query($sql);
305
306 if ($this->cache)
307 {
308 $this->cache->purge();
309 }
310
311 return false;
312 }
313
314 /**
315 * Disables an extension
316 *
317 * Disables an extension completely at once. This process could run for a
318 * while so never call this in a script that has a max_execution time.
319 *
320 * @param string $name The extension's name
321 * @return null
322 */
323 public function disable($name)
324 {
325 // @codingStandardsIgnoreStart
326 while ($this->disable_step($name));
327 // @codingStandardsIgnoreEnd
328 }
329
330 /**
331 * Purge an extension
332 *
333 * Disables the extension first if active, and then calls purge on the
334 * extension's meta class to delete the extension's database content.
335 *
336 * @param string $name The extension's name
337 * @return bool False if purging is finished, true otherwise
338 */
339 public function purge_step($name)
340 {
341 // ignore extensions that do not exist
342 if (!isset($this->extensions[$name]))
343 {
344 return false;
345 }
346
347 // disable first if necessary
348 if ($this->extensions[$name]['ext_active'])
349 {
350 $this->disable($name);
351 }
352
353 $old_state = unserialize($this->extensions[$name]['ext_state']);
354
355 $extension = $this->get_extension($name);
356 $state = $extension->purge_step($old_state);
357
358 // continue until the state is false
359 if ($state !== false)
360 {
361 $extension_data = array(
362 'ext_state' => serialize($state),
363 );
364 $this->extensions[$name]['ext_state'] = serialize($state);
365
366 $sql = 'UPDATE ' . $this->extension_table . '
367 SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
368 WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
369 $this->db->sql_query($sql);
370
371 if ($this->cache)
372 {
373 $this->cache->purge();
374 }
375
376 return true;
377 }
378
379 unset($this->extensions[$name]);
380
381 $sql = 'DELETE FROM ' . $this->extension_table . "
382 WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
383 $this->db->sql_query($sql);
384
385 if ($this->cache)
386 {
387 $this->cache->purge();
388 }
389
390 return false;
391 }
392
393 /**
394 * Purge an extension
395 *
396 * Purges an extension completely at once. This process could run for a while
397 * so never call this in a script that has a max_execution time.
398 *
399 * @param string $name The extension's name
400 * @return null
401 */
402 public function purge($name)
403 {
404 // @codingStandardsIgnoreStart
405 while ($this->purge_step($name));
406 // @codingStandardsIgnoreEnd
407 }
408
409 /**
410 * Retrieves a list of all available extensions on the filesystem
411 *
412 * @return array An array with extension names as keys and paths to the
413 * extension as values
414 */
415 public function all_available()
416 {
417 $available = array();
418 if (!is_dir($this->phpbb_root_path . 'ext/'))
419 {
420 return $available;
421 }
422
423 $iterator = new \RecursiveIteratorIterator(
424 new \phpbb\recursive_dot_prefix_filter_iterator(
425 new \RecursiveDirectoryIterator($this->phpbb_root_path . 'ext/', \FilesystemIterator::NEW_CURRENT_AND_KEY | \FilesystemIterator::FOLLOW_SYMLINKS)
426 ),
427 \RecursiveIteratorIterator::SELF_FIRST
428 );
429 $iterator->setMaxDepth(2);
430
431 foreach ($iterator as $file_info)
432 {
433 if ($file_info->isFile() && $file_info->getFilename() == 'composer.json')
434 {
435 $ext_name = $iterator->getInnerIterator()->getSubPath();
436 $composer_file = $iterator->getPath() . '/composer.json';
437
438 // Ignore the extension if there is no composer.json.
439 if (!is_readable($composer_file) || !($ext_info = file_get_contents($composer_file)))
440 {
441 continue;
442 }
443
444 $ext_info = json_decode($ext_info, true);
445 $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name);
446
447 // Ignore the extension if directory depth is not correct or if the directory structure
448 // does not match the name value specified in composer.json.
449 if (substr_count($ext_name, '/') !== 1 || !isset($ext_info['name']) || $ext_name != $ext_info['name'])
450 {
451 continue;
452 }
453
454 $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/';
455 }
456 }
457 ksort($available);
458 return $available;
459 }
460
461 /**
462 * Retrieves all configured extensions.
463 *
464 * All enabled and disabled extensions are considered configured. A purged
465 * extension that is no longer in the database is not configured.
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()
471 {
472 $configured = array();
473 foreach ($this->extensions as $name => $data)
474 {
475 $data['ext_path'] = $this->phpbb_root_path . $data['ext_path'];
476 $configured[$name] = $data;
477 }
478 return $configured;
479 }
480
481 /**
482 * Retrieves all enabled extensions.
483 *
484 * @return array An array with extension names as keys and and the
485 * database stored extension information as values
486 */
487 public function all_enabled()
488 {
489 $enabled = array();
490 foreach ($this->extensions as $name => $data)
491 {
492 if ($data['ext_active'])
493 {
494 $enabled[$name] = $this->phpbb_root_path . $data['ext_path'];
495 }
496 }
497 return $enabled;
498 }
499
500 /**
501 * Retrieves all disabled extensions.
502 *
503 * @return array An array with extension names as keys and and the
504 * database stored extension information as values
505 */
506 public function all_disabled()
507 {
508 $disabled = array();
509 foreach ($this->extensions as $name => $data)
510 {
511 if (!$data['ext_active'])
512 {
513 $disabled[$name] = $this->phpbb_root_path . $data['ext_path'];
514 }
515 }
516 return $disabled;
517 }
518
519 /**
520 * Check to see if a given extension is available on the filesystem
521 *
522 * @param string $name Extension name to check NOTE: Can be user input
523 * @return bool Depending on whether or not the extension is available
524 */
525 public function is_available($name)
526 {
527 return file_exists($this->get_extension_path($name, true));
528 }
529
530 /**
531 * Check to see if a given extension is enabled
532 *
533 * @param string $name Extension name to check
534 * @return bool Depending on whether or not the extension is enabled
535 */
536 public function is_enabled($name)
537 {
538 return isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'];
539 }
540
541 /**
542 * Check to see if a given extension is disabled
543 *
544 * @param string $name Extension name to check
545 * @return bool Depending on whether or not the extension is disabled
546 */
547 public function is_disabled($name)
548 {
549 return isset($this->extensions[$name]) && !$this->extensions[$name]['ext_active'];
550 }
551
552 /**
553 * Check to see if a given extension is configured
554 *
555 * All enabled and disabled extensions are considered configured. A purged
556 * extension that is no longer in the database is not configured.
557 *
558 * @param string $name Extension name to check
559 * @return bool Depending on whether or not the extension is configured
560 */
561 public function is_configured($name)
562 {
563 return isset($this->extensions[$name]);
564 }
565
566 /**
567 * Check to see if a given extension is purged
568 *
569 * An extension is purged if it is available, not enabled and not disabled.
570 *
571 * @param string $name Extension name to check
572 * @return bool Depending on whether or not the extension is purged
573 */
574 public function is_purged($name)
575 {
576 return $this->is_available($name) && !$this->is_configured($name);
577 }
578
579 /**
580 * Instantiates a \phpbb\finder.
581 *
582 * @param bool $use_all_available Should we load all extensions, or just enabled ones
583 * @return \phpbb\finder An extension finder instance
584 */
585 public function get_finder($use_all_available = false)
586 {
587 $finder = new \phpbb\finder($this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder');
588 if ($use_all_available)
589 {
590 $finder->set_extensions(array_keys($this->all_available()));
591 }
592 else
593 {
594 $finder->set_extensions(array_keys($this->all_enabled()));
595 }
596 return $finder;
597 }
598 }
599