diff --git a/endpoints/admin/siteconfig.php b/endpoints/admin/siteconfig.php new file mode 100644 index 00000000..16db9400 --- /dev/null +++ b/endpoints/admin/siteconfig.php @@ -0,0 +1,113 @@ + Development > Site Configuration + + protected function generate() : void + { + $this->h1 = 'Site Configuration'; + array_unshift($this->title, $this->h1); + + $this->lvTabs = new Tabs(['parent' => "\$\$WH.ge('tabs-generic')"]); + + parent::generate(); + + $this->addScript([SC_CSS_STRING, << $catName) + { + $rows = ''; + foreach (Cfg::forCategory($idx) as $key => [$value, $flags, , $default, $comment]) + $rows .= $this->buildRow($key, $value, $flags, $default, $comment); + + if ($idx == Cfg::CAT_MISCELLANEOUS) + $rows .= 'new configuration'; + + if (!$rows) + continue; + + $this->lvTabs->addDataTab(Profiler::urlize($catName), $catName, '' . $head . $rows . '
'); + } + } + + private function buildRow(string $key, string $value, int $flags, ?string $default, string $comment) : string + { + $buff = ''; + $info = explode(' - ', $comment); + $key = $flags & Cfg::FLAG_PHP ? strtolower($key) : strtoupper($key); + + // name + if (!empty($info[0])) + $buff .= ''.sprintf(Util::$dfnString, $info[0], $key).''; + else + $buff .= ''.$key.''; + + // value + if ($flags & Cfg::FLAG_TYPE_BOOL) + $buff .= '
'; + else if ($flags & Cfg::FLAG_OPT_LIST && !empty($info[1])) + { + $buff .= ''; + } + else if ($flags & Cfg::FLAG_BITMASK && !empty($info[1])) + { + $buff .= '
'; + foreach (explode(', ', $info[1]) as $option) + { + [$idx, $name] = explode(':', $option); + $buff .= ''; + } + $buff .= '
'; + } + else + $buff .= ''; + + // actions + $buff .= ''; + + $buff .= ''; + + if ($default) + $buff .= '|'; + else + $buff .= '|'; + + if (!($flags & Cfg::FLAG_PERSISTENT)) + $buff .= '|'; + + $buff .= ''; + + return $buff; + } +} + +?> diff --git a/endpoints/admin/siteconfig_add.php b/endpoints/admin/siteconfig_add.php new file mode 100644 index 00000000..a99e77a2 --- /dev/null +++ b/endpoints/admin/siteconfig_add.php @@ -0,0 +1,34 @@ + ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Cfg::PATTERN_CONF_KEY_FULL]], + 'val' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ] + ); + + protected function generate() : void + { + if (!$this->assertGET('key', 'val')) + { + trigger_error('AdminSiteconfigActionAddResponse - malformed request received', E_USER_ERROR); + $this->result = Lang::main('intError'); + return; + } + + $key = trim($this->_get['key']); + $val = trim(urldecode($this->_get['val'])); + + $this->result = Cfg::add($key, $val); + } +} + +?> diff --git a/endpoints/admin/siteconfig_remove.php b/endpoints/admin/siteconfig_remove.php new file mode 100644 index 00000000..cef906d0 --- /dev/null +++ b/endpoints/admin/siteconfig_remove.php @@ -0,0 +1,30 @@ + ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Cfg::PATTERN_CONF_KEY_FULL]] + ); + + protected function generate() : void + { + if (!$this->assertGET('key')) + { + trigger_error('AdminSiteconfigActionRemoveResponse - malformed request received', E_USER_ERROR); + $this->result = Lang::main('intError'); + return; + } + + $this->result = Cfg::delete($this->_get['key']); + } +} + +?> diff --git a/endpoints/admin/siteconfig_update.php b/endpoints/admin/siteconfig_update.php new file mode 100644 index 00000000..5afe0bec --- /dev/null +++ b/endpoints/admin/siteconfig_update.php @@ -0,0 +1,34 @@ + ['filter' => FILTER_VALIDATE_REGEXP, 'options' => ['regexp' => Cfg::PATTERN_CONF_KEY_FULL]], + 'val' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextBlob'] ] + ); + + protected function generate() : void + { + if (!$this->assertGET('key', 'val')) + { + trigger_error('AdminSiteconfigActionUpdateResponse - malformed request received', E_USER_ERROR); + $this->result = Lang::main('intError'); + return; + } + + $key = trim($this->_get['key']); + $val = trim(urldecode($this->_get['val'])); + + $this->result = Cfg::set($key, $val); + } +} + +?> diff --git a/includes/cfg.class.php b/includes/cfg.class.php index 2ddffd10..138e541d 100644 --- a/includes/cfg.class.php +++ b/includes/cfg.class.php @@ -7,8 +7,8 @@ if (!defined('AOWOW_REVISION')) class Cfg { - public const PATTERN_CONF_KEY = '/[a-z0-9_\.\-]/i'; - public const PATTERN_INV_CONF_KEY = '/[^a-z0-9_\.\-]/i'; + public const PATTERN_CONF_KEY_CHAR = '/[a-z0-9_\.\-]/i'; + public const PATTERN_CONF_KEY_FULL = '/^[a-z0-9_\.\-]+$/i'; public const PATTERN_INVALID_CHARS = '/\p{C}/ui'; // config flags @@ -116,7 +116,7 @@ class Cfg $key = strtolower($key); - if (preg_match(self::PATTERN_INV_CONF_KEY, $key)) + if (!preg_match(self::PATTERN_CONF_KEY_FULL, $key)) return 'invalid chars in option name: [a-z 0-9 _ . -] are allowed'; if (isset(self::$store[$key])) @@ -129,7 +129,7 @@ class Cfg return 'this configuration option cannot be set'; $flags = self::FLAG_TYPE_STRING | self::FLAG_PHP; - if (!DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `cat`, `flags`) VALUES (?, ?, ?d, ?d)', $key, $value, self::CAT_MISCELLANEOUS, $flags)) + if (!is_int(DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `cat`, `flags`) VALUES (?, ?, ?d, ?d)', $key, $value, self::CAT_MISCELLANEOUS, $flags))) return 'internal error'; self::$store[$key] = [$value, $flags, self::CAT_MISCELLANEOUS, null, null]; @@ -349,7 +349,7 @@ class Cfg } if ($flags & self::FLAG_TYPE_BOOL) - $value = (bool)$value; + $value = $value ? 1 : 0; return ''; } @@ -384,7 +384,17 @@ class Cfg trigger_error($msg, E_USER_ERROR); } - private static function locales(/*int|string*/ $value, ?string &$msg = '') : bool + private static function useSSL() : bool + { + return (($_SERVER['HTTPS'] ?? 'off') != 'off') || (self::$store['force_ssl'][self::IDX_VALUE] ?? 0); + } + + + /***************************/ + /* onSet/onLoad validators */ + /***************************/ + + private static function locales(int|string $value, ?string &$msg = '') : bool { if (!CLI) return true; @@ -397,7 +407,7 @@ class Cfg return false; } - private static function acc_auth_mode(/*int|string*/ $value, ?string &$msg = '') : bool + private static function acc_auth_mode(int|string $value, ?string &$msg = '') : bool { if ($value == 1 && !extension_loaded('gmp')) { @@ -408,7 +418,7 @@ class Cfg return true; } - private static function profiler_enable(/*int|string*/ $value, ?string &$msg = '') : bool + private static function profiler_enable(int|string $value, ?string &$msg = '') : bool { if ($value != 1) return true; @@ -416,7 +426,7 @@ class Cfg return Profiler::queueStart($msg); } - private static function static_host(/*int|string*/ $value, ?string &$msg = '') : bool + private static function static_host(int|string $value, ?string &$msg = '') : bool { self::$store['static_url'] = array( // points js to images & scripts (self::useSSL() ? 'https://' : 'http://').$value, @@ -429,7 +439,7 @@ class Cfg return true; } - private static function site_host(/*int|string*/ $value, ?string &$msg = '') : bool + private static function site_host(int|string $value, ?string &$msg = '') : bool { self::$store['host_url'] = array( // points js to executable files (self::useSSL() ? 'https://' : 'http://').$value, @@ -442,9 +452,15 @@ class Cfg return true; } - private static function useSSL() : bool + private static function cache_mode(int|string $value, ?string &$msg = '') : bool { - return (($_SERVER['HTTPS'] ?? 'off') != 'off') || (self::$store['force_ssl'][self::IDX_VALUE] ?? 0); + if ($value & 0x2 && !class_exists('\Memcached')) + { + $msg .= 'PHP extension Memcached is not enabled.'; + return false; + } + + return true; } private static function screenshot_min_size(int|string $value, ?string &$msg = '') : bool diff --git a/includes/components/response/baseresponse.class.php b/includes/components/response/baseresponse.class.php index 2be3beb7..3bc02c3b 100644 --- a/includes/components/response/baseresponse.class.php +++ b/includes/components/response/baseresponse.class.php @@ -217,6 +217,12 @@ trait TrCache private function memcached() : ?\Memcached { + if (!class_exists('\Memcached')) + { + trigger_error('Memcached is enabled by us but not in php!', E_USER_ERROR); + return null; + } + if (!$this->memcached && (Cfg::get('CACHE_MODE') & CACHE_MODE_MEMCACHED)) { $this->memcached = new \Memcached(); diff --git a/setup/tools/clisetup/siteconfig.us.php b/setup/tools/clisetup/siteconfig.us.php index 17dcf0c8..405061b7 100644 --- a/setup/tools/clisetup/siteconfig.us.php +++ b/setup/tools/clisetup/siteconfig.us.php @@ -114,7 +114,7 @@ CLISetup::registerUtility(new class extends UtilityScript CLI::write(); } - if (CLI::read(['idx' => ['', false, false, Cfg::PATTERN_CONF_KEY]], $uiIndex) && $uiIndex && $uiIndex['idx'] !== '') + if (CLI::read(['idx' => ['', false, false, Cfg::PATTERN_CONF_KEY_CHAR]], $uiIndex) && $uiIndex && $uiIndex['idx'] !== '') { $idx = array_search(strtolower($uiIndex['idx']), $cfgList); if ($idx === false) @@ -147,7 +147,7 @@ CLISetup::registerUtility(new class extends UtilityScript CLI::write(); $setting = array( - 'key' => ['option name', false, false, Cfg::PATTERN_CONF_KEY], + 'key' => ['option name', false, false, Cfg::PATTERN_CONF_KEY_CHAR], 'val' => ['value'] ); if (CLI::read($setting, $uiSetting) && $uiSetting) @@ -443,7 +443,13 @@ CLISetup::registerUtility(new class extends UtilityScript private function testCase(&$protocol, &$host, $testFile, &$status) : bool { - $res = get_headers($protocol.$host.$testFile, true); + // https://stackoverflow.com/questions/14279095/allow-self-signed-certificates-for-https-wrapper + $ctx = stream_context_create(array( + 'ssl' => ['verify_peer' => false, + 'allow_self_signed' => true] + )); + + $res = get_headers($protocol.$host.$testFile, true, $ctx); if (!preg_match('/HTTP\/[0-9\.]+\s+([0-9]+)/', $res[0], $m)) return false; diff --git a/setup/updates/1758578400_10.sql b/setup/updates/1758578400_10.sql new file mode 100644 index 00000000..5e7cd68d --- /dev/null +++ b/setup/updates/1758578400_10.sql @@ -0,0 +1,2 @@ +-- set on_set_fn check +UPDATE `aowow_config` SET `flags` = `flags` | 1024 WHERE `key` = 'cache_mode'; diff --git a/template/pages/admin/siteconfig.tpl.php b/template/pages/admin/siteconfig.tpl.php index ed8a9238..70324333 100644 --- a/template/pages/admin/siteconfig.tpl.php +++ b/template/pages/admin/siteconfig.tpl.php @@ -1,6 +1,8 @@ - +brick('header'); ?> + $this->brick('header'); +?>