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