Core/Config

* convert configuration from list of constants to object
 * fixes config changes not applying on cli whithout closing and reopening again
 * config variables are no longer embedded in localization text
This commit is contained in:
Sarjuuk
2024-05-28 15:41:44 +02:00
parent 454e09cc78
commit f77d676a19
94 changed files with 1094 additions and 922 deletions

View File

@@ -324,20 +324,7 @@ class AjaxAdmin extends AjaxHandler
$key = trim($this->_get['key']);
$val = trim(urldecode($this->_get['val']));
if ($key === null)
return 'empty option name given';
if (!strlen($key))
return 'invalid chars in option name: [a-z 0-9 _ . -] are allowed';
if (ini_get($key) === false || ini_set($key, $val) === false)
return 'this configuration option cannot be set';
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_config WHERE `flags` & ?d AND `key` = ?', CON_FLAG_PHP, $key))
return 'this configuration option is already in use';
DB::Aowow()->query('INSERT IGNORE INTO ?_config (`key`, `value`, `cat`, `flags`) VALUES (?, ?, 0, ?d)', $key, $val, CON_FLAG_TYPE_STRING | CON_FLAG_PHP);
return '';
return Cfg::add($key, $val);
}
protected function confRemove() : string
@@ -345,39 +332,15 @@ class AjaxAdmin extends AjaxHandler
if (!$this->reqGET('key'))
return 'invalid configuration option given';
if (DB::Aowow()->query('DELETE FROM ?_config WHERE `key` = ? AND (`flags` & ?d) = 0', $this->_get['key'], CON_FLAG_PERSISTENT))
return '';
else
return 'option name is either protected or was not found';
return Cfg::delete($this->_get['key']);
}
protected function confUpdate() : string
{
$key = trim($this->_get['key']);
$val = trim(urldecode($this->_get['val']));
$msg = '';
if (!strlen($key))
return 'empty option name given';
$cfg = DB::Aowow()->selectRow('SELECT `flags`, `value` FROM ?_config WHERE `key` = ?', $key);
if (!$cfg)
return 'configuration option not found';
if (!($cfg['flags'] & CON_FLAG_TYPE_STRING) && !strlen($val))
return 'empty value given';
else if ($cfg['flags'] & CON_FLAG_TYPE_INT && !preg_match('/^-?\d+$/i', $val))
return "value must be integer";
else if ($cfg['flags'] & CON_FLAG_TYPE_FLOAT && !preg_match('/^-?\d*(,|.)?\d+$/i', $val))
return "value must be float";
else if ($cfg['flags'] & CON_FLAG_TYPE_BOOL && $val != '1')
$val = '0';
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $val, $key);
if (!$this->confOnChange($key, $val, $msg))
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $cfg['value'], $key);
return $msg;
return Cfg::set($key, $val);
}
protected function wtSave() : string
@@ -563,7 +526,7 @@ class AjaxAdmin extends AjaxHandler
protected static function checkKey(string $val) : string
{
// expecting string
if (preg_match('/[^a-z0-9_\.\-]/i', $val))
if (preg_match(Cfg::PATTERN_INV_CONF_KEY, $val))
return '';
return strtolower($val);
@@ -586,73 +549,6 @@ class AjaxAdmin extends AjaxHandler
return '';
}
/**********/
/* helper */
/**********/
private static function confOnChange(string $key, string $val, string &$msg) : bool
{
$fn = $buildList = null;
switch ($key)
{
case 'battlegroup':
$buildList = 'realms,realmMenu';
break;
case 'name_short':
$buildList = 'searchboxBody,demo,searchplugin';
break;
case 'site_host':
$buildList = 'searchplugin,demo,power,searchboxBody';
break;
case 'static_host':
$buildList = 'searchplugin,power,searchboxBody,searchboxScript';
break;
case 'contact_email':
$buildList = 'markup';
break;
case 'locales':
$buildList = 'locales';
$msg .= ' * remember to rebuild all static files for the language you just added.<br />';
$msg .= ' * you can speed this up by supplying the regionCode to the setup: <pre class="q1">--locales=<regionCodes,> -f</pre>';
break;
case 'profiler_enable':
$buildList = 'realms,realmMenu';
$fn = function($x) use (&$msg) {
if (!$x)
return true;
return Profiler::queueStart($msg);
};
break;
case 'acc_auth_mode':
$fn = function($x) use (&$msg) {
if ($x == 1 && !extension_loaded('gmp'))
{
$msg .= 'PHP extension GMP is required to use TrinityCore as auth source, but is not currently enabled.<br />';
return false;
}
return true;
};
break;
default: // nothing to do, everything is fine
return true;
}
if ($buildList)
{
// we need to use exec as build() can only be run from CLI
exec('php aowow --build='.$buildList, $out);
foreach ($out as $o)
if (strstr($o, 'ERR'))
$msg .= explode('0m]', $o)[1]."<br />\n";
}
return $fn ? $fn($val) : true;
}
}
?>

View File

@@ -86,7 +86,7 @@ class AjaxData extends AjaxHandler
case 'item-scaling':
case 'realms':
case 'statistics':
if (!Util::loadStaticFile($set, $result) && CFG_DEBUG)
if (!Util::loadStaticFile($set, $result) && Cfg::get('DEBUG'))
$result .= "alert('could not fetch static data: ".$set."');";
$result .= "\n\n";
@@ -102,7 +102,7 @@ class AjaxData extends AjaxHandler
case 'enchants':
case 'itemsets':
case 'pets':
if (!Util::loadStaticFile($set, $result, true) && CFG_DEBUG)
if (!Util::loadStaticFile($set, $result, true) && Cfg::get('DEBUG'))
$result .= "alert('could not fetch static data: ".$set." for locale: ".User::$localeString."');";
$result .= "\n\n";

View File

