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