splitbrain /
dokuwiki
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
|
|||
| 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 |
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.