@@ -48,7 +48,7 @@ class AjaxProfile extends AjaxHandler
if (!$this->params)
return;
if (!CFG_PROFILER_ENABLE)
if (!Cfg::get('PROFILER_ENABLE'))
return;
switch ($this->params[0])
@@ -563,7 +563,7 @@ class AjaxProfile extends AjaxHandler
if ($pBase['realm'])
{
$profile['region'] = [$rData['region'], Lang::profiler('regions', $rData['region'])];
$profile['battlegroup'] = [Profiler::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP];
$profile['battlegroup'] = [Profiler::urlize(Cfg::get('BATTLEGROUP')), Cfg::get('BATTLEGROUP')];
$profile['realm'] = [Profiler::urlize($rData['name'], true), $rData['name']];
}
@@ -616,7 +616,7 @@ class AjaxProfile extends AjaxHandler
$profile['titles'] = $data;
break;
case Type::QUEST:
$qList = new QuestList(array(['id', array_keys($data)], CFG_SQL_LIMIT_NONE));
$qList = new QuestList(array(['id', array_keys($data)], Cfg::get('SQL_LIMIT_NONE')));
$qResult = [];
foreach ($qList->iterate() as $id => $__)
$qResult[$id] = [$qList->getField('cat1'), $qList->getField('cat2')];
@@ -691,7 +691,7 @@ class AjaxProfile extends AjaxHandler
if ($items = DB::Aowow()->select('SELECT * FROM ?_profiler_items WHERE id = ?d', $pBase['id']))
{
$itemz = new ItemList(array(['id', array_column($items, 'item')], CFG_SQL_LIMIT_NONE));
$itemz = new ItemList(array(['id', array_column($items, 'item')], Cfg::get('SQL_LIMIT_NONE')));
if (!$itemz->error)
{
$data = $itemz->getListviewData(ITEMINFO_JSON | ITEMINFO_SUBITEMS);
@@ -720,7 +720,7 @@ class AjaxProfile extends AjaxHandler
// if ($au = $char->getField('auras'))
// {
// $auraz = new SpellList(array(['id', $char->getField('auras')], CFG_SQL_LIMIT_NONE));
// $auraz = new SpellList(array(['id', $char->getField('auras')], Cfg::get('SQL_LIMIT_NONE')));
// $dataz = $auraz->getListviewData();
// $modz = $auraz->getProfilerMods();

View File

@@ -59,7 +59,7 @@ abstract class BaseType
{
$where = [];
$linking = ' AND ';
$limit = CFG_SQL_LIMIT_DEFAULT;
$limit = Cfg::get('SQL_LIMIT_DEFAULT');
if (!$this->queryBase || $conditions === null)
return;
@@ -875,7 +875,7 @@ trait sourceHelper
$buff[$_curTpl['moreType']][] = $_curTpl['moreTypeId'];
foreach ($buff as $type => $ids)
$this->sourceMore[$type] = Type::newList($type, [CFG_SQL_LIMIT_NONE, ['id', $ids]]);
$this->sourceMore[$type] = Type::newList($type, [Cfg::get('SQL_LIMIT_NONE'), ['id', $ids]]);
}
$s = array_keys($this->sources[$this->id]);

View File

@@ -116,7 +116,7 @@ class CommunityContent
if (!$_)
continue;
$obj = Type::newList($type, [CFG_SQL_LIMIT_NONE, ['id', $_]]);
$obj = Type::newList($type, [Cfg::get('SQL_LIMIT_NONE'), ['id', $_]]);
if (!$obj)
continue;
@@ -154,7 +154,7 @@ class CommunityContent
CC_FLAG_DELETED,
User::$id,
User::isInGroup(U_GROUP_COMMENTS_MODERATOR),
CFG_SQL_LIMIT_DEFAULT
Cfg::get('SQL_LIMIT_DEFAULT')
);
foreach ($comments as $c)
@@ -320,7 +320,7 @@ class CommunityContent
if (!$ids)
continue;
$obj = Type::newList($t, [CFG_SQL_LIMIT_NONE, ['id', $ids]]);
$obj = Type::newList($t, [Cfg::get('SQL_LIMIT_NONE'), ['id', $ids]]);
if (!$obj || $obj->error)
continue;
@@ -410,13 +410,13 @@ class CommunityContent
{
$videos = DB::Aowow()->selectPage($nFound, self::$viQuery,
CC_FLAG_STICKY,
$typeOrUser < 0 ? -$typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeId : DBSIMPLE_SKIP,
$typeOrUser < 0 ? -$typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeId : DBSIMPLE_SKIP,
CC_FLAG_APPROVED,
CC_FLAG_DELETED,
!$typeOrUser ? 'date' : DBSIMPLE_SKIP,
!$typeOrUser ? CFG_SQL_LIMIT_SEARCH : DBSIMPLE_SKIP
!$typeOrUser ? 'date' : DBSIMPLE_SKIP,
!$typeOrUser ? Cfg::get('SQL_LIMIT_SEARCH') : DBSIMPLE_SKIP
);
if ($typeOrUser <= 0) // not for search by type/typeId
@@ -455,13 +455,13 @@ class CommunityContent
{
$screenshots = DB::Aowow()->selectPage($nFound, self::$ssQuery,
CC_FLAG_STICKY,
$typeOrUser < 0 ? -$typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeId : DBSIMPLE_SKIP,
$typeOrUser < 0 ? -$typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeOrUser : DBSIMPLE_SKIP,
$typeOrUser > 0 ? $typeId : DBSIMPLE_SKIP,
CC_FLAG_APPROVED,
CC_FLAG_DELETED,
!$typeOrUser ? 'date' : DBSIMPLE_SKIP,
!$typeOrUser ? CFG_SQL_LIMIT_SEARCH : DBSIMPLE_SKIP
!$typeOrUser ? 'date' : DBSIMPLE_SKIP,
!$typeOrUser ? Cfg::get('SQL_LIMIT_SEARCH') : DBSIMPLE_SKIP
);
if ($typeOrUser <= 0) // not for search by type/typeId

387
includes/config.class.php Normal file
View File

@@ -0,0 +1,387 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
class Cfg
{
public const PATTERN_CONF_KEY = '/[a-z0-9_\.\-]/i';
public const PATTERN_INV_CONF_KEY = '/[^a-z0-9_\.\-]/i';
public const PATTERN_INVALID_CHARS = '/\p{C}/ui';
// config flags
public const FLAG_TYPE_INT = 0x001; // validate with intVal()
public const FLAG_TYPE_FLOAT = 0x002; // validate with floatVal()
public const FLAG_TYPE_BOOL = 0x004; // 0 || 1
public const FLAG_TYPE_STRING = 0x008; //
public const FLAG_OPT_LIST = 0x010; // single option
public const FLAG_BITMASK = 0x020; // multiple options
public const FLAG_PHP = 0x040; // applied with ini_set() [restrictions apply!]
public const FLAG_PERSISTENT = 0x080; // can not be deleted
public const FLAG_REQUIRED = 0x100; // required to have non-empty value
public const FLAG_ON_LOAD_FN = 0x200; // run static function of the same name after load
public const FLAG_ON_SET_FN = 0x400; // run static function of the same name as validator
public const FLAG_INTERNAL = 0x800; // can not be configures, automaticly calculated, skip on lists
public const CAT_MISCELLANEOUS = 0;
public const CAT_SITE = 1;
public const CAT_CACHE = 2;
public const CAT_ACCOUNT = 3;
public const CAT_SESSION = 4;
public const CAT_SITE_REPUTATION = 5;
public const CAT_ANALYTICS = 6;
public const CAT_PROFILER = 7;
public static $categories = array( // don't mind the ordering ... please?
1 => 'Site', 'Caching', 'Account', 'Session', 'Site Reputation', 'Google Analytics', 'Profiler', 0 => 'Other'
);
private const IDX_VALUE = 0;
private const IDX_FLAGS = 1;
private const IDX_CATEGORY = 2;
private const IDX_DEFAULT = 3;
private const IDX_COMMENT = 4;
private static $store = []; // name => [value, flags, cat, default, comment]
private static $rebuildScripts = array(
// 'rep_req_border_unco' => ['global'], // currently not a template or buildScript
// 'rep_req_border_rare' => ['global'],
// 'rep_req_border_epic' => ['global'],
// 'rep_req_border_lege' => ['global'],
'profiler_enable' => ['realms', 'realmMenu'],
'battlegroup' => ['realms', 'realmMenu'],
'name_short' => ['searchplugin', 'searchboxBody', 'searchboxScript', 'demo'],
'site_host' => ['searchplugin', 'searchboxBody', 'searchboxScript', 'demo', 'power'],
'static_host' => ['searchplugin', 'searchboxBody', 'searchboxScript', 'power'],
'contact_email' => ['markup'],
'locales' => ['locales']
);
public static function load() : void
{
if (!DB::isConnectable(DB_AOWOW))
return;
$sets = DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, `value` AS "0", `flags` AS "1", `cat` AS "2", `default` AS "3", `comment` AS "4" FROM ?_config ORDER BY `key` ASC');
foreach ($sets as $key => [$value, $flags, $catg, $default, $comment])
{
$php = $flags & self::FLAG_PHP;
if ($err = self::validate($value, $flags, $comment))
{
trigger_error('Aowow config '.strtoupper($key).' failed validation and was skipped: '.$err, E_USER_ERROR);
continue;
}
if ($flags & self::FLAG_INTERNAL)
{
trigger_error('Aowow config '.strtoupper($key).' is flagged as internaly generated and should not have been set in DB.', E_USER_ERROR);
continue;
}
if ($flags & self::FLAG_ON_LOAD_FN)
{
if (!method_exists('Cfg', $key))
trigger_error('Aowow config '.strtoupper($key).' flagged for onLoadFN handling, but no handler was set', E_USER_WARNING);
else
self::{$key}($value);
}
if ($php)
ini_set(strtolower($key), $value);
self::$store[strtolower($key)] = [$value, $flags, $catg, $default, $comment];
}
}
public static function add(string $key, /*int|string*/ $value) : string
{
if (!$key)
return 'empty option name given';
$key = strtolower($key);
if (preg_match(self::PATTERN_INV_CONF_KEY, $key))
return 'invalid chars in option name: [a-z 0-9 _ . -] are allowed';
if (isset(self::$store[$key]))
return 'this configuration option is already in use';
if ($errStr = self::validate($value))
return $errStr;
if (ini_get($key) === false || ini_set($key, $value) === false)
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))
return 'internal error';
self::$store[$key] = [$value, $flags, self::CAT_MISCELLANEOUS, null, null];
return '';
}
public static function delete(string $key) : string
{
$key = strtolower($key);
if (!isset(self::$store[$key]))
return 'configuration option not found';
if (self::$store[$key][self::IDX_FLAGS] & self::FLAG_PERSISTENT)
return 'can\'t delete persistent options';
if (!(self::$store[$key][self::IDX_FLAGS] & self::FLAG_PHP))
return 'can\'t delete non-php options';
if (self::$store[$key][self::IDX_FLAGS] & self::FLAG_INTERNAL)
return 'can\'t delete internal options';
if (!DB::Aowow()->query('DELETE FROM ?_config WHERE `key` = ? AND (`flags` & ?d) = 0 AND (`flags` & ?d) > 0', $key, self::FLAG_PERSISTENT, self::FLAG_PHP))
return 'internal error';
unset(self::$store[$key]);
return '';
}
public static function get(string $key, bool $fromDB = false, bool $fullInfo = false) // : int|float|string
{
$key = strtolower($key);
if (!isset(self::$store[$key]))
{
trigger_error('cfg not defined: '.$key, E_USER_ERROR);
return '';
}
if ($fromDB && $fullInfo)
return array_values(DB::Aowow()->selectRow('SELECT `value`, `flags`, `cat`, `default`, `comment` FROM ?_config WHERE `key` = ?', $key));
if ($fromDB)
return DB::Aowow()->selectCell('SELECT `value` FROM ?_config WHERE `key` = ?', $key);
if ($fullInfo)
return self::$store[$key];
return self::$store[$key][self::IDX_VALUE];
}
public static function set(string $key, /*int|string*/ $value, ?array &$rebuildFiles = []) : string
{
$key = strtolower($key);
if (!isset(self::$store[$key]))
return 'configuration option not found';
[$oldValue, $flags, , , $comment] = self::$store[$key];
if ($flags & self::FLAG_INTERNAL)
return 'can\'t set internal options directly';
if ($err = self::validate($value, $flags, $comment))
return $err;
if ($flags & self::FLAG_REQUIRED && !strlen($value))
return 'empty value given for required config';
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $value, $key);
self::$store[$key][self::IDX_VALUE] = $value;
// validate change
if ($flags & self::FLAG_ON_SET_FN)
{
$errMsg = '';
if (!method_exists('Cfg', $key))
$errMsg = 'required onSetFN validator not set';
else
self::{$key}($value, $errMsg);
if ($errMsg)
{
// rollback change
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $oldValue, $key);
self::$store[$key][self::IDX_VALUE] = $oldValue;
// trigger_error($errMsg) ?
return $errMsg;
}
}
if ($flags & self::FLAG_ON_LOAD_FN)
{
if (!method_exists('Cfg', $key))
return 'Aowow config '.strtoupper($key).' flagged for onLoadFN handling, but no handler was set';
else
self::{$key}($value);
}
// trigger setup build
return self::handleFileBuild($key, $rebuildFiles);
}
public static function reset(string $key, ?array &$rebuildFiles = []) : string
{
$key = strtolower($key);
if (!isset(self::$store[$key]))
return 'configuration option not found';
[, $flags, , $default, ] = self::$store[$key];
if ($flags & self::FLAG_INTERNAL)
return 'can\'t set internal options directly';
if (!$default)
return 'config option has no default value';
// @eval .. some dafault values are supplied as bitmask or the likes
if (!($flags & Cfg::FLAG_TYPE_STRING))
$default = @eval('return ('.$default.');');
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $default, $key);
self::$store[$key][self::IDX_VALUE] = $default;
// trigger setup build
return self::handleFileBuild($key, $rebuildFiles);
}
public static function forCategory(int $category) : Generator
{
foreach (self::$store as $k => [, $flags, $catg, , ])
if ($catg == $category && !($flags & self::FLAG_INTERNAL))
yield $k => self::$store[$k];
}
public static function applyToString(string $string) : string
{
return preg_replace_callback(
['/CFG_([A-Z_]+)/', '/((HOST|STATIC)_URL)/'],
function ($m) {
if (!isset(self::$store[strtolower($m[1])]))
return $m[1];
[$val, $flags, , , ] = self::$store[strtolower($m[1])];
return $flags & (self::FLAG_TYPE_FLOAT | self::FLAG_TYPE_INT) ? Lang::nf($val) : $val;
},
$string
);
}
/************/
/* internal */
/************/
private static function validate(&$value, int $flags = self::FLAG_TYPE_STRING | self::FLAG_PHP, string $comment = ' - ') : string
{
$value = preg_replace(self::PATTERN_INVALID_CHARS, '', $value);
if (!($flags & (self::FLAG_TYPE_BOOL | self::FLAG_TYPE_FLOAT | self::FLAG_TYPE_INT | self::FLAG_TYPE_STRING)))
return 'no type set for value';
if ($flags & self::FLAG_TYPE_INT && !Util::checkNumeric($value, NUM_CAST_INT))
return 'value must be integer';
if ($flags & self::FLAG_TYPE_FLOAT && !Util::checkNumeric($value, NUM_CAST_FLOAT))
return 'value must be float';
if ($flags & self::FLAG_OPT_LIST)
{
$info = explode(' - ', $comment)[1];
foreach (explode(', ', $info) as $option)
if (explode(':', $option)[0] == $value)
return '';
return 'value not in range';
}
if ($flags & self::FLAG_BITMASK)
{
$mask = 0x0;
$info = explode(' - ', $comment)[1];
foreach (explode(', ', $info) as $option)
$mask |= (1 << explode(':', $option)[0]);
if (!($value &= $mask))
return 'value not in range';
}
if ($flags & self::FLAG_TYPE_BOOL)
$value = (bool)$value;
return '';
}
private static function handleFileBuild(string $key, array &$rebuildFiles) : string
{
if (!isset(self::$rebuildScripts[$key]))
return '';
$msg = '';
if (CLI)
{
$rebuildFiles = array_merge($rebuildFiles, self::$rebuildScripts[$key]);
return '';
}
// not in CLI mode and build() can only be run from CLI. .. todo: other options..?
exec('php aowow --build='.implode(',', self::$rebuildScripts[$key]), $out);
foreach ($out as $o)
if (strstr($o, 'ERR'))
$msg .= explode('0m]', $o)[1]."<br />\n";
return $msg;
}
private static function acc_auth_mode(/*int|string*/ $value, ?string $msg = '') : bool
{
if ($value == 1 && !extension_loaded('gmp'))
{
$msg .= 'PHP extension GMP is required to use TrinityCore as auth source, but is not currently enabled.';
return false;
}
return true;
}
private static function profiler_enable(/*int|string*/ $value, ?string $msg = '') : bool
{
if ($value != 1)
return true;
return Profiler::queueStart($msg);
}
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,
self::FLAG_PERSISTENT | self::FLAG_TYPE_STRING | self::FLAG_INTERNAL,
self::CAT_SITE,
null, // no default value
null, // no comment/info
);
return true;
}
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,
self::FLAG_PERSISTENT | self::FLAG_TYPE_STRING | self::FLAG_INTERNAL,
self::CAT_SITE,
null, // no default value
null, // no comment/info
);
return true;
}
private static function useSSL() : bool
{
return (($_SERVER['HTTPS'] ?? 'off') != 'off') || (self::$store['force_ssl'][self::IDX_VALUE] ?? 0);
}
}
?>

