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 public const ICONS = [ 13 self::INFO => 'ⓘ', 14 self::WARNING => '↯', 15 self::ERROR => '⚠', 16 self::SECURITY => '☠', 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 * Access a language string 66 * 67 * @param string $msg 68 * @return string 69 */ 70 protected function getLang($msg) 71 { 72 return $this->helper->getLang($msg); 73 } 74 75 /** 76 * Check that all dependencies are met 77 * @return void 78 */ 79 protected function checkDependencies() 80 { 81 if (!$this->extension->isInstalled()) return; 82 83 $dependencies = $this->extension->getDependencyList(); 84 $missing = []; 85 foreach ($dependencies as $dependency) { 86 $dep = Extension::createFromId($dependency); 87 if (!$dep->isInstalled()) $missing[] = $dep; 88 } 89 if (!$missing) return; 90 91 $this->notices[self::ERROR][] = sprintf( 92 $this->getLang('missing_dependency'), 93 implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $missing)) 94 ); 95 } 96 97 /** 98 * Check if installed dependencies are conflicting 99 * @return void 100 */ 101 protected function checkConflicts() 102 { 103 $conflicts = $this->extension->getConflictList(); 104 $found = []; 105 foreach ($conflicts as $conflict) { 106 $dep = Extension::createFromId($conflict); 107 if ($dep->isInstalled()) $found[] = $dep; 108 } 109 if (!$found) return; 110 111 $this->notices[self::WARNING][] = sprintf( 112 $this->getLang('found_conflict'), 113 implode(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $found)) 114 ); 115 } 116 117 /** 118 * Check for security issues 119 * @return void 120 */ 121 protected function checkSecurity() 122 { 123 if ($issue = $this->extension->getSecurityIssue()) { 124 $this->notices[self::SECURITY][] = sprintf($this->getLang('security_issue'), $issue); 125 } 126 if ($issue = $this->extension->getSecurityWarning()) { 127 $this->notices[self::SECURITY][] = sprintf($this->getLang('security_warning'), $issue); 128 } 129 } 130 131 /** 132 * Check if the extension is installed in correct folder 133 * @return void 134 */ 135 protected function checkFolder() 136 { 137 if (!$this->extension->isInWrongFolder()) return; 138 139 $this->notices[self::ERROR][] = sprintf( 140 $this->getLang('wrong_folder'), 141 basename($this->extension->getCurrentDir()), 142 basename($this->extension->getInstallDir()) 143 ); 144 } 145 146 /** 147 * Check PHP requirements 148 * @return void 149 */ 150 protected function checkPHPVersion() 151 { 152 try { 153 Installer::ensurePhpCompatibility($this->extension); 154 } catch (\Exception $e) { 155 $this->notices[self::ERROR][] = $e->getMessage(); 156 } 157 } 158 159 /** 160 * Check for update message 161 * @return void 162 */ 163 protected function checkUpdateMessage() 164 { 165 // only display this for installed extensions 166 if (!$this->extension->isInstalled()) return; 167 if ($msg = $this->extension->getUpdateMessage()) { 168 $this->notices[self::WARNING][] = sprintf($this->getLang('update_message'), $msg); 169 } 170 } 171 172 /** 173 * Check for URL changes 174 * @return void 175 */ 176 protected function checkURLChange() 177 { 178 if (!$this->extension->hasChangedURL()) return; 179 $this->notices[self::WARNING][] = sprintf( 180 $this->getLang('url_change'), 181 $this->extension->getDownloadURL(), 182 $this->extension->getManager()->getDownloadURL() 183 ); 184 } 185 186 /** 187 * Check if the extension dir has the correct permissions to change 188 * 189 * @return void 190 */ 191 protected function checkPermissions() 192 { 193 try { 194 Installer::ensurePermissions($this->extension); 195 } catch (\Exception $e) { 196 $this->notices[self::ERROR][] = $e->getMessage(); 197 } 198 } 199 200 /** 201 * Hint about unused auth plugins 202 * 203 * @return void 204 */ 205 protected function checkUnusedAuth() 206 { 207 global $conf; 208 if ( 209 $this->extension->isEnabled() && 210 in_array('Auth', $this->extension->getComponentTypes()) && 211 $conf['authtype'] != $this->extension->getID() 212 ) { 213 $this->notices[self::INFO][] = $this->getLang('auth'); 214 } 215 } 216 217 /** 218 * Hint about installations by git 219 * 220 * @return void 221 */ 222 protected function checkGit() 223 { 224 if ($this->extension->isGitControlled()) { 225 $this->notices[self::INFO][] = $this->getLang('git'); 226 } 227 } 228} 229