14fd6a1d7SAndreas Gohr<?php 24fd6a1d7SAndreas Gohr 34fd6a1d7SAndreas Gohrnamespace dokuwiki\plugin\extension; 44fd6a1d7SAndreas Gohr 54fd6a1d7SAndreas Gohrclass Notice 64fd6a1d7SAndreas Gohr{ 77c184cfcSAndreas Gohr public const INFO = 'info'; 87c184cfcSAndreas Gohr public const WARNING = 'warning'; 97c184cfcSAndreas Gohr public const ERROR = 'error'; 107c184cfcSAndreas Gohr public const SECURITY = 'security'; 114fd6a1d7SAndreas Gohr 12*d2d4b908SAndreas Gohr protected const ICONS = [ 13*d2d4b908SAndreas Gohr self::INFO => 'I', 14*d2d4b908SAndreas Gohr self::WARNING => 'W', 15*d2d4b908SAndreas Gohr self::ERROR => 'E', 16*d2d4b908SAndreas Gohr self::SECURITY => 'S', 174fd6a1d7SAndreas Gohr ]; 184fd6a1d7SAndreas Gohr 194fd6a1d7SAndreas Gohr protected $notices = [ 204fd6a1d7SAndreas Gohr self::INFO => [], 214fd6a1d7SAndreas Gohr self::WARNING => [], 224fd6a1d7SAndreas Gohr self::ERROR => [], 234fd6a1d7SAndreas Gohr self::SECURITY => [], 244fd6a1d7SAndreas Gohr ]; 254fd6a1d7SAndreas Gohr 264fd6a1d7SAndreas Gohr /** @var \helper_plugin_extension */ 274fd6a1d7SAndreas Gohr protected $helper; 284fd6a1d7SAndreas Gohr 294fd6a1d7SAndreas Gohr /** @var Extension */ 304fd6a1d7SAndreas Gohr protected Extension $extension; 314fd6a1d7SAndreas Gohr 324fd6a1d7SAndreas Gohr /** 334fd6a1d7SAndreas Gohr * Not public, use list() instead 344fd6a1d7SAndreas Gohr * @param Extension $extension 354fd6a1d7SAndreas Gohr */ 364fd6a1d7SAndreas Gohr protected function __construct(Extension $extension) 374fd6a1d7SAndreas Gohr { 384fd6a1d7SAndreas Gohr $this->helper = plugin_load('helper', 'extension'); 394fd6a1d7SAndreas Gohr $this->extension = $extension; 404fd6a1d7SAndreas Gohr 414fd6a1d7SAndreas Gohr $this->checkSecurity(); 428fe483c9SAndreas Gohr $this->checkURLChange(); 434fd6a1d7SAndreas Gohr $this->checkFolder(); 444fd6a1d7SAndreas Gohr $this->checkPHPVersion(); 458fe483c9SAndreas Gohr $this->checkDependencies(); 468fe483c9SAndreas Gohr $this->checkConflicts(); 474fd6a1d7SAndreas Gohr $this->checkUpdateMessage(); 48981e70caSAndreas Gohr $this->checkPermissions(); 49981e70caSAndreas Gohr $this->checkUnusedAuth(); 50981e70caSAndreas Gohr $this->checkGit(); 514fd6a1d7SAndreas Gohr } 524fd6a1d7SAndreas Gohr 534fd6a1d7SAndreas Gohr /** 544fd6a1d7SAndreas Gohr * Get all notices for the extension 554fd6a1d7SAndreas Gohr * 564fd6a1d7SAndreas Gohr * @return string[][] array of notices grouped by type 574fd6a1d7SAndreas Gohr */ 584fd6a1d7SAndreas Gohr public static function list(Extension $extension): array 594fd6a1d7SAndreas Gohr { 604fd6a1d7SAndreas Gohr $self = new self($extension); 614fd6a1d7SAndreas Gohr return $self->notices; 624fd6a1d7SAndreas Gohr } 634fd6a1d7SAndreas Gohr 644fd6a1d7SAndreas Gohr /** 65*d2d4b908SAndreas Gohr * Return the icon path for a notice type 66*d2d4b908SAndreas Gohr * 67*d2d4b908SAndreas Gohr * @param string $type The notice type constant 68*d2d4b908SAndreas Gohr * @return string 69*d2d4b908SAndreas Gohr */ 70*d2d4b908SAndreas Gohr public static function icon($type): string 71*d2d4b908SAndreas Gohr { 72*d2d4b908SAndreas Gohr if (!isset(self::ICONS[$type])) throw new \RuntimeException('Unknown notice type: ' . $type); 73*d2d4b908SAndreas Gohr return __DIR__ . '/images/' . $type . '.svg'; 74*d2d4b908SAndreas Gohr } 75*d2d4b908SAndreas Gohr 76*d2d4b908SAndreas Gohr /** 77*d2d4b908SAndreas Gohr * Return the character symbol for a notice type used on CLI 78*d2d4b908SAndreas Gohr * 79*d2d4b908SAndreas Gohr * @param string $type The notice type constant 80*d2d4b908SAndreas Gohr * @return string 81*d2d4b908SAndreas Gohr */ 82*d2d4b908SAndreas Gohr public static function symbol($type): string 83*d2d4b908SAndreas Gohr { 84*d2d4b908SAndreas Gohr if (!isset(self::ICONS[$type])) throw new \RuntimeException('Unknown notice type: ' . $type); 85*d2d4b908SAndreas Gohr return self::ICONS[$type][0] ?? ''; 86*d2d4b908SAndreas Gohr } 87*d2d4b908SAndreas Gohr 88*d2d4b908SAndreas Gohr /** 894fd6a1d7SAndreas Gohr * Access a language string 904fd6a1d7SAndreas Gohr * 914fd6a1d7SAndreas Gohr * @param string $msg 924fd6a1d7SAndreas Gohr * @return string 934fd6a1d7SAndreas Gohr */ 944fd6a1d7SAndreas Gohr protected function getLang($msg) 954fd6a1d7SAndreas Gohr { 96cf461f20SAndreas Gohr return $this->helper->getLang($msg); 974fd6a1d7SAndreas Gohr } 984fd6a1d7SAndreas Gohr 994fd6a1d7SAndreas Gohr /** 1004fd6a1d7SAndreas Gohr * Check that all dependencies are met 1014fd6a1d7SAndreas Gohr * @return void 1024fd6a1d7SAndreas Gohr */ 1034fd6a1d7SAndreas Gohr protected function checkDependencies() 1044fd6a1d7SAndreas Gohr { 1054fd6a1d7SAndreas Gohr if (!$this->extension->isInstalled()) return; 1064fd6a1d7SAndreas Gohr 1074fd6a1d7SAndreas Gohr $dependencies = $this->extension->getDependencyList(); 1084fd6a1d7SAndreas Gohr $missing = []; 1094fd6a1d7SAndreas Gohr foreach ($dependencies as $dependency) { 1104fd6a1d7SAndreas Gohr $dep = Extension::createFromId($dependency); 1114fd6a1d7SAndreas Gohr if (!$dep->isInstalled()) $missing[] = $dep; 1124fd6a1d7SAndreas Gohr } 1134fd6a1d7SAndreas Gohr if (!$missing) return; 1144fd6a1d7SAndreas Gohr 1154fd6a1d7SAndreas Gohr $this->notices[self::ERROR][] = sprintf( 1164fd6a1d7SAndreas Gohr $this->getLang('missing_dependency'), 1177c184cfcSAndreas Gohr implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $missing)) 1184fd6a1d7SAndreas Gohr ); 1194fd6a1d7SAndreas Gohr } 1204fd6a1d7SAndreas Gohr 1214fd6a1d7SAndreas Gohr /** 1224fd6a1d7SAndreas Gohr * Check if installed dependencies are conflicting 1234fd6a1d7SAndreas Gohr * @return void 1244fd6a1d7SAndreas Gohr */ 1254fd6a1d7SAndreas Gohr protected function checkConflicts() 1264fd6a1d7SAndreas Gohr { 1274fd6a1d7SAndreas Gohr $conflicts = $this->extension->getConflictList(); 1284fd6a1d7SAndreas Gohr $found = []; 1294fd6a1d7SAndreas Gohr foreach ($conflicts as $conflict) { 1304fd6a1d7SAndreas Gohr $dep = Extension::createFromId($conflict); 1314fd6a1d7SAndreas Gohr if ($dep->isInstalled()) $found[] = $dep; 1324fd6a1d7SAndreas Gohr } 1334fd6a1d7SAndreas Gohr if (!$found) return; 1344fd6a1d7SAndreas Gohr 1354fd6a1d7SAndreas Gohr $this->notices[self::WARNING][] = sprintf( 1364fd6a1d7SAndreas Gohr $this->getLang('found_conflict'), 1377c184cfcSAndreas Gohr implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $found)) 1384fd6a1d7SAndreas Gohr ); 1394fd6a1d7SAndreas Gohr } 1404fd6a1d7SAndreas Gohr 1414fd6a1d7SAndreas Gohr /** 1424fd6a1d7SAndreas Gohr * Check for security issues 1434fd6a1d7SAndreas Gohr * @return void 1444fd6a1d7SAndreas Gohr */ 1454fd6a1d7SAndreas Gohr protected function checkSecurity() 1464fd6a1d7SAndreas Gohr { 1474fd6a1d7SAndreas Gohr if ($issue = $this->extension->getSecurityIssue()) { 1484fd6a1d7SAndreas Gohr $this->notices[self::SECURITY][] = sprintf($this->getLang('security_issue'), $issue); 1494fd6a1d7SAndreas Gohr } 1504fd6a1d7SAndreas Gohr if ($issue = $this->extension->getSecurityWarning()) { 151cf461f20SAndreas Gohr $this->notices[self::SECURITY][] = sprintf($this->getLang('security_warning'), $issue); 1524fd6a1d7SAndreas Gohr } 1534fd6a1d7SAndreas Gohr } 1544fd6a1d7SAndreas Gohr 1554fd6a1d7SAndreas Gohr /** 1564fd6a1d7SAndreas Gohr * Check if the extension is installed in correct folder 1574fd6a1d7SAndreas Gohr * @return void 1584fd6a1d7SAndreas Gohr */ 1594fd6a1d7SAndreas Gohr protected function checkFolder() 1604fd6a1d7SAndreas Gohr { 1614fd6a1d7SAndreas Gohr if (!$this->extension->isInWrongFolder()) return; 1624fd6a1d7SAndreas Gohr 1634fd6a1d7SAndreas Gohr $this->notices[self::ERROR][] = sprintf( 1644fd6a1d7SAndreas Gohr $this->getLang('wrong_folder'), 1654fd6a1d7SAndreas Gohr basename($this->extension->getCurrentDir()), 1664fd6a1d7SAndreas Gohr basename($this->extension->getInstallDir()) 1674fd6a1d7SAndreas Gohr ); 1684fd6a1d7SAndreas Gohr } 1694fd6a1d7SAndreas Gohr 1704fd6a1d7SAndreas Gohr /** 1714fd6a1d7SAndreas Gohr * Check PHP requirements 1724fd6a1d7SAndreas Gohr * @return void 1734fd6a1d7SAndreas Gohr */ 1744fd6a1d7SAndreas Gohr protected function checkPHPVersion() 1754fd6a1d7SAndreas Gohr { 1764fd6a1d7SAndreas Gohr try { 1774fd6a1d7SAndreas Gohr Installer::ensurePhpCompatibility($this->extension); 1784fd6a1d7SAndreas Gohr } catch (\Exception $e) { 1794fd6a1d7SAndreas Gohr $this->notices[self::ERROR][] = $e->getMessage(); 1804fd6a1d7SAndreas Gohr } 1814fd6a1d7SAndreas Gohr } 1824fd6a1d7SAndreas Gohr 1834fd6a1d7SAndreas Gohr /** 1844fd6a1d7SAndreas Gohr * Check for update message 1854fd6a1d7SAndreas Gohr * @return void 1864fd6a1d7SAndreas Gohr */ 1874fd6a1d7SAndreas Gohr protected function checkUpdateMessage() 1884fd6a1d7SAndreas Gohr { 189d98308b7SAndreas Gohr // only display this for installed extensions 190d98308b7SAndreas Gohr if (!$this->extension->isInstalled()) return; 1914fd6a1d7SAndreas Gohr if ($msg = $this->extension->getUpdateMessage()) { 1924fd6a1d7SAndreas Gohr $this->notices[self::WARNING][] = sprintf($this->getLang('update_message'), $msg); 1934fd6a1d7SAndreas Gohr } 1944fd6a1d7SAndreas Gohr } 1954fd6a1d7SAndreas Gohr 1964fd6a1d7SAndreas Gohr /** 1974fd6a1d7SAndreas Gohr * Check for URL changes 1984fd6a1d7SAndreas Gohr * @return void 1994fd6a1d7SAndreas Gohr */ 2004fd6a1d7SAndreas Gohr protected function checkURLChange() 2014fd6a1d7SAndreas Gohr { 2024fd6a1d7SAndreas Gohr if (!$this->extension->hasChangedURL()) return; 2034fd6a1d7SAndreas Gohr $this->notices[self::WARNING][] = sprintf( 2044fd6a1d7SAndreas Gohr $this->getLang('url_change'), 2054fd6a1d7SAndreas Gohr $this->extension->getDownloadURL(), 2064fd6a1d7SAndreas Gohr $this->extension->getManager()->getDownloadURL() 2074fd6a1d7SAndreas Gohr ); 2084fd6a1d7SAndreas Gohr } 2094fd6a1d7SAndreas Gohr 210981e70caSAndreas Gohr /** 211981e70caSAndreas Gohr * Check if the extension dir has the correct permissions to change 212981e70caSAndreas Gohr * 213981e70caSAndreas Gohr * @return void 214981e70caSAndreas Gohr */ 215981e70caSAndreas Gohr protected function checkPermissions() 216981e70caSAndreas Gohr { 217981e70caSAndreas Gohr try { 218981e70caSAndreas Gohr Installer::ensurePermissions($this->extension); 219981e70caSAndreas Gohr } catch (\Exception $e) { 220981e70caSAndreas Gohr $this->notices[self::ERROR][] = $e->getMessage(); 221981e70caSAndreas Gohr } 222981e70caSAndreas Gohr } 223981e70caSAndreas Gohr 224981e70caSAndreas Gohr /** 225981e70caSAndreas Gohr * Hint about unused auth plugins 226981e70caSAndreas Gohr * 227981e70caSAndreas Gohr * @return void 228981e70caSAndreas Gohr */ 229981e70caSAndreas Gohr protected function checkUnusedAuth() 230981e70caSAndreas Gohr { 231981e70caSAndreas Gohr global $conf; 232981e70caSAndreas Gohr if ( 233981e70caSAndreas Gohr $this->extension->isEnabled() && 234981e70caSAndreas Gohr in_array('Auth', $this->extension->getComponentTypes()) && 235981e70caSAndreas Gohr $conf['authtype'] != $this->extension->getID() 236981e70caSAndreas Gohr ) { 237981e70caSAndreas Gohr $this->notices[self::INFO][] = $this->getLang('auth'); 238981e70caSAndreas Gohr } 239981e70caSAndreas Gohr } 240981e70caSAndreas Gohr 241981e70caSAndreas Gohr /** 242981e70caSAndreas Gohr * Hint about installations by git 243981e70caSAndreas Gohr * 244981e70caSAndreas Gohr * @return void 245981e70caSAndreas Gohr */ 246981e70caSAndreas Gohr protected function checkGit() 247981e70caSAndreas Gohr { 248981e70caSAndreas Gohr if ($this->extension->isGitControlled()) { 249981e70caSAndreas Gohr $this->notices[self::INFO][] = $this->getLang('git'); 250981e70caSAndreas Gohr } 251981e70caSAndreas Gohr } 2524fd6a1d7SAndreas Gohr} 253