View File

@@ -79,7 +79,7 @@ class DB
// make number sensible again
$data['code'] = abs($data['code']);
if (defined('CFG_DEBUG') && CFG_DEBUG)
if (Cfg::get('DEBUG') >= CLI::LOG_INFO)
{
echo "\nDB ERROR\n";
foreach ($data as $k => $v)

View File

@@ -98,16 +98,6 @@ define('SITEREP_ACTION_ARTICLE', 16); // Guide approved (a
define('SITEREP_ACTION_USER_WARNED', 17); // Moderator Warning
define('SITEREP_ACTION_USER_SUSPENDED', 18); // Moderator Suspension
// config flags
define('CON_FLAG_TYPE_INT', 0x01); // validate with intVal()
define('CON_FLAG_TYPE_FLOAT', 0x02); // validate with floatVal()
define('CON_FLAG_TYPE_BOOL', 0x04); // 0 || 1
define('CON_FLAG_TYPE_STRING', 0x08); //
define('CON_FLAG_OPT_LIST', 0x10); // single option
define('CON_FLAG_BITMASK', 0x20); // multiple options
define('CON_FLAG_PHP', 0x40); // applied with ini_set() [restrictions apply!]
define('CON_FLAG_PERSISTENT', 0x80); // can not be deleted
// Auth Result
define('AUTH_OK', 0);
define('AUTH_WRONGUSER', 1);

View File

@@ -22,15 +22,10 @@ if ($error)
die(CLI ? strip_tags($error) : $error);
if (file_exists('config/config.php'))
require_once 'config/config.php';
else
$AoWoWconf = [];
require_once 'includes/defines.php';
require_once 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master)
require_once 'includes/utilities.php'; // helper functions
require_once 'includes/config.class.php'; // Config holder
require_once 'includes/game.php'; // game related data & functions
require_once 'includes/profiler.class.php';
require_once 'includes/user.class.php';
@@ -93,36 +88,59 @@ set_error_handler(function($errNo, $errStr, $errFile, $errLine)
if (strstr($errStr, 'mysqli_connect') && $errNo == E_WARNING)
return true;
$errName = 'unknown error'; // errors not in this list can not be handled by set_error_handler (as per documentation) or are ignored
$uGroup = U_GROUP_EMPLOYEE;
$errName = 'unknown error'; // errors not in this list can not be handled by set_error_handler (as per documentation) or are ignored
$uGroup = U_GROUP_EMPLOYEE;
$logLevel = CLI::LOG_BLANK;
if ($errNo == E_WARNING) // 0x0002
$errName = 'E_WARNING';
{
$errName = 'E_WARNING';
$logLevel = CLI::LOG_WARN;
}
else if ($errNo == E_PARSE) // 0x0004
$errName = 'E_PARSE';
{
$errName = 'E_PARSE';
$logLevel = CLI::LOG_ERROR;
}
else if ($errNo == E_NOTICE) // 0x0008
$errName = 'E_NOTICE';
{
$errName = 'E_NOTICE';
$logLevel = CLI::LOG_INFO;
}
else if ($errNo == E_USER_ERROR) // 0x0100
$errName = 'E_USER_ERROR';
{
$errName = 'E_USER_ERROR';
$logLevel = CLI::LOG_ERROR;
}
else if ($errNo == E_USER_WARNING) // 0x0200
$errName = 'E_USER_WARNING';
{
$errName = 'E_USER_WARNING';
$logLevel = CLI::LOG_WARN;
}
else if ($errNo == E_USER_NOTICE) // 0x0400
{
$errName = 'E_USER_NOTICE';
$uGroup = U_GROUP_STAFF;
$errName = 'E_USER_NOTICE';
$uGroup = U_GROUP_STAFF;
$logLevel = CLI::LOG_INFO;
}
else if ($errNo == E_RECOVERABLE_ERROR) // 0x1000
$errName = 'E_RECOVERABLE_ERROR';
Util::addNote($uGroup, $errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine);
if (CLI)
CLI::write($errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine, $errNo & (E_WARNING | E_USER_WARNING | E_NOTICE | E_USER_NOTICE) ? CLI::LOG_WARN : CLI::LOG_ERROR);
{
$errName = 'E_RECOVERABLE_ERROR';
$logLevel = CLI::LOG_ERROR;
}
if (DB::isConnected(DB_AOWOW))
DB::Aowow()->query('INSERT INTO ?_errors (`date`, `version`, `phpError`, `file`, `line`, `query`, `userGroups`, `message`) VALUES (UNIX_TIMESTAMP(), ?d, ?d, ?, ?d, ?, ?d, ?) ON DUPLICATE KEY UPDATE `date` = UNIX_TIMESTAMP()',
AOWOW_REVISION, $errNo, $errFile, $errLine, CLI ? 'CLI' : ($_SERVER['QUERY_STRING'] ?? ''), User::$groups, $errStr
);
if (Cfg::get('DEBUG') >= $logLevel)
{
Util::addNote($uGroup, $errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine);
if (CLI)
CLI::write($errName.' - '.$errStr.' @ '.$errFile. ':'.$errLine, $errNo & (E_WARNING | E_USER_WARNING | E_NOTICE | E_USER_NOTICE) ? CLI::LOG_WARN : CLI::LOG_ERROR);
}
return true;
}, E_AOWOW);
@@ -161,6 +179,11 @@ register_shutdown_function(function()
});
// Setup DB-Wrapper
if (file_exists('config/config.php'))
require_once 'config/config.php';
else
$AoWoWconf = [];
if (!empty($AoWoWconf['aowow']['db']))
DB::load(DB_AOWOW, $AoWoWconf['aowow']);
@@ -175,80 +198,29 @@ if (!empty($AoWoWconf['characters']))
if (!empty($charDBInfo))
DB::load(DB_CHARACTERS . $realm, $charDBInfo);
// load config to constants
function loadConfig(bool $noPHP = false) : void
{
$sets = DB::isConnected(DB_AOWOW) ? DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, `value`, `flags` FROM ?_config') : [];
foreach ($sets as $k => $v)
{
$php = $v['flags'] & CON_FLAG_PHP;
if ($php && $noPHP)
continue;
// this should not have been possible
if (!strlen($v['value']) && !($v['flags'] & CON_FLAG_TYPE_STRING) && !$php)
{
trigger_error('Aowow config value CFG_'.strtoupper($k).' is empty - config will not be used!', E_USER_ERROR);
continue;
}
if ($v['flags'] & CON_FLAG_TYPE_INT)
$val = intVal($v['value']);
else if ($v['flags'] & CON_FLAG_TYPE_FLOAT)
$val = floatVal($v['value']);
else if ($v['flags'] & CON_FLAG_TYPE_BOOL)
$val = (bool)$v['value'];
else if ($v['flags'] & CON_FLAG_TYPE_STRING)
$val = preg_replace("/[\p{C}]/ui", '', $v['value']);
else if ($php)
{
trigger_error('PHP config value '.strtolower($k).' has no type set - config will not be used!', E_USER_ERROR);
continue;
}
else // if (!$php)
{
trigger_error('Aowow config value CFG_'.strtoupper($k).' has no type set - value forced to 0!', E_USER_ERROR);
$val = 0;
}
if ($php)
ini_set(strtolower($k), $val);
else if (!defined('CFG_'.strtoupper($k)))
define('CFG_'.strtoupper($k), $val);
}
$required = ['CFG_SCREENSHOT_MIN_SIZE', 'CFG_CONTACT_EMAIL', 'CFG_NAME', 'CFG_NAME_SHORT', 'CFG_FORCE_SSL', 'CFG_DEBUG'];
foreach ($required as $r)
if (!defined($r))
define($r, '');
}
loadConfig();
$AoWoWconf = null; // empty auths
$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || (!empty($AoWoWconf['aowow']) && CFG_FORCE_SSL);
if (defined('CFG_STATIC_HOST')) // points js to images & scripts
define('STATIC_URL', ($secure ? 'https://' : 'http://').CFG_STATIC_HOST);
if (defined('CFG_SITE_HOST')) // points js to executable files
define('HOST_URL', ($secure ? 'https://' : 'http://').CFG_SITE_HOST);
// load config from DB
Cfg::load();
// handle non-fatal errors and notices
error_reporting(CFG_DEBUG ? E_AOWOW : 0);
error_reporting(Cfg::get('DEBUG') ? E_AOWOW : 0);
if (!CLI)
{
// not displaying the brb gnomes as static_host is missing, but eh...
if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD) || !defined('HOST_URL') || !defined('STATIC_URL'))
if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD) || !Cfg::get('HOST_URL') || !Cfg::get('STATIC_URL'))
(new GenericPage())->maintenance();
// Setup Session
if (CFG_SESSION_CACHE_DIR && Util::writeDir(CFG_SESSION_CACHE_DIR))
session_save_path(getcwd().'/'.CFG_SESSION_CACHE_DIR);
$cacheDir = Cfg::get('SESSION_CACHE_DIR');
if ($cacheDir && Util::writeDir($cacheDir))
session_save_path(getcwd().'/'.$cacheDir);
session_set_cookie_params(15 * YEAR, '/', '', $secure, true);
session_set_cookie_params(15 * YEAR, '/', '', (($_SERVER['HTTPS'] ?? 'off') != 'off') || Cfg::get('FORCE_SSL'), true);
session_cache_limiter('private');
if (!session_start())
{
@@ -260,7 +232,7 @@ if (!CLI)
User::save(); // save user-variables in session
// set up some logging (~10 queries will execute before we init the user and load the config)
if (CFG_DEBUG && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
if (Cfg::get('DEBUG') >= CLI::LOG_INFO && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
{
DB::Aowow()->setLogger(['DB', 'profiler']);
DB::World()->setLogger(['DB', 'profiler']);
@@ -278,7 +250,7 @@ if (!CLI)
if (isset($_GET['locale']))
{
$loc = intVal($_GET['locale']);
if ($loc <= MAX_LOCALES && $loc >= 0 && (CFG_LOCALES & (1 << $loc)))
if ($loc <= MAX_LOCALES && $loc >= 0 && (Cfg::get('LOCALES') & (1 << $loc)))
User::useLocale($loc);
}
@@ -293,6 +265,4 @@ if (!CLI)
else if (DB::isConnected(DB_AOWOW))
Lang::load(LOCALE_EN);
$AoWoWconf = null; // empty auths
?>

View File

@@ -283,7 +283,7 @@ class Loot
if (!$struct)
return false;
$items = new ItemList(array(['i.id', $struct[1]], CFG_SQL_LIMIT_NONE));
$items = new ItemList(array(['i.id', $struct[1]], Cfg::get('SQL_LIMIT_NONE')));
$this->jsGlobals = $items->getJSGlobals(GLOBALINFO_SELF | GLOBALINFO_RELATED);
$foo = $items->getListviewData();
@@ -386,13 +386,16 @@ class Loot
return true;
}
public function getByItem(int $entry, int $maxResults = CFG_SQL_LIMIT_DEFAULT, array $lootTableList = []) : bool
public function getByItem(int $entry, int $maxResults = -1, array $lootTableList = []) : bool
{
$this->entry = intVal($entry);
if (!$this->entry)
return false;
if ($maxResults < 0)
$maxResults = Cfg::get('SQL_LIMIT_DEFAULT');
// [fileName, tabData, tabName, tabId, extraCols, hiddenCols, visibleCols]
$tabsFinal = array(
[Type::ITEM, [], '$LANG.tab_containedin', 'contained-in-item', [], [], []],

View File

@@ -243,7 +243,7 @@ class Profiler
// not on already scheduled - recalc time and set status to PR_QUEUE_STATUS_WAITING
if ($rData['status'] != PR_QUEUE_STATUS_WAITING)
{
$newTime = CFG_DEBUG ? time() : max($rData['time'] + CFG_PROFILER_RESYNC_DELAY, time());
$newTime = Cfg::get('DEBUG') ? time() : max($rData['time'] + Cfg::get('PROFILER_RESYNC_DELAY'), time());
DB::Aowow()->query('UPDATE ?_profiler_sync SET requestTime = ?d, status = ?d, errorCode = 0 WHERE realm = ?d AND realmGUID = ?d AND `type` = ?d AND typeId = ?d', $newTime, PR_QUEUE_STATUS_WAITING, $realmId, $guid, $type, $localId);
}
}
@@ -287,7 +287,7 @@ class Profiler
public static function resyncStatus($type, array $subjectGUIDs)
{
$response = [CFG_PROFILER_ENABLE ? 2 : 0]; // in theory you could have multiple queues; used as divisor for: (15 / x) + 2
$response = [Cfg::get('PROFILER_ENABLE') ? 2 : 0]; // in theory you could have multiple queues; used as divisor for: (15 / x) + 2
if (!$subjectGUIDs)
$response[] = [PR_QUEUE_STATUS_ENDED, 0, 0, PR_QUEUE_ERROR_CHAR];
else
@@ -306,7 +306,7 @@ class Profiler
else
$response[] = array(
$subjectStatus[$guid]['status'],
$subjectStatus[$guid]['status'] != PR_QUEUE_STATUS_READY ? CFG_PROFILER_RESYNC_PING : 0,
$subjectStatus[$guid]['status'] != PR_QUEUE_STATUS_READY ? Cfg::get('PROFILER_RESYNC_PING') : 0,
array_search($type.':'.$guid, $queue) + 1,
0,
1 // nResycTries - unsure about this one

View File

@@ -152,7 +152,7 @@ class RemoteArenaTeamList extends ArenaTeamList
foreach ($this->iterate() as $guid => &$curTpl)
{
// battlegroup
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
// realm, rank
$r = explode(':', $guid);
@@ -208,7 +208,7 @@ class RemoteArenaTeamList extends ArenaTeamList
);
// equalize subject distribution across realms
$limit = CFG_SQL_LIMIT_DEFAULT;
$limit = Cfg::get('SQL_LIMIT_DEFAULT');
foreach ($conditions as $c)
if (is_int($c))
$limit = $c;
@@ -244,7 +244,7 @@ class RemoteArenaTeamList extends ArenaTeamList
foreach ($teams as $team)
$gladiators = array_merge($gladiators, array_keys($team));
$profiles[$realmId] = new RemoteProfileList(array(['c.guid', $gladiators], CFG_SQL_LIMIT_NONE), ['sv' => $realmId]);
$profiles[$realmId] = new RemoteProfileList(array(['c.guid', $gladiators], Cfg::get('SQL_LIMIT_NONE')), ['sv' => $realmId]);
if (!$profiles[$realmId]->error)
$profiles[$realmId]->initializeLocalEntries();
@@ -346,7 +346,7 @@ class LocalArenaTeamList extends ArenaTeamList
}
// battlegroup
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
$curTpl['members'] = $members[$id];
}

View File

@@ -146,13 +146,13 @@ class GuideList extends BaseType
if ($c = $this->getField('classId'))
{
$n = Lang::game('cl', $c);
$specStr .= '&nbsp;&nbsp;&nbsp;&nbsp;<span class="icontiny c'.$c.'" style="background-image: url('.STATIC_URL.'/images/wow/icons/tiny/class_'.Game::$classFileStrings[$c].'.gif)">%s</span>';
$specStr .= '&nbsp;&nbsp;&nbsp;&nbsp;<span class="icontiny c'.$c.'" style="background-image: url('.Cfg::get('STATIC_URL').'/images/wow/icons/tiny/class_'.Game::$classFileStrings[$c].'.gif)">%s</span>';
if (($s = $this->getField('specId')) > -1)
{
$i = Game::$specIconStrings[$c][$s];
$n = '';
$specStr .= '<span class="icontiny c'.$c.'" style="background-image: url('.STATIC_URL.'/images/wow/icons/tiny/'.$i.'.gif)">'.Lang::game('classSpecs', $c, $s).'</span>';
$specStr .= '<span class="icontiny c'.$c.'" style="background-image: url('.Cfg::get('STATIC_URL').'/images/wow/icons/tiny/'.$i.'.gif)">'.Lang::game('classSpecs', $c, $s).'</span>';
}
$specStr = sprintf($specStr, $n);

View File

@@ -182,7 +182,7 @@ class RemoteGuildList extends GuildList
foreach ($this->iterate() as $guid => &$curTpl)
{
// battlegroup
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
$r = explode(':', $guid)[0];
if (!empty($realms[$r]))
@@ -213,7 +213,7 @@ class RemoteGuildList extends GuildList
$distrib[$curTpl['realm']]++;
}
$limit = CFG_SQL_LIMIT_DEFAULT;
$limit = Cfg::get('SQL_LIMIT_DEFAULT');
foreach ($conditions as $c)
if (is_int($c))
$limit = $c;
@@ -292,7 +292,7 @@ class LocalGuildList extends GuildList
}
// battlegroup
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
}
}

View File

@@ -834,7 +834,7 @@ class ItemList extends BaseType
$pop = array_pop($enhance['g']);
$col = $pop ? 1 : 0;
$hasMatch &= $pop ? (($gems[$pop]['colorMask'] & (1 << $colorId)) ? 1 : 0) : 0;
$icon = $pop ? sprintf(Util::$bgImagePath['tiny'], STATIC_URL, strtolower($gems[$pop]['iconString'])) : null;
$icon = $pop ? sprintf('style="background-image: url(%s/images/wow/icons/tiny/%s.gif)"', Cfg::get('STATIC_URL'), strtolower($gems[$pop]['iconString'])) : null;
$text = $pop ? Util::localizedString($gems[$pop], 'name') : Lang::item('socket', $colorId);
if ($interactive)
@@ -848,7 +848,7 @@ class ItemList extends BaseType
{
$pop = array_pop($enhance['g']);
$col = $pop ? 1 : 0;
$icon = $pop ? sprintf(Util::$bgImagePath['tiny'], STATIC_URL, strtolower($gems[$pop]['iconString'])) : null;
$icon = $pop ? sprintf('style="background-image: url(%s/images/wow/icons/tiny/%s.gif)"', Cfg::get('STATIC_URL'), strtolower($gems[$pop]['iconString'])) : null;
$text = $pop ? Util::localizedString($gems[$pop], 'name') : Lang::item('socket', -1);
if ($interactive)
@@ -1580,7 +1580,7 @@ class ItemList extends BaseType
array_column($randEnchants, 'enchantId5')
));
$enchants = new EnchantmentList(array(['id', $enchIds], CFG_SQL_LIMIT_NONE));
$enchants = new EnchantmentList(array(['id', $enchIds], Cfg::get('SQL_LIMIT_NONE')));
foreach ($enchants->iterate() as $eId => $_)
{
$this->rndEnchIds[$eId] = array(

View File

@@ -531,7 +531,7 @@ class RemoteProfileList extends ProfileList
$talentSpells = [];
$talentLookup = [];
$distrib = null;
$limit = CFG_SQL_LIMIT_DEFAULT;
$limit = Cfg::get('SQL_LIMIT_DEFAULT');
foreach ($conditions as $c)
if (is_int($c))
@@ -541,7 +541,7 @@ class RemoteProfileList extends ProfileList
foreach ($this->iterate() as $guid => &$curTpl)
{
// battlegroup
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
// realm
[$r, $g] = explode(':', $guid);
@@ -575,7 +575,7 @@ class RemoteProfileList extends ProfileList
$curTpl['activespec'] = $curTpl['activeTalentGroup'];
// equalize distribution
if ($limit != CFG_SQL_LIMIT_NONE)
if ($limit != Cfg::get('SQL_LIMIT_NONE'))
{
if (empty($distrib[$curTpl['realm']]))
$distrib[$curTpl['realm']] = 1;
@@ -753,7 +753,7 @@ class LocalProfileList extends ProfileList
}
// battlegroup
$curTpl['battlegroup'] = CFG_BATTLEGROUP;
$curTpl['battlegroup'] = Cfg::get('BATTLEGROUP');
}
}

View File

@@ -53,7 +53,7 @@ class SoundList extends BaseType
// enum to string
$data['type'] = self::$fileTypes[$data['type']];
// get real url
$data['url'] = STATIC_URL . '/wowsounds/' . $data['id'];
$data['url'] = Cfg::get('STATIC_URL') . '/wowsounds/' . $data['id'];
// v push v
$this->fileBuffer[$id] = $data;
}

View File

@@ -178,7 +178,7 @@ class SpellList extends BaseType
}
if ($foo)
$this->relItems = new ItemList(array(['i.id', array_unique($foo)], CFG_SQL_LIMIT_NONE));
$this->relItems = new ItemList(array(['i.id', array_unique($foo)], Cfg::get('SQL_LIMIT_NONE')));
}
// use if you JUST need the name

