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 // FIXME should we only display this for installed extensions? 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