User/Misc

* don't run querys if not strictly required (e.g. query for chars from ajax context)
 * prepare user globals and favorites so errors can be handled and don't destroy the template
   this also allows for profiling of the affected queries
 * add keys to items table to speed up querying for recipes in general and user completions in particular
This commit is contained in:
Sarjuuk
2025-11-05 15:28:57 +01:00
parent 9020e36db6
commit 16c5b73cd3
6 changed files with 78 additions and 55 deletions

View File

@@ -30,6 +30,8 @@ class PageTemplate
private string $gStaticUrl; private string $gStaticUrl;
private string $gHost; private string $gHost;
private string $gServerTime; private string $gServerTime;
private string $gUser;
private string $gFavorites;
private ?string $analyticsTag = null; private ?string $analyticsTag = null;
private bool $consentFooter = false; private bool $consentFooter = false;
private string $dbProfiles = ''; private string $dbProfiles = '';
@@ -484,6 +486,9 @@ class PageTemplate
// js + css // js + css
$this->prepareScripts(); $this->prepareScripts();
$this->gUser = Util::toJSON(User::getUserGlobal());
$this->gFavorites = Util::toJSON(User::getFavorites());
// db profiling // db profiling
if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN)) if (Cfg::get('DEBUG') >= LOG_LEVEL_INFO && User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
$this->dbProfiles = \Aowow\DB::getProfiles(); $this->dbProfiles = \Aowow\DB::getProfiles();

View File

@@ -29,7 +29,28 @@ class User
public static function init() public static function init()
{ {
self::setIP(); # set ip #
$ipAddr = '';
foreach (['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'] as $env)
{
if ($rawIp = getenv($env))
{
if ($env == 'HTTP_X_FORWARDED')
$rawIp = explode(',', $rawIp)[0]; // [ip, proxy1, proxy2]
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
break;
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
break;
}
}
self::$ip = $ipAddr ?: null;
# set locale #
if (isset($_SESSION['locale']) && $_SESSION['locale'] instanceof Locale) if (isset($_SESSION['locale']) && $_SESSION['locale'] instanceof Locale)
self::$preferedLoc = $_SESSION['locale']->validate() ?? Locale::getFallback(); self::$preferedLoc = $_SESSION['locale']->validate() ?? Locale::getFallback();
@@ -38,8 +59,10 @@ class User
else else
self::$preferedLoc = Locale::getFallback(); self::$preferedLoc = Locale::getFallback();
// session have a dataKey to access the JScripts (yes, also the anons)
if (empty($_SESSION['dataKey'])) # set basic data #
if (empty($_SESSION['dataKey'])) // session have a dataKey to access the JScripts (yes, also the anons)
$_SESSION['dataKey'] = Util::createHash(); // just some random numbers for identification purpose $_SESSION['dataKey'] = Util::createHash(); // just some random numbers for identification purpose
self::$dataKey = $_SESSION['dataKey']; self::$dataKey = $_SESSION['dataKey'];
@@ -48,7 +71,9 @@ class User
if (!self::$ip) if (!self::$ip)
return false; return false;
// check IP bans
# check IP bans #
if ($ipBan = DB::Aowow()->selectRow('SELECT `count`, IF(`unbanDate` > UNIX_TIMESTAMP(), 1, 0) AS "active" FROM ?_account_bannedips WHERE `ip` = ? AND `type` = ?d', self::$ip, IP_BAN_TYPE_LOGIN_ATTEMPT)) if ($ipBan = DB::Aowow()->selectRow('SELECT `count`, IF(`unbanDate` > UNIX_TIMESTAMP(), 1, 0) AS "active" FROM ?_account_bannedips WHERE `ip` = ? AND `type` = ?d', self::$ip, IP_BAN_TYPE_LOGIN_ATTEMPT))
{ {
if ($ipBan['count'] > Cfg::get('ACC_FAILED_AUTH_COUNT') && $ipBan['active']) if ($ipBan['count'] > Cfg::get('ACC_FAILED_AUTH_COUNT') && $ipBan['active'])
@@ -57,7 +82,9 @@ class User
DB::Aowow()->query('DELETE FROM ?_account_bannedips WHERE `ip` = ?', self::$ip); DB::Aowow()->query('DELETE FROM ?_account_bannedips WHERE `ip` = ?', self::$ip);
} }
// try to restore session
# try to restore session #
if (empty($_SESSION['user'])) if (empty($_SESSION['user']))
return false; return false;
@@ -122,16 +149,9 @@ class User
self::$email = $userData['email']; self::$email = $userData['email'];
self::$avatarborder = $userData['avatarborder']; self::$avatarborder = $userData['avatarborder'];
if (Cfg::get('PROFILER_ENABLE'))
{
$conditions = [['OR', ['user', self::$id], ['ap.accountId', self::$id]]];
if (!self::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
$conditions[] = [['cuFlags', PROFILER_CU_DELETED, '&'], 0];
self::$profiles = (new LocalProfileList($conditions)); # reset premium options #
}
// reset premium options
if (!self::isPremium()) if (!self::isPremium())
{ {
if ($userData['avatar'] == 2) if ($userData['avatar'] == 2)
@@ -144,17 +164,16 @@ class User
// do not reset, it's just not sent to the browser // do not reset, it's just not sent to the browser
} }
// stuff, that updates on a daily basis goes here (if you keep you session alive indefinitly, the signin-handler doesn't do very much)
// - consecutive visits # update daily limits #
// - votes per day
// - reputation for daily visit
if (!self::isBanned()) if (!self::isBanned())
{ {
$lastLogin = DB::Aowow()->selectCell('SELECT `curLogin` FROM ?_account WHERE `id` = ?d', self::$id); $lastLogin = DB::Aowow()->selectCell('SELECT `curLogin` FROM ?_account WHERE `id` = ?d', self::$id);
// either the day changed or the last visit was >24h ago // either the day changed or the last visit was >24h ago
if (date('j', $lastLogin) != date('j') || (time() - $lastLogin) > 1 * DAY) if (date('j', $lastLogin) != date('j') || (time() - $lastLogin) > 1 * DAY)
{ {
// daily votes (we need to reset this one) // - daily votes (we need to reset this one)
self::$dailyVotes = self::getMaxDailyVotes(); self::$dailyVotes = self::getMaxDailyVotes();
DB::Aowow()->query( DB::Aowow()->query(
@@ -166,12 +185,11 @@ class User
self::$id self::$id
); );
// gain rep for daily visit // - gain reputation for daily visit
if (!(self::isBanned()) && !self::isInGroup(U_GROUP_PENDING)) if (!(self::isBanned()) && !self::isInGroup(U_GROUP_PENDING))
Util::gainSiteReputation(self::$id, SITEREP_ACTION_DAILYVISIT); Util::gainSiteReputation(self::$id, SITEREP_ACTION_DAILYVISIT);
// increment consecutive visits (next day or first of new month and not more than 48h) // - increment consecutive visits (next day or first of new month and not more than 48h)
// i bet my ass i forgot a corner case
if ((date('j', $lastLogin) + 1 == date('j') || (date('j') == 1 && date('n', $lastLogin) != date('n'))) && (time() - $lastLogin) < 2 * DAY) if ((date('j', $lastLogin) + 1 == date('j') || (date('j') == 1 && date('n', $lastLogin) != date('n'))) && (time() - $lastLogin) < 2 * DAY)
DB::Aowow()->query('UPDATE ?_account SET `consecutiveVisits` = `consecutiveVisits` + 1 WHERE `id` = ?d', self::$id); DB::Aowow()->query('UPDATE ?_account SET `consecutiveVisits` = `consecutiveVisits` + 1 WHERE `id` = ?d', self::$id);
else else
@@ -182,31 +200,6 @@ class User
return true; return true;
} }
private static function setIP() : void
{
$ipAddr = '';
$method = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'];
foreach ($method as $m)
{
if ($rawIp = getenv($m))
{
if ($m == 'HTTP_X_FORWARDED')
$rawIp = explode(',', $rawIp)[0]; // [ip, proxy1, proxy2]
// check IPv4
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
break;
// check IPv6
if ($ipAddr = filter_var($rawIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
break;
}
}
self::$ip = $ipAddr ?: null;
}
public static function save(bool $toDB = false) public static function save(bool $toDB = false)
{ {
$_SESSION['user'] = self::$id; $_SESSION['user'] = self::$id;
@@ -640,7 +633,7 @@ class User
public static function getCharacters() : array public static function getCharacters() : array
{ {
if (!self::$profiles) if (!self::loadProfiles())
return []; return [];
return self::$profiles->getJSGlobals(PROFILEINFO_CHARACTER); return self::$profiles->getJSGlobals(PROFILEINFO_CHARACTER);
@@ -648,7 +641,7 @@ class User
public static function getProfiles() : array public static function getProfiles() : array
{ {
if (!self::$profiles) if (!self::loadProfiles())
return []; return [];
return self::$profiles->getJSGlobals(PROFILEINFO_PROFILE); return self::$profiles->getJSGlobals(PROFILEINFO_PROFILE);
@@ -656,7 +649,7 @@ class User
public static function getPinnedCharacter() : array public static function getPinnedCharacter() : array
{ {
if (!self::$profiles) if (!self::loadProfiles())
return []; return [];
$realms = Profiler::getRealms(); $realms = Profiler::getRealms();
@@ -727,6 +720,9 @@ class User
public static function getCompletion() : array public static function getCompletion() : array
{ {
if (!self::loadProfiles())
return [];
$ids = []; $ids = [];
foreach (self::$profiles->iterate() as $_) foreach (self::$profiles->iterate() as $_)
if (!self::$profiles->isCustom()) if (!self::$profiles->isCustom())
@@ -752,7 +748,7 @@ class User
'SELECT pcs.`id` AS ARRAY_KEY, pcs.`spellId` AS ARRAY_KEY2, pcs.`spellId`, i.`id` AS "itemId" 'SELECT pcs.`id` AS ARRAY_KEY, pcs.`spellId` AS ARRAY_KEY2, pcs.`spellId`, i.`id` AS "itemId"
FROM ?_spell s FROM ?_spell s
JOIN ?_profiler_completion_spells pcs ON s.`id` = pcs.`spellId` JOIN ?_profiler_completion_spells pcs ON s.`id` = pcs.`spellId`
LEFT JOIN ?_items i ON i.spellId1 IN (?a) AND i.spellId2 = pcs.spellId LEFT JOIN ?_items i ON i.`spellId1` IN (?a) AND i.`spellId2` = pcs.`spellId`
WHERE s.`typeCat` IN (?a) AND pcs.`id` IN (?a)', WHERE s.`typeCat` IN (?a) AND pcs.`id` IN (?a)',
LEARN_SPELLS, [-5, -6, 9, 11], $ids LEARN_SPELLS, [-5, -6, 9, 11], $ids
); );
@@ -776,6 +772,23 @@ class User
return $completion; return $completion;
} }
private static function loadProfiles() : bool
{
if (!Cfg::get('PROFILER_ENABLE'))
return false;
if (self::$profiles === null)
{
$conditions = [['OR', ['user', self::$id], ['ap.accountId', self::$id]]];
if (!self::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU))
$conditions[] = [['cuFlags', PROFILER_CU_DELETED, '&'], 0];
self::$profiles = (new LocalProfileList($conditions));
}
return !!self::$profiles->getFoundIDs();
}
} }
?> ?>

View File

@@ -1441,7 +1441,9 @@ CREATE TABLE `aowow_items` (
KEY `items_index` (`class`), KEY `items_index` (`class`),
KEY `idx_model` (`displayId`), KEY `idx_model` (`displayId`),
KEY `idx_faction` (`requiredFaction`), KEY `idx_faction` (`requiredFaction`),
KEY `iconId` (`iconId`) KEY `iconId` (`iconId`),
KEY `spellId1` (`spellId1`),
KEY `spellId2` (`spellId2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;

View File

@@ -71,7 +71,7 @@ UNLOCK TABLES;
LOCK TABLES `aowow_dbversion` WRITE; LOCK TABLES `aowow_dbversion` WRITE;
/*!40000 ALTER TABLE `aowow_dbversion` DISABLE KEYS */; /*!40000 ALTER TABLE `aowow_dbversion` DISABLE KEYS */;
INSERT INTO `aowow_dbversion` VALUES (1758578400,17,NULL,NULL); INSERT INTO `aowow_dbversion` VALUES (1762352734,0,NULL,NULL);
/*!40000 ALTER TABLE `aowow_dbversion` ENABLE KEYS */; /*!40000 ALTER TABLE `aowow_dbversion` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;

View File

@@ -0,0 +1,3 @@
ALTER TABLE `aowow_items`
ADD KEY spellId1 (`spellId1`),
ADD KEY spellId2 (`spellId2`);

View File

@@ -22,10 +22,10 @@ endif;
</script> </script>
<?=$this->renderArray('js', 4); ?> <?=$this->renderArray('js', 4); ?>
<script type="text/javascript"> <script type="text/javascript">
var g_user = <?=$this->json($this->user::getUserGlobal()); ?>; var g_user = <?=$this->gUser; ?>;
<?php <?php
if ($fav = $this->user::getFavorites()): if ($this->gFavorites):
echo " g_favorites = ".$this->json($fav).";\n"; echo " g_favorites = ".$this->gFavorites.";\n";
endif; endif;
?> ?>
</script> </script>