getLang('menu'); } public function getMenuSort() { // keep near other plugin tools return 1011; } public function forAdminOnly() { return true; } public function handle() { global $INPUT; if ($INPUT->str('luxtools_cmd') !== 'save') return; if (!checkSecurityToken()) { msg($this->getLang('err_security'), -1); return; } $newConf = []; // Normalize newlines to "\n" for consistent parsing $paths = $INPUT->str('paths'); $paths = str_replace(["\r\n", "\r"], "\n", $paths); $newConf['paths'] = $paths; $scratchpadPaths = $INPUT->str('scratchpad_paths'); $scratchpadPaths = str_replace(["\r\n", "\r"], "\n", $scratchpadPaths); $newConf['scratchpad_paths'] = $scratchpadPaths; $newConf['extensions'] = $INPUT->str('extensions'); $newConf['default_sort'] = $INPUT->str('default_sort'); $newConf['default_order'] = $INPUT->str('default_order'); $newConf['default_style'] = $INPUT->str('default_style'); $newConf['default_tableheader'] = (int)$INPUT->bool('default_tableheader'); $newConf['default_foldersfirst'] = (int)$INPUT->bool('default_foldersfirst'); $newConf['default_recursive'] = (int)$INPUT->bool('default_recursive'); $newConf['default_titlefile'] = $INPUT->str('default_titlefile'); $newConf['default_cache'] = (int)$INPUT->bool('default_cache'); $newConf['default_randlinks'] = (int)$INPUT->bool('default_randlinks'); $newConf['default_showsize'] = (int)$INPUT->bool('default_showsize'); $newConf['default_showdate'] = (int)$INPUT->bool('default_showdate'); $newConf['default_tablecolumns'] = $INPUT->str('default_tablecolumns'); $newConf['default_listsep'] = $INPUT->str('default_listsep'); $newConf['default_maxheight'] = $INPUT->str('default_maxheight'); $newConf['thumb_placeholder'] = $INPUT->str('thumb_placeholder'); $newConf['gallery_thumb_scale'] = $INPUT->str('gallery_thumb_scale'); $newConf['open_service_url'] = $INPUT->str('open_service_url'); if ($this->savePluginLocalConf($newConf)) { msg($this->getLang('saved'), 1); } else { msg($this->getLang('err_save'), -1); } } public function html() { global $ID; echo '
'; echo '

' . hsc($this->getLang('settings')) . '

'; echo '
'; echo ''; echo ''; echo ''; echo ''; echo formSecurityToken(); echo '
'; echo '' . hsc($this->getLang('legend')) . ''; // paths: multiline textarea $paths = (string)$this->getConf('paths'); echo '
'; // scratchpad_paths: multiline textarea $scratchpadPaths = (string)$this->getConf('scratchpad_paths'); echo '
'; // extensions echo '
'; echo '

' . hsc($this->getLang('listing_defaults')) . '

'; // default_sort $defaultSort = (string)$this->getConf('default_sort'); echo '
'; // default_order $defaultOrder = (string)$this->getConf('default_order'); echo '
'; // default_style $defaultStyle = (string)$this->getConf('default_style'); echo '
'; // default_tableheader $checked = $this->getConf('default_tableheader') ? ' checked="checked"' : ''; echo '
'; // default_foldersfirst $checked = $this->getConf('default_foldersfirst') ? ' checked="checked"' : ''; echo '
'; // default_recursive $checked = $this->getConf('default_recursive') ? ' checked="checked"' : ''; echo '
'; // default_titlefile echo '
'; // default_cache $checked = $this->getConf('default_cache') ? ' checked="checked"' : ''; echo '
'; // default_randlinks $checked = $this->getConf('default_randlinks') ? ' checked="checked"' : ''; echo '
'; // default_showsize $checked = $this->getConf('default_showsize') ? ' checked="checked"' : ''; echo '
'; // default_showdate $checked = $this->getConf('default_showdate') ? ' checked="checked"' : ''; echo '
'; // default_tablecolumns echo '
'; // default_listsep echo '
'; // default_maxheight echo '
'; // thumb_placeholder echo '
'; // gallery_thumb_scale echo '
'; // open_service_url echo '
'; echo ''; echo '
'; echo '
'; echo '
'; } /** * Persist plugin settings to conf/local.php. * * DokuWiki loads conf/local.php on each request; values written there will * be available via getConf(). We write into a dedicated BEGIN/END block so * updates are idempotent. * * @param array $newConf * @return bool */ protected function savePluginLocalConf(array $newConf) { if (!defined('DOKU_CONF')) return false; $plugin = 'luxtools'; $file = DOKU_CONF . 'local.php'; $existing = ''; if (@is_file($file) && @is_readable($file)) { $existing = (string)file_get_contents($file); } if ($existing === '') { $existing = "configKeys as $key) { if (!array_key_exists($key, $newConf)) continue; $value = $newConf[$key]; $lines[] = '$conf[\'plugin\'][\'' . $plugin . '\'][' . var_export($key, true) . '] = ' . $this->exportPhpValue($value, $key) . ';'; } $lines[] = $end; $block = implode("\n", $lines); // Replace or append the block in conf/local.php $beginPos = strpos($existing, $begin); if ($beginPos !== false) { $endPos = strpos($existing, $end, $beginPos); if ($endPos === false) { // malformed existing block - append a new one $content = rtrim($existing) . "\n\n" . $block; } else { $endPos += strlen($end); $content = substr($existing, 0, $beginPos) . $block . substr($existing, $endPos); } } else { $content = rtrim($existing) . "\n\n" . $block; } $ok = false; if (function_exists('io_saveFile')) { $ok = (bool)io_saveFile($file, $content); } else { $ok = @file_put_contents($file, $content, LOCK_EX) !== false; } // Ensure the updated conf/local.php is picked up immediately even when // OPcache is configured to revalidate infrequently (e.g. revalidate_freq=60). if ($ok && function_exists('opcache_invalidate')) { @opcache_invalidate($file, true); } // Best-effort cleanup: stop creating/using legacy conf/plugins/luxtools.local.php $legacy = DOKU_CONF . 'plugins/' . $plugin . '.local.php'; if (@is_file($legacy)) { @unlink($legacy); } return $ok; } /** * Export a value to PHP code. * * We use nowdoc for multiline strings to safely preserve newlines. * * @param mixed $value * @param string $key * @return string */ protected function exportPhpValue($value, string $key): string { if (is_bool($value) || is_int($value) || is_float($value) || $value === null) { return var_export($value, true); } $value = (string)$value; if (str_contains($value, "\n") || str_contains($value, "\r")) { $marker = strtoupper('LUXTOOLS_' . preg_replace('/[^A-Z0-9_]/i', '_', $key) . '_EOT'); // Extremely unlikely, but avoid delimiter collision. while (str_contains($value, $marker)) { $marker .= '_X'; } return "<<<'$marker'\n" . $value . "\n$marker"; } return var_export($value, true); } }