Failed Conditions
Push — psr2-config ( c6639e )
by Andreas
06:39 queued 03:33
created

lib/plugins/config/admin.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Configuration Manager admin plugin
4
 *
5
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6
 * @author     Christopher Smith <[email protected]>
7
 * @author     Ben Coburn <[email protected]>
8
 */
9
10
use dokuwiki\plugin\config\core\Configuration;
11
12
/**
13
 * All DokuWiki plugins to extend the admin function
14
 * need to inherit from this class
15
 */
16
class admin_plugin_config extends DokuWiki_Admin_Plugin {
17
18
    const METADATA = __DIR__ . 'settings/config.metadata.php';
19
    const IMGDIR = DOKU_BASE.'lib/plugins/config/images/';
20
21
    protected $_config = null;
22
    protected $_input = null;
23
    protected $_changed = false;          // set to true if configuration has altered
24
    protected $_error = false;
25
    protected $_session_started = false;
26
    protected $_localised_prompts = false;
27
28
    /**
29
     * @return int
30
     */
31
    public function getMenuSort() { return 100; }
32
33
    /**
34
     * handle user request
35
     */
36
    public function handle() {
37
        global $ID, $INPUT;
38
39
        if(!$this->_restore_session() || $INPUT->int('save') != 1 || !checkSecurityToken()) {
40
            $this->_close_session();
41
            return;
42
        }
43
44
        if(is_null($this->_config)) {
45
            $this->_config = new Configuration(self::METADATA);
46
        }
47
48
        // don't go any further if the configuration is locked
49
        if($this->_config->locked) {
50
            $this->_close_session();
51
            return;
52
        }
53
54
        $this->_input = $INPUT->arr('config');
55
56
        foreach ($this->_config->setting as $key => $value){
57
            $input = isset($this->_input[$key]) ? $this->_input[$key] : null;
58
            if ($this->_config->setting[$key]->update($input)) {
59
                $this->_changed = true;
60
            }
61
            if ($this->_config->setting[$key]->error()) $this->_error = true;
62
        }
63
64
        if ($this->_changed  && !$this->_error) {
65
            $this->_config->save_settings($this->getPluginName());
66
67
            // save state & force a page reload to get the new settings to take effect
68
            $_SESSION['PLUGIN_CONFIG'] = array('state' => 'updated', 'time' => time());
69
            $this->_close_session();
70
            send_redirect(wl($ID,array('do'=>'admin','page'=>'config'),true,'&'));
71
            exit();
72
        } elseif(!$this->_error) {
73
            $this->_config->touch_settings(); // just touch to refresh cache
74
        }
75
76
        $this->_close_session();
77
    }
78
79
    /**
80
     * output appropriate html
81
     */
82
    public function html() {
83
        $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here.
84
        global $lang;
85
        global $ID;
86
87
        if (is_null($this->_config)) { $this->_config = new Configuration(self::METADATA); }
88
        $this->setupLocale(true);
89
90
        print $this->locale_xhtml('intro');
91
92
        ptln('<div id="config__manager">');
93
94
        if ($this->_config->locked)
95
            ptln('<div class="info">'.$this->getLang('locked').'</div>');
96
        elseif ($this->_error)
97
            ptln('<div class="error">'.$this->getLang('error').'</div>');
98
        elseif ($this->_changed)
99
            ptln('<div class="success">'.$this->getLang('updated').'</div>');
100
101
        // POST to script() instead of wl($ID) so config manager still works if
102
        // rewrite config is broken. Add $ID as hidden field to remember
103
        // current ID in most cases.
104
        ptln('<form action="'.script().'" method="post">');
105
        ptln('<div class="no"><input type="hidden" name="id" value="'.$ID.'" /></div>');
106
        formSecurityToken();
107
        $this->_print_h1('dokuwiki_settings', $this->getLang('_header_dokuwiki'));
108
109
        /** @var setting[] $undefined_settings */
110
        $undefined_settings = array();
111
        $in_fieldset = false;
112
        $first_plugin_fieldset = true;
113
        $first_template_fieldset = true;
114
        foreach($this->_config->setting as $setting) {
115
            if (is_a($setting, 'setting_hidden')) {
116
                // skip hidden (and undefined) settings
117
                if ($allow_debug && is_a($setting, 'setting_undefined')) {
118
                    $undefined_settings[] = $setting;
119
                } else {
120
                    continue;
121
                }
122
            } else if (is_a($setting, 'setting_fieldset')) {
123
                // config setting group
124
                if ($in_fieldset) {
125
                    ptln('  </table>');
126
                    ptln('  </div>');
127
                    ptln('  </fieldset>');
128
                } else {
129
                    $in_fieldset = true;
130
                }
131
                if ($first_plugin_fieldset && substr($setting->_key, 0, 10)=='plugin'.Configuration::KEYMARKER) {
0 ignored issues
show
The property _key cannot be accessed from this context as it is declared protected in class dokuwiki\plugin\config\core\Setting.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
132
                    $this->_print_h1('plugin_settings', $this->getLang('_header_plugin'));
133
                    $first_plugin_fieldset = false;
134
                } else if ($first_template_fieldset && substr($setting->_key, 0, 7)=='tpl'.Configuration::KEYMARKER) {
0 ignored issues
show
The property _key cannot be accessed from this context as it is declared protected in class dokuwiki\plugin\config\core\Setting.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
135
                    $this->_print_h1('template_settings', $this->getLang('_header_template'));
136
                    $first_template_fieldset = false;
137
                }
138
                ptln('  <fieldset id="'.$setting->_key.'">');
0 ignored issues
show
The property _key cannot be accessed from this context as it is declared protected in class dokuwiki\plugin\config\core\Setting.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
139
                ptln('  <legend>'.$setting->prompt($this).'</legend>');
140
                ptln('  <div class="table">');
141
                ptln('  <table class="inline">');
142
            } else {
143
                // config settings
144
                list($label,$input) = $setting->html($this, $this->_error);
145
146
                $class = $setting->is_default()
147
                    ? ' class="default"'
148
                    : ($setting->is_protected() ? ' class="protected"' : '');
149
                $error = $setting->error()
150
                    ? ' class="value error"'
151
                    : ' class="value"';
152
                $icon = $setting->caution()
153
                    ? '<img src="'.self::IMGDIR.$setting->caution().'.png" '.
154
                      'alt="'.$setting->caution().'" title="'.$this->getLang($setting->caution()).'" />'
155
                    : '';
156
157
                ptln('    <tr'.$class.'>');
158
                ptln('      <td class="label">');
159
                ptln('        <span class="outkey">'.$setting->_out_key(true, true).'</span>');
160
                ptln('        '.$icon.$label);
161
                ptln('      </td>');
162
                ptln('      <td'.$error.'>'.$input.'</td>');
163
                ptln('    </tr>');
164
            }
165
        }
166
167
        ptln('  </table>');
168
        ptln('  </div>');
169
        if ($in_fieldset) {
170
            ptln('  </fieldset>');
171
        }
172
173
        // show undefined settings list
174
        if ($allow_debug && !empty($undefined_settings)) {
175
            /**
176
             * Callback for sorting settings
177
             *
178
             * @param setting $a
179
             * @param setting $b
180
             * @return int if $a is lower/equal/higher than $b
181
             */
182
            function _setting_natural_comparison($a, $b) {
183
                return strnatcmp($a->_key, $b->_key);
184
            }
185
186
            usort($undefined_settings, '_setting_natural_comparison');
187
            $this->_print_h1('undefined_settings', $this->getLang('_header_undefined'));
188
            ptln('<fieldset>');
189
            ptln('<div class="table">');
190
            ptln('<table class="inline">');
191
            $undefined_setting_match = array();
192
            foreach($undefined_settings as $setting) {
193
                if (
194
                    preg_match(
195
                        '/^(?:plugin|tpl)'.Configuration::KEYMARKER.'.*?'.Configuration::KEYMARKER.'(.*)$/',
196
                        $setting->_key,
197
                        $undefined_setting_match
198
                    )
199
                ) {
200
                    $undefined_setting_key = $undefined_setting_match[1];
201
                } else {
202
                    $undefined_setting_key = $setting->_key;
203
                }
204
                ptln('  <tr>');
205
                ptln('    <td class="label"><span title="$meta[\''.$undefined_setting_key.'\']">$'.
206
                     $this->_config->_name.'[\''.$setting->_out_key().'\']</span></td>');
0 ignored issues
show
The property _name cannot be accessed from this context as it is declared protected in class dokuwiki\plugin\config\core\Configuration.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
207
                ptln('    <td>'.$this->getLang('_msg_'.get_class($setting)).'</td>');
208
                ptln('  </tr>');
209
            }
210
            ptln('</table>');
211
            ptln('</div>');
212
            ptln('</fieldset>');
213
        }
214
215
        // finish up form
216
        ptln('<p>');
217
        ptln('  <input type="hidden" name="do"     value="admin" />');
218
        ptln('  <input type="hidden" name="page"   value="config" />');
219
220
        if (!$this->_config->locked) {
221
            ptln('  <input type="hidden" name="save"   value="1" />');
222
            ptln('  <button type="submit" name="submit" accesskey="s">'.$lang['btn_save'].'</button>');
223
            ptln('  <button type="reset">'.$lang['btn_reset'].'</button>');
224
        }
225
226
        ptln('</p>');
227
228
        ptln('</form>');
229
        ptln('</div>');
230
    }
231
232
    /**
233
     * @return boolean   true - proceed with handle, false - don't proceed
234
     */
235
    protected function _restore_session() {
236
237
        // dokuwiki closes the session before act_dispatch. $_SESSION variables are all set,
238
        // however they can't be changed without starting the session again
239
        if (!headers_sent()) {
240
            session_start();
241
            $this->_session_started = true;
242
        }
243
244
        if (!isset($_SESSION['PLUGIN_CONFIG'])) return true;
245
246
        $session = $_SESSION['PLUGIN_CONFIG'];
247
        unset($_SESSION['PLUGIN_CONFIG']);
248
249
        // still valid?
250
        if (time() - $session['time'] > 120) return true;
251
252
        switch ($session['state']) {
253
            case 'updated' :
254
                $this->_changed = true;
255
                return false;
256
        }
257
258
        return true;
259
    }
260
261
    protected function _close_session() {
262
      if ($this->_session_started) session_write_close();
263
    }
264
265
    /**
266
     * @param bool $prompts
267
     */
268
    public function setupLocale($prompts=false) {
269
270
        parent::setupLocale();
271
        if (!$prompts || $this->_localised_prompts) return;
272
273
        $this->_setup_localised_plugin_prompts();
274
        $this->_localised_prompts = true;
275
276
    }
277
278
    /**
279
     * @return bool
280
     */
281
    protected function _setup_localised_plugin_prompts() {
282
        global $conf;
283
284
        $langfile   = '/lang/'.$conf['lang'].'/settings.php';
285
        $enlangfile = '/lang/en/settings.php';
286
287
        if ($dh = opendir(DOKU_PLUGIN)) {
288
            while (false !== ($plugin = readdir($dh))) {
289
                if ($plugin == '.' || $plugin == '..' || $plugin == 'tmp' || $plugin == 'config') continue;
290
                if (is_file(DOKU_PLUGIN.$plugin)) continue;
291
292
                if (file_exists(DOKU_PLUGIN.$plugin.$enlangfile)){
293
                    $lang = array();
294
                    @include(DOKU_PLUGIN.$plugin.$enlangfile);
295
                    if ($conf['lang'] != 'en') @include(DOKU_PLUGIN.$plugin.$langfile);
296
                    foreach ($lang as $key => $value){
297
                        $this->lang['plugin'.Configuration::KEYMARKER.$plugin.Configuration::KEYMARKER.$key] = $value;
298
                    }
299
                }
300
301
                // fill in the plugin name if missing (should exist for plugins with settings)
302
                if (!isset($this->lang['plugin'.Configuration::KEYMARKER.$plugin.Configuration::KEYMARKER.'plugin_settings_name'])) {
303
                    $this->lang['plugin'.Configuration::KEYMARKER.$plugin.Configuration::KEYMARKER.'plugin_settings_name'] =
304
                      ucwords(str_replace('_', ' ', $plugin));
305
                }
306
            }
307
            closedir($dh);
308
      }
309
310
        // the same for the active template
311
        $tpl = $conf['template'];
312
313
        if (file_exists(tpl_incdir().$enlangfile)){
314
            $lang = array();
315
            @include(tpl_incdir().$enlangfile);
316
            if ($conf['lang'] != 'en') @include(tpl_incdir().$langfile);
317
            foreach ($lang as $key => $value){
318
                $this->lang['tpl'.Configuration::KEYMARKER.$tpl.Configuration::KEYMARKER.$key] = $value;
319
            }
320
        }
321
322
        // fill in the template name if missing (should exist for templates with settings)
323
        if (!isset($this->lang['tpl'.Configuration::KEYMARKER.$tpl.Configuration::KEYMARKER.'template_settings_name'])) {
324
            $this->lang['tpl'.Configuration::KEYMARKER.$tpl.Configuration::KEYMARKER.'template_settings_name'] =
325
              ucwords(str_replace('_', ' ', $tpl));
326
        }
327
328
        return true;
329
    }
330
331
    /**
332
     * Generates a two-level table of contents for the config plugin.
333
     *
334
     * @author Ben Coburn <[email protected]>
335
     *
336
     * @return array
337
     */
338
    public function getTOC() {
339
        if (is_null($this->_config)) { $this->_config = new Configuration(self::METADATA); }
340
        $this->setupLocale(true);
341
342
        $allow_debug = $GLOBALS['conf']['allowdebug']; // avoid global $conf; here.
343
344
        // gather toc data
345
        $has_undefined = false;
346
        $toc = array('conf'=>array(), 'plugin'=>array(), 'template'=>null);
347
        foreach($this->_config->setting as $setting) {
348
            if (is_a($setting, 'setting_fieldset')) {
349
                if (substr($setting->_key, 0, 10)=='plugin'.Configuration::KEYMARKER) {
0 ignored issues
show
The property _key cannot be accessed from this context as it is declared protected in class dokuwiki\plugin\config\core\Setting.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
350
                    $toc['plugin'][] = $setting;
351
                } else if (substr($setting->_key, 0, 7)=='tpl'.Configuration::KEYMARKER) {
0 ignored issues
show
The property _key cannot be accessed from this context as it is declared protected in class dokuwiki\plugin\config\core\Setting.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
352
                    $toc['template'] = $setting;
353
                } else {
354
                    $toc['conf'][] = $setting;
355
                }
356
            } else if (!$has_undefined && is_a($setting, 'setting_undefined')) {
357
                $has_undefined = true;
358
            }
359
        }
360
361
        // build toc
362
        $t = array();
363
364
        $check = false;
365
        $title = $this->getLang('_configuration_manager');
366
        $t[] = html_mktocitem(sectionID($title, $check), $title, 1);
367
        $t[] = html_mktocitem('dokuwiki_settings', $this->getLang('_header_dokuwiki'), 1);
368
        /** @var setting $setting */
369
        foreach($toc['conf'] as $setting) {
370
            $name = $setting->prompt($this);
371
            $t[] = html_mktocitem($setting->_key, $name, 2);
372
        }
373
        if (!empty($toc['plugin'])) {
374
            $t[] = html_mktocitem('plugin_settings', $this->getLang('_header_plugin'), 1);
375
        }
376
        foreach($toc['plugin'] as $setting) {
377
            $name = $setting->prompt($this);
378
            $t[] = html_mktocitem($setting->_key, $name, 2);
379
        }
380
        if (isset($toc['template'])) {
381
            $t[] = html_mktocitem('template_settings', $this->getLang('_header_template'), 1);
382
            $setting = $toc['template'];
383
            $name = $setting->prompt($this);
384
            $t[] = html_mktocitem($setting->_key, $name, 2);
385
        }
386
        if ($has_undefined && $allow_debug) {
387
            $t[] = html_mktocitem('undefined_settings', $this->getLang('_header_undefined'), 1);
388
        }
389
390
        return $t;
391
    }
392
393
    /**
394
     * @param string $id
395
     * @param string $text
396
     */
397
    protected function _print_h1($id, $text) {
398
        ptln('<h1 id="'.$id.'">'.$text.'</h1>');
399
    }
400
401
    /**
402
     * Adds a translation to this plugin's language array
403
     *
404
     * @param string $key
405
     * @param string $value
406
     */
407
    public function addLang($key, $value) {
408
        if (!$this->localised) $this->setupLocale();
409
        $this->lang[$key] = $value;
410
    }
411
}
412