View File

@@ -41,7 +41,7 @@ class User
// check IP bans
if ($ipBan = DB::Aowow()->selectRow('SELECT count, unbanDate FROM ?_account_bannedips WHERE ip = ? AND type = 0', self::$ip))
{
if ($ipBan['count'] > CFG_ACC_FAILED_AUTH_COUNT && $ipBan['unbanDate'] > time())
if ($ipBan['count'] > Cfg::get('ACC_FAILED_AUTH_COUNT') && $ipBan['unbanDate'] > time())
return false;
else if ($ipBan['unbanDate'] <= time())
DB::Aowow()->query('DELETE FROM ?_account_bannedips WHERE ip = ?', self::$ip);
@@ -193,11 +193,12 @@ class User
}
// check; pick first viable if failed
if (CFG_LOCALES && !(CFG_LOCALES & (1 << $loc)))
$allowedLoc = Cfg::get('LOCALES');
if ($allowedLoc && !($allowedLoc & (1 << $loc)))
{
foreach (Util::$localeStrings as $idx => $__)
{
if (CFG_LOCALES & (1 << $idx))
if ($allowedLoc & (1 << $idx))
{
$loc = $idx;
break;
@@ -236,7 +237,7 @@ class User
$user = 0;
$hash = '';
switch (CFG_ACC_AUTH_MODE)
switch (Cfg::get('ACC_AUTH_MODE'))
{
case AUTH_MODE_SELF:
{
@@ -246,11 +247,11 @@ class User
// handle login try limitation
$ip = DB::Aowow()->selectRow('SELECT ip, count, unbanDate FROM ?_account_bannedips WHERE type = 0 AND ip = ?', self::$ip);
if (!$ip || $ip['unbanDate'] < time()) // no entry exists or time expired; set count to 1
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 0, 1, UNIX_TIMESTAMP() + ?d)', self::$ip, CFG_ACC_FAILED_AUTH_BLOCK);
DB::Aowow()->query('REPLACE INTO ?_account_bannedips (ip, type, count, unbanDate) VALUES (?, 0, 1, UNIX_TIMESTAMP() + ?d)', self::$ip, Cfg::get('ACC_FAILED_AUTH_BLOCK'));
else // entry already exists; increment count
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ?', CFG_ACC_FAILED_AUTH_BLOCK, self::$ip);
DB::Aowow()->query('UPDATE ?_account_bannedips SET count = count + 1, unbanDate = UNIX_TIMESTAMP() + ?d WHERE ip = ?', Cfg::get('ACC_FAILED_AUTH_BLOCK'), self::$ip);
if ($ip && $ip['count'] >= CFG_ACC_FAILED_AUTH_COUNT && $ip['unbanDate'] >= time())
if ($ip && $ip['count'] >= Cfg::get('ACC_FAILED_AUTH_COUNT') && $ip['unbanDate'] >= time())
return AUTH_IPBANNED;
$query = DB::Aowow()->SelectRow('
@@ -406,12 +407,12 @@ class User
// different auth modes require different usernames
$min = 0; // external case
$max = 0;
if (CFG_ACC_AUTH_MODE == AUTH_MODE_SELF)
if (Cfg::get('ACC_AUTH_MODE') == AUTH_MODE_SELF)
{
$min = 4;
$max = 16;
}
else if (CFG_ACC_AUTH_MODE == AUTH_MODE_REALM)
else if (Cfg::get('ACC_AUTH_MODE') == AUTH_MODE_REALM)
{
$min = 3;
$max = 32;
@@ -430,7 +431,7 @@ class User
$errCode = 0;
// only enforce for own passwords
if (mb_strlen($pass) < 6 && CFG_ACC_AUTH_MODE == AUTH_MODE_SELF)
if (mb_strlen($pass) < 6 && Cfg::get('ACC_AUTH_MODE') == AUTH_MODE_SELF)
$errCode = 1;
// else if (preg_match('/[^\w\d!"#\$%]/', $pass)) // such things exist..? :o
// $errCode = 2;
@@ -443,7 +444,7 @@ class User
$_SESSION['user'] = self::$id;
$_SESSION['hash'] = self::$passHash;
$_SESSION['locale'] = self::$localeId;
$_SESSION['timeout'] = self::$expires ? time() + CFG_SESSION_TIMEOUT_DELAY : 0;
$_SESSION['timeout'] = self::$expires ? time() + Cfg::get('SESSION_TIMEOUT_DELAY') : 0;
// $_SESSION['dataKey'] does not depend on user login status and is set in User::init()
}
@@ -475,7 +476,7 @@ class User
if (!self::$id || self::$banStatus & (ACC_BAN_COMMENT | ACC_BAN_PERM | ACC_BAN_TEMP))
return false;
return self::$perms || self::$reputation >= CFG_REP_REQ_COMMENT;
return self::$perms || self::$reputation >= Cfg::get('REP_REQ_COMMENT');
}
public static function canReply()
@@ -483,7 +484,7 @@ class User
if (!self::$id || self::$banStatus & (ACC_BAN_COMMENT | ACC_BAN_PERM | ACC_BAN_TEMP))
return false;
return self::$perms || self::$reputation >= CFG_REP_REQ_REPLY;
return self::$perms || self::$reputation >= Cfg::get('REP_REQ_REPLY');
}
public static function canUpvote()
@@ -491,7 +492,7 @@ class User
if (!self::$id || self::$banStatus & (ACC_BAN_COMMENT | ACC_BAN_PERM | ACC_BAN_TEMP))
return false;
return self::$perms || (self::$reputation >= CFG_REP_REQ_UPVOTE && self::$dailyVotes > 0);
return self::$perms || (self::$reputation >= Cfg::get('REP_REQ_UPVOTE') && self::$dailyVotes > 0);
}
public static function canDownvote()
@@ -499,7 +500,7 @@ class User
if (!self::$id || self::$banStatus & (ACC_BAN_RATE | ACC_BAN_PERM | ACC_BAN_TEMP))
return false;
return self::$perms || (self::$reputation >= CFG_REP_REQ_DOWNVOTE && self::$dailyVotes > 0);
return self::$perms || (self::$reputation >= Cfg::get('REP_REQ_DOWNVOTE') && self::$dailyVotes > 0);
}
public static function canSupervote()
@@ -507,7 +508,7 @@ class User
if (!self::$id || self::$banStatus & (ACC_BAN_RATE | ACC_BAN_PERM | ACC_BAN_TEMP))
return false;
return self::$reputation >= CFG_REP_REQ_SUPERVOTE;
return self::$reputation >= Cfg::get('REP_REQ_SUPERVOTE');
}
public static function canUploadScreenshot()
@@ -536,7 +537,7 @@ class User
public static function isPremium()
{
return self::isInGroup(U_GROUP_PREMIUM) || self::$reputation >= CFG_REP_REQ_PREMIUM;
return self::isInGroup(U_GROUP_PREMIUM) || self::$reputation >= Cfg::get('REP_REQ_PREMIUM');
}
/**************/
@@ -559,7 +560,7 @@ class User
if (!self::$id || self::$banStatus & (ACC_BAN_PERM | ACC_BAN_TEMP))
return 0;
return CFG_USER_MAX_VOTES + (self::$reputation >= CFG_REP_REQ_VOTEMORE_BASE ? 1 + intVal((self::$reputation - CFG_REP_REQ_VOTEMORE_BASE) / CFG_REP_REQ_VOTEMORE_ADD) : 0);
return Cfg::get('USER_MAX_VOTES') + (self::$reputation >= Cfg::get('REP_REQ_VOTEMORE_BASE') ? 1 + intVal((self::$reputation - Cfg::get('REP_REQ_VOTEMORE_BASE')) / Cfg::get('REP_REQ_VOTEMORE_ADD')) : 0);
}
public static function getReputation()
@@ -585,8 +586,8 @@ class User
$gUser['canDownvote'] = self::canDownvote();
$gUser['canPostReplies'] = self::canReply();
$gUser['superCommentVotes'] = self::canSupervote();
$gUser['downvoteRep'] = CFG_REP_REQ_DOWNVOTE;
$gUser['upvoteRep'] = CFG_REP_REQ_UPVOTE;
$gUser['downvoteRep'] = Cfg::get('REP_REQ_DOWNVOTE');
$gUser['upvoteRep'] = Cfg::get('REP_REQ_UPVOTE');
$gUser['characters'] = self::getCharacters();
$gUser['excludegroups'] = self::$excludeGroups;
$gUser['settings'] = (new StdClass); // profiler requires this to be set; has property premiumborder (NYI)

