From f99ab72d25e94948af9e1ae2dc5499a869130763 Mon Sep 17 00:00:00 2001 From: Catalin Novgorodschi <1140613+Shadowss@users.noreply.github.com> Date: Wed, 13 May 2026 15:09:05 +0300 Subject: [PATCH] Incremental Refactor Form/BBCode/Mailer/Village Incremental Refactor Form/BBCode/Mailer/Village --- GameEngine/BBCode.php | 400 +++++++++++++++++---------------------- GameEngine/Chat.php | 6 +- GameEngine/Form.php | 6 +- GameEngine/Mailer.php | 143 +++++++------- GameEngine/Village.php | 386 +++++++++++++++++++------------------ GameEngine/functions.php | 114 ++++++++--- 6 files changed, 555 insertions(+), 500 deletions(-) diff --git a/GameEngine/BBCode.php b/GameEngine/BBCode.php index 822ffe17..8a5a6094 100755 --- a/GameEngine/BBCode.php +++ b/GameEngine/BBCode.php @@ -1,255 +1,205 @@ -$1"; -$replace[1] = "$1"; -$replace[2] = "$1"; -$replace[3] = "".U1.""; -$replace[4] = "".U2.""; -$replace[5] = "".U3.""; -$replace[6] = "".U4.""; -$replace[7] = "".U5.""; -$replace[8] = "".U6.""; -$replace[9] = "".U7.""; -$replace[10] = "".U8.""; -$replace[11] = "".U9.""; -$replace[12] = "".U10.""; -$replace[13] = "".U11.""; -$replace[14] = "".U12.""; -$replace[15] = "".U13.""; -$replace[16] = "".U14.""; -$replace[17] = "".U15.""; -$replace[18] = "".U16.""; -$replace[19] = "".U17.""; -$replace[20] = "".U18.""; -$replace[21] = "".U19.""; -$replace[22] = "".U20.""; -$replace[23] = "".U21.""; -$replace[24] = "".U22.""; -$replace[25] = "".U23.""; -$replace[26] = "".U24.""; -$replace[27] = "".U25.""; -$replace[28] = "".U26.""; -$replace[29] = "".U27.""; -$replace[30] = "".U28.""; -$replace[31] = "".U29.""; -$replace[32] = "".U30.""; -$replace[33] = "".U31.""; -$replace[34] = "".U32.""; -$replace[35] = "".U33.""; -$replace[36] = "".U34.""; -$replace[37] = "".U35.""; -$replace[38] = "".U36.""; -$replace[39] = "".U37.""; -$replace[40] = "".U38.""; -$replace[41] = "".U39.""; -$replace[42] = "".U40.""; -$replace[43] = "".U41.""; -$replace[44] = "".U42.""; -$replace[45] = "".U43.""; -$replace[46] = "".U44.""; -$replace[47] = "".U45.""; -$replace[48] = "".U46.""; -$replace[49] = "".U47.""; -$replace[50] = "".U48.""; -$replace[51] = "".U49.""; -$replace[52] = "".U50.""; -$replace[53] = "".U0.""; -$replace[54] = "".LUMBER.""; -$replace[55] = "".CLAY.""; -$replace[56] = "".IRON.""; -$replace[57] = "".CROP.""; -$replace[54] = "".LUMBER.""; -$replace[55] = "".CLAY.""; -$replace[56] = "".IRON.""; -$replace[57] = "".CROP.""; -$replace[58] = "*aha*"; -$replace[59] = "*angry*"; -$replace[60] = "*cool*"; -$replace[61] = "*cry*"; -$replace[62] = "*cute*"; -$replace[63] = "*depressed*"; -$replace[64] = "*eek*"; -$replace[65] = "*ehem*"; -$replace[66] = "*emotional*"; -$replace[67] = ":D"; -$replace[68] = ":)"; -$replace[69] = "*hit*"; -$replace[70] = "*hmm*"; -$replace[71] = "*hmpf*"; -$replace[72] = "*hrhr*"; -$replace[73] = "*huh*"; -$replace[74] = "*lazy*"; -$replace[75] = "*love*"; -$replace[76] = "*nocomment*"; -$replace[77] = "*noemotion*"; -$replace[78] = "*notamused*"; -$replace[79] = "*pout*"; -$replace[80] = "*redface*"; -$replace[81] = "*rolleyes*"; -$replace[82] = ":("; -$replace[83] = "*shy*"; -$replace[84] = "*smile*"; -$replace[85] = "*tongue*"; -$replace[86] = "*veryangry*"; -$replace[87] = "*veryhappy*"; -$replace[88] = ";)"; -// replace alliance placeholders -$input = preg_replace_callback( +/* Basic BBCode */ +$pattern[] = "/\[b\](.*?)\[\/b\]/is"; +$replace[] = "$1"; + +$pattern[] = "/\[i\](.*?)\[\/i\]/is"; +$replace[] = "$1"; + +$pattern[] = "/\[u\](.*?)\[\/u\]/is"; +$replace[] = "$1"; + +/* Unit placeholders tid1 - tid50 */ +for ($i = 1; $i <= 50; $i++) { + $pattern[] = "/\[tid{$i}\]/"; + $replace[] = "" . constant("U{$i}") . ""; +} + +/* Hero */ +$pattern[] = "/\[hero\]/"; +$replace[] = "" . U0 . ""; + +/* Resources */ +$resourceMap = [ + 'lumber' => [1, LUMBER], + 'clay' => [2, CLAY], + 'iron' => [3, IRON], + 'crop' => [4, CROP], +]; + +foreach ($resourceMap as $tag => $data) { + [$id, $name] = $data; + + $pattern[] = "/\[" . $tag . "\]/"; + $replace[] = "{$name}"; +} + +/* Smilies & emoticons */ +$smilies = [ + "/\*aha\*/" => "*aha*", + "/\*angry\*/" => "*angry*", + "/\*cool\*/" => "*cool*", + "/\*cry\*/" => "*cry*", + "/\*cute\*/" => "*cute*", + "/\*depressed\*/" => "*depressed*", + "/\*eek\*/" => "*eek*", + "/\*ehem\*/" => "*ehem*", + "/\*emotional\*/" => "*emotional*", + "/:D/" => ":D", + "/:\)/" => ":)", + "/\*hit\*/" => "*hit*", + "/\*hmm\*/" => "*hmm*", + "/\*hmpf\*/" => "*hmpf*", + "/\*hrhr\*/" => "*hrhr*", + "/\*huh\*/" => "*huh*", + "/\*lazy\*/" => "*lazy*", + "/\*love\*/" => "*love*", + "/\*nocomment\*/" => "*nocomment*", + "/\*noemotion\*/" => "*noemotion*", + "/\*notamused\*/" => "*notamused*", + "/\*pout\*/" => "*pout*", + "/\*redface\*/" => "*redface*", + "/\*rolleyes\*/" => "*rolleyes*", + "/:\(/" => ":(", + "/\*shy\*/" => "*shy*", + "/\*smile\*/" => "*smile*", + "/\*tongue\*/" => "*tongue*", + "/\*veryangry\*/" => "*veryangry*", + "/\*veryhappy\*/" => "*veryhappy*", + "/;\)/" => ";)", +]; + +foreach ($smilies as $k => $v) { + $pattern[] = $k; + $replace[] = $v; +} + +/* Message cleanup */ +$input = preg_replace('/\[message\]/', '', $input); +$input = preg_replace('/\[\/message\]/', '', $input); + +/* Apply BBCode/static replacements */ +$bbcoded = preg_replace($pattern, $replace, $input); + +/** + * ------------------------------------------------------------------------- + * CALLBACK REPLACEMENTS (dynamic database-driven content) + * ------------------------------------------------------------------------- + */ + +/* Alliance */ +$bbcoded = preg_replace_callback( "/\[alliance(\d{0,20})\]([^\]]*)\[\/alliance\d{0,20}\]/is", - function($matches) { + function ($matches) { global $database; $aname = $database->getAllianceName($matches[2]); - if (!empty($aname)) return "".$aname.""; - else return "Alliance not found!"; + if (!empty($aname)) { + return "{$aname}"; + } + return "Alliance not found!"; }, - $input); + $bbcoded +); -// replace player placeholders -$input = preg_replace_callback( +/* Player */ +$bbcoded = preg_replace_callback( "/\[player(\d{0,20})\]([^\]]*)\[\/player\d{0,20}\]/is", - function($matches) { + function ($matches) { global $database; - - $uname = $database->getUserField((int) $matches[2], "username", 0); - if (!empty($uname) && $uname != "[?]") return "".$uname.""; - else return "Player not found!"; - }, - $input); -// replace report placeholders -$input = preg_replace_callback( + $uname = $database->getUserField((int)$matches[2], "username", 0); + if (!empty($uname) && $uname !== "[?]") { + return "{$uname}"; + } + return "Player not found!"; + }, + $bbcoded +); + +/* Report */ +$bbcoded = preg_replace_callback( "/\[report(\d{0,20})\]([^\]]*)\[\/report\d{0,20}\]/is", - function($matches) { + function ($matches) { global $database; - + $reportID = $matches[1] > 0 ? $matches[1] : $matches[2]; - $report = $database->getNotice2((int) $reportID, null, false); + $report = $database->getNotice2((int)$reportID, null, false); - if (!empty($report)) return "".$report['topic'].""; - else return "Report not found!"; + if (!empty($report)) { + return "{$report['topic']}"; + } + return "Report not found!"; }, - $input); + $bbcoded +); -// replace coordinate placeholders -$input = preg_replace_callback( +/* Coordinates */ +$bbcoded = preg_replace_callback( "/\[coor(\d{0,20})\]([^\]]*)\[\/coor\d{0,20}\]/is", - function($matches) { + function ($matches) { global $generator, $database; - - $name = ""; + $coordinates = explode("|", $matches[2]); $wRef = $database->getVilWref($coordinates[0], $coordinates[1]); $cwref = $generator->getMapCheck($wRef); + $state = $database->getVillageType($wRef); - if($state > 0){ - if($database->getVillageState($wRef)) $name = $database->getVillageField($wRef, 'name'); - else $name = ABANDVALLEY; + + if ($state > 0) { + $name = $database->getVillageState($wRef) + ? $database->getVillageField($wRef, 'name') + : ABANDVALLEY; + } else { + $name = $database->getOasisInfo($wRef)['name'] ?? ''; } - else $name = $database->getOasisInfo($wRef)['name']; - - if(!empty($name)) return "".$name." (".$coordinates[0]."|".$coordinates[1].")".""; + + if (!empty($name)) { + return "{$name} ({$coordinates[0]}|{$coordinates[1]})"; + } + return "Village not found!"; }, - $input); + $bbcoded +); -$input = preg_replace('/\[message\]/', '', $input); -$input = preg_replace('/\[\/message\]/', '', $input); -$bbcoded = preg_replace($pattern, $replace, $input); -?> +/* Final cleanup safety */ +$bbcoded = preg_replace('/\[message\]/', '', $bbcoded); +$bbcoded = preg_replace('/\[\/message\]/', '', $bbcoded); + +?> \ No newline at end of file diff --git a/GameEngine/Chat.php b/GameEngine/Chat.php index b71624c5..e82c80b2 100755 --- a/GameEngine/Chat.php +++ b/GameEngine/Chat.php @@ -1,11 +1,15 @@ fallback safe value added + */ + function sendInvite($email, $uid, $text) + { + $subject = SERVER_NAME . " registration"; - $subject = "".SERVER_NAME." registeration"; + // FIX: prevent undefined variable notice + $username = "User"; - $message = "Hello ".$username." + $message = + "Hello " . $username . "\n\n" . + "Try the new " . SERVER_NAME . "!\n\n\n" . + "Link: " . SERVER . "anmelden.php?id=ref" . $uid . "\n\n" . + $text . "\n\n\n" . + "Greetings,\n" . + "Travian"; -Try the new ".SERVER_NAME."! + $headers = "From: " . ADMIN_EMAIL . "\r\n"; - -Link: ".SERVER."anmelden.php?id=ref".$uid." - -".$text." - - -Greetings, -Travian"; - - $headers = "From: ".ADMIN_EMAIL."\n"; - - mail($email, $subject, $message, $headers); + @mail($email, $subject, $message, $headers); } - function sendPassword($email,$uid,$username,$npw,$cpw) { - + /** + * ------------------------------------------------------------------------- + * SEND PASSWORD RESET EMAIL + * ------------------------------------------------------------------------- + */ + function sendPassword($email, $uid, $username, $npw, $cpw) + { $subject = "Password forgotten"; - $message = "Hello ".$username." + $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost'; -You have requested a new password for Travian. + $message = + "Hello " . $username . "\n\n" . + "You have requested a new password for Travian.\n\n" . + "----------------------------\n" . + "Name: " . $username . "\n" . + "Password: " . $npw . "\n" . + "----------------------------\n\n" . + "Please click this link to activate your new password. The old password then becomes invalid:\n\n" . + "http://" . $host . "/password.php?cpw=" . $cpw . "&npw=" . $uid . "\n\n" . + "If you want to change your new password, you can enter a new one in your profile\n" . + "on tab \"account\".\n\n" . + "In case you did not request a new password you may ignore this email.\n\n" . + "Travian"; ----------------------------- -Name: ".$username." -Password: ".$npw." ----------------------------- + $headers = "From: " . ADMIN_EMAIL . "\r\n"; -Please click this link to activate your new password. The old password then -becomes invalid: - -http://${_SERVER['HTTP_HOST']}/password.php?cpw=$cpw&npw=$uid - -If you want to change your new password, you can enter a new one in your profile -on tab \"account\". - -In case you did not request a new password you may ignore this email. - -Travian -"; - - $headers = "From: ".ADMIN_EMAIL."\n"; - - mail($email, $subject, $message, $headers); + @mail($email, $subject, $message, $headers); } +} + +/** + * ------------------------------------------------------------------------- + * GLOBAL INSTANCE (legacy compatibility) + * ------------------------------------------------------------------------- + */ +$mailer = new Mailer(); -}; -$mailer = new Mailer; ?> \ No newline at end of file diff --git a/GameEngine/Village.php b/GameEngine/Village.php index be4b6059..6e4f132d 100755 --- a/GameEngine/Village.php +++ b/GameEngine/Village.php @@ -3,9 +3,15 @@ ################################################################################# ## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ## ## --------------------------------------------------------------------------- ## +## Project: TravianZ ## +## Version: 13.05.2026 ## ## Filename Village.php ## +## Developed by: Dzoki ## +## Refactor by: Shadow ## ## License: TravianZ Project ## -## Copyright: TravianZ (c) 2010-2025. All rights reserved. ## +## Copyright: TravianZ (c) 2010-2026. All rights reserved. ## +## URLs: https://travianz.org ## +## https://github.com/Shadowss/TravianZ ## ## ## ################################################################################# @@ -23,41 +29,55 @@ class Village { public $wid, $vname, $capital, $natar, $master; public $resarray = []; public $unitarray, $techarray, $unitall, $researching, $abarray = []; + private $infoarray = []; private $production = []; private $oasisowned, $ocounter = []; - function __construct() { - global $session, $database; - - if(isset($_SESSION['wid'])) $this->wid = $_SESSION['wid']; - else $this->wid = $session->villages[0]; + // single-load guards + private static $loadedWid = null; + private static $cacheCleared = false; - $this->preloadVillagesData(); + function __construct() { + global $session, $database; - //add new line code - //check exist village if from village destroy to avoid error msg. - if(!$database->checkVilExist($this->wid)){ - $this->wid=$database->getVillageID($session->uid); - $_SESSION['wid'] = $this->wid; - } + // set village id + if (isset($_SESSION['wid'])) $this->wid = $_SESSION['wid']; + else $this->wid = $session->villages[0]; + + // preload caches (safe warmup) + $this->preloadVillagesData(); + + // validate existence + if (!$database->checkVilExist($this->wid)) { + $this->wid = $database->getVillageID($session->uid); + $_SESSION['wid'] = $this->wid; + } + + // prevent double init in same request + if (self::$loadedWid === $this->wid) { + return; + } + self::$loadedWid = $this->wid; + + $this->LoadTown(); + + $database->cacheResourceLevels($this->wid); - $this->LoadTown(); - $database->cacheResourceLevels($this->wid); $this->calculateProduction(); $this->processProduction(); $this->ActionControl(); } + /** + * preload user + world cache + */ private function preloadVillagesData() { - global $database, $session; + global $database, $session; - // preload villages for this user account - $database->getProfileVillages($session->uid, 5); - - // preload villages world data records - $database->cacheVillageByWorldIDs($session->uid); - } + $database->getProfileVillages($session->uid, 5); + $database->cacheVillageByWorldIDs($session->uid); + } public function getProd($type) { return $this->production[$type]; @@ -65,29 +85,46 @@ class Village { public function getAllUnits($vid) { global $database, $technology; - return $technology->getUnits($database->getUnit($vid),$database->getEnforceVillage($vid,0)); + + return $technology->getUnits( + $database->getUnit($vid), + $database->getEnforceVillage($vid, 0) + ); } + /** + * LOAD VILLAGE DATA (single source of truth) + */ private function LoadTown($second_run = false) { global $database, $session, $logging, $technology; - + + // prevent duplicate reload in same request + if (self::$loadedWid === $this->wid && !$second_run && !empty($this->infoarray)) { + return; + } + $this->infoarray = $database->getVillage($this->wid); - if($this->infoarray['owner'] != $session->uid && !$session->isAdmin) { + + if ($this->infoarray['owner'] != $session->uid && !$session->isAdmin) { unset($_SESSION['wid']); - $logging->addIllegal($session->uid,$this->wid,1); + $logging->addIllegal($session->uid, $this->wid, 1); + $this->wid = $session->villages[0]; $this->infoarray = $database->getVillage($this->wid); } + $this->resarray = $database->getResourceLevel($this->wid); $this->coor = $database->getCoor($this->wid); $this->type = $database->getVillageType($this->wid); $this->oasisowned = $database->getOasis($this->wid); $this->ocounter = $this->sortOasis(); + $this->unitarray = $database->getUnit($this->wid); - $this->enforcetome = $database->getEnforceVillage($this->wid,0); - $this->enforcetoyou = $database->getEnforceVillage($this->wid,1); - $this->enforceoasis = $database->getOasisEnforce($this->wid,0); - $this->unitall = $technology->getAllUnits($this->wid); + $this->enforcetome = $database->getEnforceVillage($this->wid, 0); + $this->enforcetoyou = $database->getEnforceVillage($this->wid, 1); + $this->enforceoasis = $database->getOasisEnforce($this->wid, 0); + + $this->unitall = $technology->getAllUnits($this->wid); $this->techarray = $database->getTech($this->wid); $this->abarray = $database->getABTech($this->wid); $this->researching = $database->getResearching($this->wid, !$second_run); @@ -97,199 +134,194 @@ class Village { $this->currentcel = $this->infoarray['celebration']; $this->wid = $this->infoarray['wref']; $this->vname = $this->infoarray['name']; + $this->awood = $this->infoarray['wood']; $this->aclay = $this->infoarray['clay']; $this->airon = $this->infoarray['iron']; $this->acrop = $this->infoarray['crop']; + $this->atotal = (int)($this->awood + $this->aclay + $this->airon + $this->acrop); + $this->pop = $this->infoarray['pop']; $this->maxstore = $this->infoarray['maxstore']; $this->maxcrop = $this->infoarray['maxcrop']; + $this->allcrop = $this->getCropProd(); $this->loyalty = $this->infoarray['loyalty']; + $this->master = count($database->getMasterJobs($this->wid)); - - //If resources overflow the warehouse/granary limit, set them at the maximum value - $resourceUpdates = []; - if($this->awood > $this->maxstore) - { - $this->awood = $this->maxstore; - $resourceUpdates['wood'] = $this->maxstore; - } - - if($this->aclay > $this->maxstore) - { - $this->aclay = $this->maxstore; - $resourceUpdates['clay'] = $this->maxstore; - } - - if($this->airon > $this->maxstore) - { - $this->airon = $this->maxstore; - $resourceUpdates['iron'] = $this->maxstore; - } - - if($this->acrop > $this->maxcrop) - { - $this->acrop = $this->maxcrop; - $resourceUpdates['crop'] = $this->maxcrop; - } - if (count($resourceUpdates)) { - $database->updateResource($this->wid, array_keys($resourceUpdates), array_values($resourceUpdates)); + // overflow fix + $updates = []; - // reload cache if we've updated resources and the like - if ($second_run) { - // update DB cache - call_user_func(get_class($database).'::clearVillageCache'); - $this->preloadVillagesData(); - } - } - else if ($second_run) $this->preloadVillagesData(); + if ($this->awood > $this->maxstore) { $this->awood = $this->maxstore; $updates['wood'] = $this->maxstore; } + if ($this->aclay > $this->maxstore) { $this->aclay = $this->maxstore; $updates['clay'] = $this->maxstore; } + if ($this->airon > $this->maxstore) { $this->airon = $this->maxstore; $updates['iron'] = $this->maxstore; } + if ($this->acrop > $this->maxcrop) { $this->acrop = $this->maxcrop; $updates['crop'] = $this->maxcrop; } + + if (count($updates)) { + $database->updateResource($this->wid, array_keys($updates), array_values($updates)); + } } + /** + * PRODUCTION CALC + */ private function calculateProduction() { - global $technology, $database, $session; + global $technology, $database; + + if (!self::$cacheCleared) { + $db = get_class($database); + $db::clearVillageCache(); + self::$cacheCleared = true; + } - // clear cache, since we're updating village data - call_user_func(get_class($database).'::clearVillageCache'); $upkeep = $technology->getUpkeep($this->unitall, 0, $this->wid); + $this->production['wood'] = $this->getWoodProd(); $this->production['clay'] = $this->getClayProd(); $this->production['iron'] = $this->getIronProd(); - $this->production['crop'] = $this->getCropProd() - (!$this->natar ? $this->pop : round($this->pop / 2)) - $upkeep; + + $this->production['crop'] = + $this->getCropProd() + - (!$this->natar ? $this->pop : round($this->pop / 2)) + - $upkeep; } + /** + * APPLY PRODUCTION (NO MORE LOADTOWN RELOAD) + */ private function processProduction() { global $database; - + $timepast = time() - $this->infoarray['lastupdate']; + $nwood = min(($this->production['wood'] / 3600) * $timepast, $this->maxstore); $nclay = min(($this->production['clay'] / 3600) * $timepast, $this->maxstore); $niron = min(($this->production['iron'] / 3600) * $timepast, $this->maxstore); $ncrop = min(($this->production['crop'] / 3600) * $timepast, $this->maxcrop); - call_user_func(get_class($database).'::clearVillageCache'); + + if (!self::$cacheCleared) { + $db = get_class($database); + $db::clearVillageCache(); + self::$cacheCleared = true; + } $database->modifyResource($this->wid, $nwood, $nclay, $niron, $ncrop, 1); $database->updateVillage($this->wid); - $this->LoadTown(true); + + // lightweight sync ONLY (no DB reload) + $this->infoarray['lastupdate'] = time(); + + $this->awood = min($this->awood + $nwood, $this->maxstore); + $this->aclay = min($this->aclay + $nclay, $this->maxstore); + $this->airon = min($this->airon + $niron, $this->maxstore); + $this->acrop = min($this->acrop + $ncrop, $this->maxcrop); } - + private function getWoodProd() { + global $bid1, $bid5, $session; - $wood = $sawmill = 0; - $woodholder = []; - for($i = 1; $i <= 38; $i++) { - if($this->resarray['f'.$i.'t'] == 1) array_push($woodholder,'f'.$i); - if($this->resarray['f'.$i.'t'] == 5) $sawmill = $this->resarray['f'.$i]; + $holder = []; + for ($i = 1; $i <= 38; $i++) { + if ($this->resarray['f'.$i.'t'] == 1) $holder[] = 'f'.$i; + if ($this->resarray['f'.$i.'t'] == 5) $sawmill = $this->resarray['f'.$i]; } - - for($i = 0; $i <= count($woodholder) - 1; $i++) $wood += $bid1[$this->resarray[$woodholder[$i]]]['prod']; - $wood = $wood + $wood * 0.25 * $this->ocounter[0]; - - if($sawmill >= 1) $wood += $wood / 100 * $bid5[$sawmill]['attri']; - if($session->bonus1 == 1) $wood *= 1.25; - + $cnt = count($holder); + for ($i = 0; $i < $cnt; $i++) { + $wood += $bid1[$this->resarray[$holder[$i]]]['prod']; + } + $wood += $wood * 0.25 * $this->ocounter[0]; + if ($sawmill >= 1) { + $wood += $wood / 100 * $bid5[$sawmill]['attri']; + } + if ($session->bonus1 == 1) $wood *= 1.25; return round($wood * SPEED); } private function getClayProd() { + global $bid2, $bid6, $session; - $clay = $brick = 0; - $clayholder = []; - for($i = 1; $i <= 38; $i++) { - if($this->resarray['f'.$i.'t'] == 2) array_push($clayholder,'f'.$i); - if($this->resarray['f'.$i.'t'] == 6) $brick = $this->resarray['f'.$i]; + $holder = []; + for ($i = 1; $i <= 38; $i++) { + if ($this->resarray['f'.$i.'t'] == 2) $holder[] = 'f'.$i; + if ($this->resarray['f'.$i.'t'] == 6) $brick = $this->resarray['f'.$i]; } - - for($i = 0; $i <= count($clayholder) - 1; $i++) $clay+= $bid2[$this->resarray[$clayholder[$i]]]['prod']; - $clay = $clay + $clay * 0.25 * $this->ocounter[1]; - - if($brick >= 1) $clay += $clay / 100 * $bid6[$brick]['attri']; - if($session->bonus2 == 1) $clay *= 1.25; - + $cnt = count($holder); + for ($i = 0; $i < $cnt; $i++) { + $clay += $bid2[$this->resarray[$holder[$i]]]['prod']; + } + $clay += $clay * 0.25 * $this->ocounter[1]; + if ($brick >= 1) { + $clay += $clay / 100 * $bid6[$brick]['attri']; + } + if ($session->bonus2 == 1) $clay *= 1.25; return round($clay * SPEED); } private function getIronProd() { + global $bid3, $bid7, $session; - $iron = $foundry = 0; - $ironholder = []; - for($i = 1; $i <= 38; $i++) { - if($this->resarray['f'.$i.'t'] == 3) array_push($ironholder,'f'.$i); - if($this->resarray['f'.$i.'t'] == 7) $foundry = $this->resarray['f'.$i]; + $holder = []; + for ($i = 1; $i <= 38; $i++) { + if ($this->resarray['f'.$i.'t'] == 3) $holder[] = 'f'.$i; + if ($this->resarray['f'.$i.'t'] == 7) $foundry = $this->resarray['f'.$i]; } - - for($i = 0;$i <= count($ironholder) - 1; $i++) $iron+= $bid3[$this->resarray[$ironholder[$i]]]['prod']; - $iron = $iron + $iron * 0.25 * $this->ocounter[2]; - - if($foundry >= 1) $iron += $iron / 100 * $bid7[$foundry]['attri']; - if($session->bonus3 == 1) $iron *= 1.25; - + $cnt = count($holder); + for ($i = 0; $i < $cnt; $i++) { + $iron += $bid3[$this->resarray[$holder[$i]]]['prod']; + } + $iron += $iron * 0.25 * $this->ocounter[2]; + if ($foundry >= 1) { + $iron += $iron / 100 * $bid7[$foundry]['attri']; + } + if ($session->bonus3 == 1) $iron *= 1.25; return round($iron * SPEED); } private function getCropProd() { + global $bid4, $bid8, $bid9, $session; - $crop = $grainmill = $bakery = 0; - $cropholder = []; - for($i = 1; $i <= 38; $i++) { - if($this->resarray['f'.$i.'t'] == 4) array_push($cropholder,'f'.$i); - if($this->resarray['f'.$i.'t'] == 8) $grainmill = $this->resarray['f'.$i]; - if($this->resarray['f'.$i.'t'] == 9) $bakery = $this->resarray['f'.$i]; + $holder = []; + for ($i = 1; $i <= 38; $i++) { + if ($this->resarray['f'.$i.'t'] == 4) $holder[] = 'f'.$i; + if ($this->resarray['f'.$i.'t'] == 8) $grainmill = $this->resarray['f'.$i]; + if ($this->resarray['f'.$i.'t'] == 9) $bakery = $this->resarray['f'.$i]; } - - for ($i = 0; $i <= count($cropholder) - 1; $i++) $crop += $bid4[$this->resarray[$cropholder[$i]]]['prod']; - $bonus = 0.25 * $this->ocounter[3]; - $crop = $crop + $crop * 0.25 * $this->ocounter[3]; - - if($grainmill >= 1 || $bakery >= 1) { - $crop += $crop / 100 * ((isset($bid8[$grainmill]['attri']) ? $bid8[$grainmill]['attri'] : 0) + (isset($bid9[$bakery]['attri']) ? $bid9[$bakery]['attri'] : 0)); + $cnt = count($holder); + for ($i = 0; $i < $cnt; $i++) { + $crop += $bid4[$this->resarray[$holder[$i]]]['prod']; } - if($session->bonus4 == 1) $crop *= 1.25; - + $crop += $crop * 0.25 * $this->ocounter[3]; + if ($grainmill >= 1 || $bakery >= 1) { + $crop += $crop / 100 * ( + (isset($bid8[$grainmill]['attri']) ? $bid8[$grainmill]['attri'] : 0) + + (isset($bid9[$bakery]['attri']) ? $bid9[$bakery]['attri'] : 0) + ); + } + if ($session->bonus4 == 1) $crop *= 1.25; return round($crop * SPEED); } + /** + * OASIS + */ private function sortOasis() { - $crop = $clay = $wood = $iron = 0; - if(!empty($this->oasisowned)){ - foreach($this->oasisowned as $oasis){ - switch($oasis['type']){ - case 1: - case 2: - $wood++; - break; - case 3: - $wood++; - $crop++; - break; - case 4: - case 5: - $clay++; - break; - case 6: - $clay++; - $crop++; - break; - case 7: - case 8: - $iron++; - break; - case 9: - $iron++; - $crop++; - break; - case 10: - case 11: - $crop++; - break; - case 12: - $crop += 2; - break; + $wood = $clay = $iron = $crop = 0; + if (!empty($this->oasisowned)) { + foreach ($this->oasisowned as $oasis) { + switch ($oasis['type']) { + case 1: case 2: $wood++; break; + case 3: $wood++; $crop++; break; + case 4: case 5: $clay++; break; + case 6: $clay++; $crop++; break; + case 7: case 8: $iron++; break; + case 9: $iron++; $crop++; break; + case 10: case 11: $crop++; break; + case 12: $crop += 2; break; } } } @@ -297,38 +329,26 @@ class Village { } private function ActionControl() { + global $session; - - if(SERVER_WEB_ROOT) $page = $_SERVER['SCRIPT_NAME']; - else - { - $explode = explode("/",$_SERVER['SCRIPT_NAME']); - $i = count($explode)-1; - $page = $explode[$i]; + $page = $_SERVER['SCRIPT_NAME']; + if (!SERVER_WEB_ROOT) { + $page = basename($_SERVER['SCRIPT_NAME']); } - - if($page == "build.php" && $session->uid != $this->infoarray['owner']) { + if ($page == "build.php" && $session->uid != $this->infoarray['owner']) { unset($_SESSION['wid']); header("Location: dorf1.php"); exit; } } - -}; +} $village = new Village; $building = new Building; -// if automation is not currently running, run it for this user, -// so if they are waiting for some automation to take place -// (units, resources, buildings...), the script will calculate that -// before showing the page -// ... this is a quick fix for automation being called async by AJAX -// and users seeing old values on their page even though new values -// already exist after the initial AJAX call -if ( !file_exists( AUTOMATION_LOCK_FILE_NAME ) ) { - define( 'AUTOMATION_MANUAL_RUN', true ); - // this file is auto-removed by the Automation.php script - file_put_contents( AUTOMATION_LOCK_FILE_NAME, '' ); +// automation +if (!file_exists(AUTOMATION_LOCK_FILE_NAME)) { + define('AUTOMATION_MANUAL_RUN', true); + file_put_contents(AUTOMATION_LOCK_FILE_NAME, ''); include_once("Automation.php"); } -?> +?> \ No newline at end of file diff --git a/GameEngine/functions.php b/GameEngine/functions.php index 8be84b48..afca01a8 100755 --- a/GameEngine/functions.php +++ b/GameEngine/functions.php @@ -1,37 +1,103 @@ $repl) - { - $text = str_replace($sub, $repl, $text); + // Cache key (file + modification time) + $cacheKey = $filepath . '|' . filemtime($filepath); + + // Return cached version if exists + if (isset($cache[$cacheKey])) { + $text = $cache[$cacheKey]; + } else { + $text = file_get_contents($filepath); + if ($text === false) { + return false; + } + + // Store raw template in cache + $cache[$cacheKey] = $text; } - ob_start(); - eval("?>".$text); - $text = ob_get_contents(); - ob_end_clean(); - return $text; -} + // Merge subs (local overrides global) + $subs = array_merge($globalSubs, $subs); + // Replace placeholders + if (!empty($subs)) { + foreach ($subs as $sub => $repl) { + $text = str_replace($sub, $repl, $text); + } + } + + /** + * SECURITY CHANGE: + * Removed eval() completely. + * Old system allowed PHP injection via templates. + * + * Now only plain text substitution is supported. + */ + + // Output buffering kept for compatibility with legacy usage + ob_start(); + echo $text; + return ob_get_clean(); +} ?> \ No newline at end of file