1<?php 2 3namespace dokuwiki\plugin\extension; 4 5class Notice 6{ 7 public const INFO = 'info'; 8 public const WARNING = 'warning'; 9 public const ERROR = 'error'; 10 public const SECURITY = 'security'; 11 12 protected const ICONS = [ 13 self::INFO => 'I', 14 self::WARNING => 'W', 15 self::ERROR => 'E', 16 self::SECURITY => 'S', 17 ]; 18 19 protected $notices = [ 20 self::INFO => [], 21 self::WARNING => [], 22 self::ERROR => [], 23 self::SECURITY => [], 24 ]; 25 26 /** @var \helper_plugin_extension */ 27 protected $helper; 28 29 /** @var Extension */ 30 protected Extension $extension; 31 32 /** 33 * Not public, use list() instead 34 * @param Extension $extension 35 */ 36 protected function __construct(Extension $extension) 37 { 38 $this->helper = plugin_load('helper', 'extension'); 39 $this->extension = $extension; 40 41 $this->checkSecurity(); 42 $this->checkURLChange(); 43 $this->checkFolder(); 44 $this->checkPHPVersion(); 45 $this->checkDependencies(); 46 $this->checkConflicts(); 47 $this->checkUpdateMessage(); 48 $this->checkPermissions(); 49 $this->checkUnusedAuth(); 50 $this->checkGit(); 51 } 52 53 /** 54 * Get all notices for the extension 55 * 56 * @return string[][] array of notices grouped by type 57 */ 58 public static function list(Extension $extension): array 59 { 60 $self = new self($extension); 61 return $self->notices; 62 } 63 64 /** 65 * Return the icon path for a notice type 66 * 67 * @param string $type The notice type constant 68 * @return string 69 */ 70 public static function icon($type): string 71 { 72 if (!isset(self::ICONS[$type])) throw new \RuntimeException('Unknown notice type: ' . $type); 73 return __DIR__ . '/images/' . $type . '.svg'; 74 } 75 76 /** 77 * Return the character symbol for a notice type used on CLI 78 * 79 * @param string $type The notice type constant 80 * @return string 81 */ 82 public static function symbol($type): string 83 { 84 if (!isset(self::ICONS[$type])) throw new \RuntimeException('Unknown notice type: ' . $type); 85 return self::ICONS[$type][0] ?? ''; 86 } 87 88 /** 89 * Access a language string 90 * 91 * @param string $msg 92 * @return string 93 */ 94 protected function getLang($msg) 95 { 96 return $this->helper->getLang($msg); 97 } 98 99 /** 100 * Check that all dependencies are met 101 * @return void 102 */ 103 protected function checkDependencies() 104 { 105 if (!$this->extension->isInstalled()) return; 106 107 $dependencies = $this->extension->getDependencyList(); 108 $missing = []; 109 foreach ($dependencies as $dependency) { 110 $dep = Extension::createFromId($dependency); 111 if (!$dep->isInstalled()) $missing[] = $dep; 112 } 113 if (!$missing) return; 114 115 $this->notices[self::ERROR][] = sprintf( 116 $this->getLang('missing_dependency'), 117 implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $missing)) 118 ); 119 } 120 121 /** 122 * Check if installed dependencies are conflicting 123 * @return void 124 */ 125 protected function checkConflicts() 126 { 127 $conflicts = $this->extension->getConflictList(); 128 $found = []; 129 foreach ($conflicts as $conflict) { 130 $dep = Extension::createFromId($conflict); 131 if ($dep->isInstalled()) $found[] = $dep; 132 } 133 if (!$found) return; 134 135 $this->notices[self::WARNING][] = sprintf( 136 $this->getLang('found_conflict'), 137 implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $found)) 138 ); 139 } 140 141 /** 142 * Check for security issues 143 * @return void 144 */ 145 protected function checkSecurity() 146 { 147 if ($issue = $this->extension->getSecurityIssue()) { 148 $this->notices[self::SECURITY][] = sprintf($this->getLang('security_issue'), $issue); 149 } 150 if ($issue = $this->extension->getSecurityWarning()) { 151 $this->notices[self::SECURITY][] = sprintf($this->getLang('security_warning'), $issue); 152 } 153 } 154 155 /** 156 * Check if the extension is installed in correct folder 157 * @return void 158 */ 159 protected function checkFolder() 160 { 161 if (!$this->extension->isInWrongFolder()) return; 162 163 $this->notices[self::ERROR][] = sprintf( 164 $this->getLang('wrong_folder'), 165 basename($this->extension->getCurrentDir()), 166 basename($this->extension->getInstallDir()) 167 ); 168 } 169 170 /** 171 * Check PHP requirements 172 * @return void 173 */ 174 protected function checkPHPVersion() 175 { 176 try { 177 Installer::ensurePhpCompatibility($this->extension); 178 } catch (\Exception $e) { 179 $this->notices[self::ERROR][] = $e->getMessage(); 180 } 181 } 182 183 /** 184 * Check for update message 185 * @return void 186 */ 187 protected function checkUpdateMessage() 188 { 189 // only display this for installed extensions 190 if (!$this->extension->isInstalled()) return; 191 if ($msg = $this->extension->getUpdateMessage()) { 192 $this->notices[self::WARNING][] = sprintf($this->getLang('update_message'), $msg); 193 } 194 } 195 196 /** 197 * Check for URL changes 198 * @return void 199 */ 200 protected function checkURLChange() 201 { 202 if (!$this->extension->hasChangedURL()) return; 203 $this->notices[self::WARNING][] = sprintf( 204 $this->getLang('url_change'), 205 $this->extension->getDownloadURL(), 206 $this->extension->getManager()->getDownloadURL() 207 ); 208 } 209 210 /** 211 * Check if the extension dir has the correct permissions to change 212 * 213 * @return void 214 */ 215 protected function checkPermissions() 216 { 217 try { 218 Installer::ensurePermissions($this->extension); 219 } catch (\Exception $e) { 220 $this->notices[self::ERROR][] = $e->getMessage(); 221 } 222 } 223 224 /** 225 * Hint about unused auth plugins 226 * 227 * @return void 228 */ 229 protected function checkUnusedAuth() 230 { 231 global $conf; 232 if ( 233 $this->extension->isEnabled() && 234 in_array('Auth', $this->extension->getComponentTypes()) && 235 $conf['authtype'] != $this->extension->getID() 236 ) { 237 $this->notices[self::INFO][] = $this->getLang('auth'); 238 } 239 } 240 241 /** 242 * Hint about installations by git 243 * 244 * @return void 245 */ 246 protected function checkGit() 247 { 248 if ($this->extension->isGitControlled()) { 249 $this->notices[self::INFO][] = $this->getLang('git'); 250 } 251 } 252} 253