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_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_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');
$depth = (int)$INPUT->int('pagelink_search_depth');
if ($depth < 0) $depth = 0;
$newConf['pagelink_search_depth'] = $depth;
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 '';
}
/**
* 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);
}
/**
* Strip nowdoc markers from values when displaying in the admin form.
*
* @param string $value
* @param string $key
* @return string
*/
protected function normalizeMultilineDisplay(string $value, string $key): string
{
$marker = strtoupper('LUXTOOLS_' . preg_replace('/[^A-Z0-9_]/i', '_', $key) . '_EOT');
$prefix = "<<<'$marker'\n";
$suffix = "\n$marker";
if (str_starts_with($value, $prefix) && str_ends_with($value, $suffix)) {
return substr($value, strlen($prefix), -strlen($suffix));
}
return $value;
}
}