View File

@@ -132,19 +132,19 @@ trait TrRequestData
abstract class CLI
{
const CHR_BELL = 7;
const CHR_BACK = 8;
const CHR_TAB = 9;
const CHR_LF = 10;
const CHR_CR = 13;
const CHR_ESC = 27;
const CHR_BACKSPACE = 127;
private const CHR_BELL = 7;
private const CHR_BACK = 8;
private const CHR_TAB = 9;
private const CHR_LF = 10;
private const CHR_CR = 13;
private const CHR_ESC = 27;
private const CHR_BACKSPACE = 127;
const LOG_BLANK = 0;
const LOG_OK = 1;
const LOG_WARN = 2;
const LOG_ERROR = 3;
const LOG_INFO = 4;
public const LOG_BLANK = 0;
public const LOG_ERROR = 1;
public const LOG_WARN = 2;
public const LOG_INFO = 3;
public const LOG_OK = 4;
private static $logHandle = null;
private static $hasReadline = null;
@@ -216,6 +216,11 @@ abstract class CLI
}
}
public static function grey(string $str) : string
{
return CLI_HAS_E ? "\e[90m".$str."\e[0m" : $str;
}
public static function red(string $str) : string
{
return CLI_HAS_E ? "\e[31m".$str."\e[0m" : $str;
@@ -536,17 +541,6 @@ abstract class Util
null, 'bc', 'wotlk', 'cata', 'mop'
);
public static $bgImagePath = array (
'tiny' => 'style="background-image: url(%s/images/wow/icons/tiny/%s.gif)"',
'small' => 'style="background-image: url(%s/images/wow/icons/small/%s.jpg)"',
'medium' => 'style="background-image: url(%s/images/wow/icons/medium/%s.jpg)"',
'large' => 'style="background-image: url(%s/images/wow/icons/large/%s.jpg)"',
);
public static $configCats = array( // don't mind the ordering ... please?
1 => 'Site', 'Caching', 'Account', 'Session', 'Site Reputation', 'Google Analytics', 'Profiler', 0 => 'Other'
);
public static $tcEncoding = '0zMcmVokRsaqbdrfwihuGINALpTjnyxtgevElBCDFHJKOPQSUWXYZ123456789';
private static $notes = [];
@@ -737,7 +731,7 @@ abstract class Util
// html may contain 'Pictures' and FlavorImages and "stuff"
$text = preg_replace_callback(
'/src="([^"]+)"/i',
function ($m) { return 'src="'.STATIC_URL.'/images/wow/'.strtr($m[1], ['\\' => '/']).'.png"'; },
function ($m) { return sprintf('src="%s/images/wow/%s.png"', Cfg::get('STATIC_URL'), strtr($m[1], ['\\' => '/'])); },
strtr($text, $pairs)
);
}
@@ -848,8 +842,8 @@ abstract class Util
return strtr($data, array(
'<script' => '<scr"+"ipt',
'script>' => 'scr"+"ipt>',
'HOST_URL' => HOST_URL,
'STATIC_URL' => STATIC_URL
'HOST_URL' => Cfg::get('HOST_URL'),
'STATIC_URL' => Cfg::get('STATIC_URL')
));
}
@@ -955,43 +949,59 @@ abstract class Util
return mb_strtolower($str);
}
// note: valid integer > 32bit are returned as float
// doesn't handle scientific notation .. why would you input 3e3 for 3000..?
public static function checkNumeric(&$data, $typeCast = NUM_ANY)
{
if ($data === null)
return false;
else if (!is_array($data))
if (is_array($data))
{
$rawData = $data; // do not transform strings
$data = trim($data);
if (preg_match('/^-?\d*,\d+$/', $data))
$data = strtr($data, ',', '.');
if (is_numeric($data))
{
$data += 0; // becomes float or int
if ((is_float($data) && $typeCast == NUM_REQ_INT) ||
(is_int($data) && $typeCast == NUM_REQ_FLOAT))
return false;
if (is_float($data) && $typeCast == NUM_CAST_INT)
$data = intval($data);
if (is_int($data) && $typeCast == NUM_CAST_FLOAT)
$data = floatval($data);
return true;
}
$data = $rawData;
return false;
array_walk($data, function(&$x) use($typeCast) { self::checkNumeric($x, $typeCast); });
return false; // always false for passed arrays
}
array_walk($data, function(&$x) use($typeCast) { self::checkNumeric($x, $typeCast); });
// already in required state
if ((is_float($data) && $typeCast == NUM_REQ_FLOAT) ||
(is_int($data) && $typeCast == NUM_REQ_INT))
return true;
return false; // always false for passed arrays
// irreconcilable state
if ((!is_int($data) && $typeCast == NUM_REQ_INT) ||
(!is_float($data) && $typeCast == NUM_REQ_FLOAT))
return false;
$number = $data; // do not transform strings, store state
$nMatches = 0;
$number = trim($number);
$number = preg_replace('/^(-?\d*)[.,](\d+)$/', '$1.$2', $number, -1, $nMatches);
// is float string
if ($nMatches)
{
if ($typeCast == NUM_CAST_INT)
$data = intVal($number);
else if ($typeCast == NUM_CAST_FLOAT)
$data = floatVal($number);
return true;
}
// is int string (is_numeric can only handle strings in base 10)
if (is_numeric($number) || preg_match('/0[xb]?\d+/', $number))
{
$number = intVal($number, 0); // 'base 0' auto-detects base
if ($typeCast == NUM_CAST_INT)
$data = $number;
else if ($typeCast == NUM_CAST_FLOAT)
$data = floatVal($number);
return true;
}
// is string string
return false;
}
public static function arraySumByKey(array &$ref, array ...$adds) : void
@@ -1090,18 +1100,18 @@ abstract class Util
switch ($action)
{
case SITEREP_ACTION_REGISTER:
$x['amount'] = CFG_REP_REWARD_REGISTER;
$x['amount'] = Cfg::get('REP_REWARD_REGISTER');
break;
case SITEREP_ACTION_DAILYVISIT:
$x['sourceA'] = time();
$x['amount'] = CFG_REP_REWARD_DAILYVISIT;
$x['amount'] = Cfg::get('REP_REWARD_DAILYVISIT');
break;
case SITEREP_ACTION_COMMENT:
if (empty($miscData['id']))
return false;
$x['sourceA'] = $miscData['id']; // commentId
$x['amount'] = CFG_REP_REWARD_COMMENT;
$x['amount'] = Cfg::get('REP_REWARD_COMMENT');
break;
case SITEREP_ACTION_UPVOTED:
case SITEREP_ACTION_DOWNVOTED:
@@ -1118,7 +1128,7 @@ abstract class Util
$x['sourceA'] = $miscData['id']; // commentId
$x['sourceB'] = $miscData['voterId'];
$x['amount'] = $action == SITEREP_ACTION_UPVOTED ? CFG_REP_REWARD_UPVOTED : CFG_REP_REWARD_DOWNVOTED;
$x['amount'] = $action == SITEREP_ACTION_UPVOTED ? Cfg::get('REP_REWARD_UPVOTED') : Cfg::get('REP_REWARD_DOWNVOTED');
break;
case SITEREP_ACTION_UPLOAD:
if (empty($miscData['id']) || empty($miscData['what']))
@@ -1126,7 +1136,7 @@ abstract class Util
$x['sourceA'] = $miscData['id']; // screenshotId or videoId
$x['sourceB'] = $miscData['what']; // screenshot:1 or video:NYD
$x['amount'] = CFG_REP_REWARD_UPLOAD;
$x['amount'] = Cfg::get('REP_REWARD_UPLOAD');
break;
case SITEREP_ACTION_GOOD_REPORT: // NYI
case SITEREP_ACTION_BAD_REPORT:
@@ -1134,14 +1144,14 @@ abstract class Util
return false;
$x['sourceA'] = $miscData['id'];
$x['amount'] = $action == SITEREP_ACTION_GOOD_REPORT ? CFG_REP_REWARD_GOOD_REPORT : CFG_REP_REWARD_BAD_REPORT;
$x['amount'] = $action == SITEREP_ACTION_GOOD_REPORT ? Cfg::get('REP_REWARD_GOOD_REPORT') : Cfg::get('REP_REWARD_BAD_REPORT');
break;
case SITEREP_ACTION_ARTICLE:
if (empty($miscData['id'])) // guideId
return false;
$x['sourceA'] = $miscData['id'];
$x['amount'] = CFG_REP_REWARD_ARTICLE;
$x['amount'] = Cfg::get('REP_REWARD_ARTICLE');
break;
case SITEREP_ACTION_USER_WARNED: // NYI
case SITEREP_ACTION_USER_SUSPENDED:
@@ -1149,7 +1159,7 @@ abstract class Util
return false;
$x['sourceA'] = $miscData['id'];
$x['amount'] = $action == SITEREP_ACTION_USER_WARNED ? CFG_REP_REWARD_USER_WARNED : CFG_REP_REWARD_USER_SUSPENDED;
$x['amount'] = $action == SITEREP_ACTION_USER_WARNED ? Cfg::get('REP_REWARD_USER_WARNED') : Cfg::get('REP_REWARD_USER_SUSPENDED');
break;
}
@@ -1318,7 +1328,7 @@ abstract class Util
{
$flags = $forceFlags ?: (JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE);
if (CFG_DEBUG && !$forceFlags)
if (Cfg::get('DEBUG') && !$forceFlags)
$flags |= JSON_PRETTY_PRINT;
$json = json_encode($data, $flags);
@@ -1658,7 +1668,7 @@ abstract class Util
return [(int)$deg, $desc];
}
static function mask2bits($bitmask, $offset = 0)
static function mask2bits(int $bitmask, int $offset = 0) : array
{
$bits = [];
$i = 0;