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