1<?php 2 3 4namespace dokuwiki\plugin\extension; 5 6class Notice 7{ 8 const INFO = 'info'; 9 const WARNING = 'warning'; 10 const ERROR = 'error'; 11 const SECURITY = 'security'; 12 13 public const ICONS = [ 14 self::INFO => 'ⓘ', 15 self::WARNING => '↯', 16 self::ERROR => '⚠', 17 self::SECURITY => '☠', 18 ]; 19 20 protected $notices = [ 21 self::INFO => [], 22 self::WARNING => [], 23 self::ERROR => [], 24 self::SECURITY => [], 25 ]; 26 27 /** @var \helper_plugin_extension */ 28 protected $helper; 29 30 /** @var Extension */ 31 protected Extension $extension; 32 33 /** 34 * Not public, use list() instead 35 * @param Extension $extension 36 */ 37 protected function __construct(Extension $extension) 38 { 39 $this->helper = plugin_load('helper', 'extension'); 40 $this->extension = $extension; 41 42 // FIXME sort sensibly 43 $this->checkDependencies(); 44 $this->checkConflicts(); 45 $this->checkSecurity(); 46 $this->checkFolder(); 47 $this->checkPHPVersion(); 48 $this->checkUpdateMessage(); 49 $this->checkURLChange(); 50 $this->checkPermissions(); 51 $this->checkUnusedAuth(); 52 $this->checkGit(); 53 } 54 55 /** 56 * Get all notices for the extension 57 * 58 * @return string[][] array of notices grouped by type 59 */ 60 public static function list(Extension $extension): array 61 { 62 $self = new self($extension); 63 return $self->notices; 64 } 65 66 /** 67 * Access a language string 68 * 69 * @param string $msg 70 * @return string 71 */ 72 protected function getLang($msg) 73 { 74 return strip_tags(preg_replace('/<br ?\/?>/', "\n", $this->helper->getLang($msg))); // FIXME existing strings should be adjusted 75 } 76 77 /** 78 * Check that all dependencies are met 79 * @return void 80 */ 81 protected function checkDependencies() 82 { 83 if (!$this->extension->isInstalled()) return; 84 85 $dependencies = $this->extension->getDependencyList(); 86 $missing = []; 87 foreach ($dependencies as $dependency) { 88 $dep = Extension::createFromId($dependency); 89 if (!$dep->isInstalled()) $missing[] = $dep; 90 } 91 if (!$missing) return; 92 93 $this->notices[self::ERROR][] = sprintf( 94 $this->getLang('missing_dependency'), 95 join(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $missing)) 96 ); 97 } 98 99 /** 100 * Check if installed dependencies are conflicting 101 * @return void 102 */ 103 protected function checkConflicts() 104 { 105 $conflicts = $this->extension->getConflictList(); 106 $found = []; 107 foreach ($conflicts as $conflict) { 108 $dep = Extension::createFromId($conflict); 109 if ($dep->isInstalled()) $found[] = $dep; 110 } 111 if (!$found) return; 112 113 $this->notices[self::WARNING][] = sprintf( 114 $this->getLang('found_conflict'), 115 join(', ', array_map(static fn(Extension $dep) => $dep->getId(true), $found)) 116 ); 117 } 118 119 /** 120 * Check for security issues 121 * @return void 122 */ 123 protected function checkSecurity() 124 { 125 if ($issue = $this->extension->getSecurityIssue()) { 126 $this->notices[self::SECURITY][] = sprintf($this->getLang('security_issue'), $issue); 127 } 128 if ($issue = $this->extension->getSecurityWarning()) { 129 $this->notices[self::SECURITY][] = sprintf($this->getLang('security_issue'), $issue); 130 } 131 } 132 133 /** 134 * Check if the extension is installed in correct folder 135 * @return void 136 */ 137 protected function checkFolder() 138 { 139 if (!$this->extension->isInWrongFolder()) return; 140 141 $this->notices[self::ERROR][] = sprintf( 142 $this->getLang('wrong_folder'), 143 basename($this->extension->getCurrentDir()), 144 basename($this->extension->getInstallDir()) 145 ); 146 } 147 148 /** 149 * Check PHP requirements 150 * @return void 151 */ 152 protected function checkPHPVersion() 153 { 154 try { 155 Installer::ensurePhpCompatibility($this->extension); 156 } catch (\Exception $e) { 157 $this->notices[self::ERROR][] = $e->getMessage(); 158 } 159 } 160 161 /** 162 * Check for update message 163 * @return void 164 */ 165 protected function checkUpdateMessage() 166 { 167 // FIXME should we only display this for installed extensions? 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