xref: /dokuwiki/lib/plugins/extension/Notice.php (revision cf461f202d7f621cf248e33ad3d6b8c69beb5c6d)
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