Incremental Refactor Form/BBCode/Mailer/Village

Incremental Refactor Form/BBCode/Mailer/Village
This commit is contained in:
Catalin Novgorodschi
2026-05-13 15:09:05 +03:00
parent 35467b93ec
commit f99ab72d25
6 changed files with 555 additions and 500 deletions
+175 -225
View File
@@ -1,255 +1,205 @@
<?php
<?php
include_once ("config.php");
include_once ("Lang/".LANG.".php");
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
## Project: TravianZ ##
## Version: 30.04.2026 ##
## Filename BBCode.php ##
## Developed by: Shadow ##
## Refactor by: Shadow ##
## License: TravianZ Project ##
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
## URLs: https://travianz.org ##
## https://github.com/Shadowss/TravianZ ##
## ##
#################################################################################
include_once("config.php");
include_once("Lang/" . LANG . ".php");
/**
* Ensure input exists (avoid undefined variable issues)
*/
if (!isset($input)) {
$input = '';
}
/**
* -------------------------------------------------------------------------
* BUILD PATTERNS + REPLACEMENTS (optimized, loop-based, no duplication)
* -------------------------------------------------------------------------
*/
$pattern = [];
$pattern[0] = "/\[b\](.*?)\[\/b\]/is";
$pattern[1] = "/\[i\](.*?)\[\/i\]/is";
$pattern[2] = "/\[u\](.*?)\[\/u\]/is";
$pattern[3] = "/\[tid1\]/";
$pattern[4] = "/\[tid2\]/";
$pattern[5] = "/\[tid3\]/";
$pattern[6] = "/\[tid4\]/";
$pattern[7] = "/\[tid5\]/";
$pattern[8] = "/\[tid6\]/";
$pattern[9] = "/\[tid7\]/";
$pattern[10] = "/\[tid8\]/";
$pattern[11] = "/\[tid9\]/";
$pattern[12] = "/\[tid10\]/";
$pattern[13] = "/\[tid11\]/";
$pattern[14] = "/\[tid12\]/";
$pattern[15] = "/\[tid13\]/";
$pattern[16] = "/\[tid14\]/";
$pattern[17] = "/\[tid15\]/";
$pattern[18] = "/\[tid16\]/";
$pattern[19] = "/\[tid17\]/";
$pattern[20] = "/\[tid18\]/";
$pattern[21] = "/\[tid19\]/";
$pattern[22] = "/\[tid20\]/";
$pattern[23] = "/\[tid21\]/";
$pattern[24] = "/\[tid22\]/";
$pattern[25] = "/\[tid23\]/";
$pattern[26] = "/\[tid24\]/";
$pattern[27] = "/\[tid25\]/";
$pattern[28] = "/\[tid26\]/";
$pattern[29] = "/\[tid27\]/";
$pattern[30] = "/\[tid28\]/";
$pattern[31] = "/\[tid29\]/";
$pattern[32] = "/\[tid30\]/";
$pattern[33] = "/\[tid31\]/";
$pattern[34] = "/\[tid32\]/";
$pattern[35] = "/\[tid33\]/";
$pattern[36] = "/\[tid34\]/";
$pattern[37] = "/\[tid35\]/";
$pattern[38] = "/\[tid36\]/";
$pattern[39] = "/\[tid37\]/";
$pattern[40] = "/\[tid38\]/";
$pattern[41] = "/\[tid39\]/";
$pattern[42] = "/\[tid40\]/";
$pattern[43] = "/\[tid41\]/";
$pattern[44] = "/\[tid42\]/";
$pattern[45] = "/\[tid43\]/";
$pattern[46] = "/\[tid44\]/";
$pattern[47] = "/\[tid45\]/";
$pattern[48] = "/\[tid46\]/";
$pattern[49] = "/\[tid47\]/";
$pattern[50] = "/\[tid48\]/";
$pattern[51] = "/\[tid49\]/";
$pattern[52] = "/\[tid50\]/";
$pattern[53] = "/\[hero\]/";
$pattern[54] = "/\[lumber\]/";
$pattern[55] = "/\[clay\]/";
$pattern[56] = "/\[iron\]/";
$pattern[57] = "/\[crop\]/";
$pattern[58] = "/\*aha\*/";
$pattern[59] = "/\*angry\*/";
$pattern[60] = "/\*cool\*/";
$pattern[61] = "/\*cry\*/";
$pattern[62] = "/\*cute\*/";
$pattern[63] = "/\*depressed\*/";
$pattern[64] = "/\*eek\*/";
$pattern[65] = "/\*ehem\*/";
$pattern[66] = "/\*emotional\*/";
$pattern[67] = "/\:D/";
$pattern[68] = "/\:\)/";
$pattern[69] = "/\*hit\*/";
$pattern[70] = "/\*hmm\*/";
$pattern[71] = "/\*hmpf\*/";
$pattern[72] = "/\*hrhr\*/";
$pattern[73] = "/\*huh\*/";
$pattern[74] = "/\*lazy\*/";
$pattern[75] = "/\*love\*/";
$pattern[76] = "/\*nocomment\*/";
$pattern[77] = "/\*noemotion\*/";
$pattern[78] = "/\*notamused\*/";
$pattern[79] = "/\*pout\*/";
$pattern[80] = "/\*redface\*/";
$pattern[81] = "/\*rolleyes\*/";
$pattern[82] = "/\:\(/";
$pattern[83] = "/\*shy\*/";
$pattern[84] = "/\*smile\*/";
$pattern[85] = "/\*tongue\*/";
$pattern[86] = "/\*veryangry\*/";
$pattern[87] = "/\*veryhappy\*/";
$pattern[88] = "/\;\)/";
$replace = [];
$replace[0] = "<b>$1</b>";
$replace[1] = "<i>$1</i>";
$replace[2] = "<u>$1</u>";
$replace[3] = "<img class='unit u1' src='img/x.gif' title='".U1."' alt='".U1."'>";
$replace[4] = "<img class='unit u2' src='img/x.gif' title='".U2."' alt='".U2."'>";
$replace[5] = "<img class='unit u3' src='img/x.gif' title='".U3."' alt='".U3."'>";
$replace[6] = "<img class='unit u4' src='img/x.gif' title='".U4."' alt='".U4."'>";
$replace[7] = "<img class='unit u5' src='img/x.gif' title='".U5."' alt='".U5."'>";
$replace[8] = "<img class='unit u6' src='img/x.gif' title='".U6."' alt='".U6."'>";
$replace[9] = "<img class='unit u7' src='img/x.gif' title='".U7."' alt='".U7."'>";
$replace[10] = "<img class='unit u8' src='img/x.gif' title='".U8."' alt='".U8."'>";
$replace[11] = "<img class='unit u9' src='img/x.gif' title='".U9."' alt='".U9."'>";
$replace[12] = "<img class='unit u10' src='img/x.gif' title='".U10."' alt='".U10."'>";
$replace[13] = "<img class='unit u11' src='img/x.gif' title='".U11."' alt='".U11."'>";
$replace[14] = "<img class='unit u12' src='img/x.gif' title='".U12."' alt='".U12."'>";
$replace[15] = "<img class='unit u13' src='img/x.gif' title='".U13."' alt='".U13."'>";
$replace[16] = "<img class='unit u14' src='img/x.gif' title='".U14."' alt='".U14."'>";
$replace[17] = "<img class='unit u15' src='img/x.gif' title='".U15."' alt='".U15."'>";
$replace[18] = "<img class='unit u16' src='img/x.gif' title='".U16."' alt='".U16."'>";
$replace[19] = "<img class='unit u17' src='img/x.gif' title='".U17."' alt='".U17."'>";
$replace[20] = "<img class='unit u18' src='img/x.gif' title='".U18."' alt='".U18."'>";
$replace[21] = "<img class='unit u19' src='img/x.gif' title='".U19."' alt='".U19."'>";
$replace[22] = "<img class='unit u20' src='img/x.gif' title='".U20."' alt='".U20."'>";
$replace[23] = "<img class='unit u21' src='img/x.gif' title='".U21."' alt='".U21."'>";
$replace[24] = "<img class='unit u22' src='img/x.gif' title='".U22."' alt='".U22."'>";
$replace[25] = "<img class='unit u23' src='img/x.gif' title='".U23."' alt='".U23."'>";
$replace[26] = "<img class='unit u24' src='img/x.gif' title='".U24."' alt='".U24."'>";
$replace[27] = "<img class='unit u25' src='img/x.gif' title='".U25."' alt='".U25."'>";
$replace[28] = "<img class='unit u26' src='img/x.gif' title='".U26."' alt='".U26."'>";
$replace[29] = "<img class='unit u27' src='img/x.gif' title='".U27."' alt='".U27."'>";
$replace[30] = "<img class='unit u28' src='img/x.gif' title='".U28."' alt='".U28."'>";
$replace[31] = "<img class='unit u29' src='img/x.gif' title='".U29."' alt='".U29."'>";
$replace[32] = "<img class='unit u30' src='img/x.gif' title='".U30."' alt='".U30."'>";
$replace[33] = "<img class='unit u31' src='img/x.gif' title='".U31."' alt='".U31."'>";
$replace[34] = "<img class='unit u32' src='img/x.gif' title='".U32."' alt='".U32."'>";
$replace[35] = "<img class='unit u33' src='img/x.gif' title='".U33."' alt='".U33."'>";
$replace[36] = "<img class='unit u34' src='img/x.gif' title='".U34."' alt='".U34."'>";
$replace[37] = "<img class='unit u35' src='img/x.gif' title='".U35."' alt='".U35."'>";
$replace[38] = "<img class='unit u36' src='img/x.gif' title='".U36."' alt='".U36."'>";
$replace[39] = "<img class='unit u37' src='img/x.gif' title='".U37."' alt='".U37."'>";
$replace[40] = "<img class='unit u38' src='img/x.gif' title='".U38."' alt='".U38."'>";
$replace[41] = "<img class='unit u39' src='img/x.gif' title='".U39."' alt='".U39."'>";
$replace[42] = "<img class='unit u40' src='img/x.gif' title='".U40."' alt='".U40."'>";
$replace[43] = "<img class='unit u41' src='img/x.gif' title='".U41."' alt='".U41."'>";
$replace[44] = "<img class='unit u42' src='img/x.gif' title='".U42."' alt='".U42."'>";
$replace[45] = "<img class='unit u43' src='img/x.gif' title='".U43."' alt='".U43."'>";
$replace[46] = "<img class='unit u44' src='img/x.gif' title='".U44."' alt='".U44."'>";
$replace[47] = "<img class='unit u45' src='img/x.gif' title='".U45."' alt='".U45."'>";
$replace[48] = "<img class='unit u46' src='img/x.gif' title='".U46."' alt='".U46."'>";
$replace[49] = "<img class='unit u47' src='img/x.gif' title='".U47."' alt='".U47."'>";
$replace[50] = "<img class='unit u48' src='img/x.gif' title='".U48."' alt='".U48."'>";
$replace[51] = "<img class='unit u49' src='img/x.gif' title='".U49."' alt='".U49."'>";
$replace[52] = "<img class='unit u50' src='img/x.gif' title='".U50."' alt='".U50."'>";
$replace[53] = "<img class='unit uhero' src='img/x.gif' title='".U0."' alt='".U0."'>";
$replace[54] = "<img src='img/x.gif' class='r1' title='".LUMBER."' alt='".LUMBER."'>";
$replace[55] = "<img src='img/x.gif' class='r2' title='".CLAY."' alt='".CLAY."'>";
$replace[56] = "<img src='img/x.gif' class='r3' title='".IRON."' alt='".IRON."'>";
$replace[57] = "<img src='img/x.gif' class='r4' title='".CROP."' alt='".CROP."'>";
$replace[54] = "<img src='img/x.gif' class='r1' title='".LUMBER."' alt='".LUMBER."'>";
$replace[55] = "<img src='img/x.gif' class='r2' title='".CLAY."' alt='".CLAY."'>";
$replace[56] = "<img src='img/x.gif' class='r3' title='".IRON."' alt='".IRON."'>";
$replace[57] = "<img src='img/x.gif' class='r4' title='".CROP."' alt='".CROP."'>";
$replace[58] = "<img class='smiley aha' src='img/x.gif' alt='*aha*' title='*aha*'>";
$replace[59] = "<img class='smiley angry' src='img/x.gif' alt='*angry*' title='*angry*'>";
$replace[60] = "<img class='smiley cool' src='img/x.gif' alt='*cool*' title='*cool*'>";
$replace[61] = "<img class='smiley cry' src='img/x.gif' alt='*cry*' title='*cry*'>";
$replace[62] = "<img class='smiley cute' src='img/x.gif' alt='*cute*' title='*cute*'>";
$replace[63] = "<img class='smiley depressed' src='img/x.gif' alt='*depressed*' title='*depressed*'>";
$replace[64] = "<img class='smiley eek' src='img/x.gif' alt='*eek*' title='*eek*'>";
$replace[65] = "<img class='smiley ehem' src='img/x.gif' alt='*ehem*' title='*ehem*'>";
$replace[66] = "<img class='smiley emotional' src='img/x.gif' alt='*emotional*' title='*emotional*'>";
$replace[67] = "<img class='smiley grin' src='img/x.gif' alt=':D' title=':D'>";
$replace[68] = "<img class='smiley happy' src='img/x.gif' alt=':)' title=':)'>";
$replace[69] = "<img class='smiley hit' src='img/x.gif' alt='*hit*' title='*hit*'>";
$replace[70] = "<img class='smiley hmm' src='img/x.gif' alt='*hmm*' title='*hmm*'>";
$replace[71] = "<img class='smiley hmpf' src='img/x.gif' alt='*hmpf*' title='*hmpf*'>";
$replace[72] = "<img class='smiley hrhr' src='img/x.gif' alt='*hrhr*' title='*hrhr*'>";
$replace[73] = "<img class='smiley huh' src='img/x.gif' alt='*huh*' title='*huh*'>";
$replace[74] = "<img class='smiley lazy' src='img/x.gif' alt='*lazy*' title='*lazy*'>";
$replace[75] = "<img class='smiley love' src='img/x.gif' alt='*love*' title='*love*'>";
$replace[76] = "<img class='smiley nocomment' src='img/x.gif' alt='*nocomment*' title='*nocomment*'>";
$replace[77] = "<img class='smiley noemotion' src='img/x.gif' alt='*noemotion*' title='*noemotion*'>";
$replace[78] = "<img class='smiley notamused' src='img/x.gif' alt='*notamused*' title='*notamused*'>";
$replace[79] = "<img class='smiley pout' src='img/x.gif' alt='*pout*' title='*pout*'>";
$replace[80] = "<img class='smiley redface' src='img/x.gif' alt='*redface*' title='*redface*'>";
$replace[81] = "<img class='smiley rolleyes' src='img/x.gif' alt='*rolleyes*' title='*rolleyes*'>";
$replace[82] = "<img class='smiley sad' src='img/x.gif' alt=':(' title=':('>";
$replace[83] = "<img class='smiley shy' src='img/x.gif' alt='*shy*' title='*shy*'>";
$replace[84] = "<img class='smiley smile' src='img/x.gif' alt='*smile*' title='*smile*'>";
$replace[85] = "<img class='smiley tongue' src='img/x.gif' alt='*tongue*' title='*tongue*'>";
$replace[86] = "<img class='smiley veryangry' src='img/x.gif' alt='*veryangry*' title='*veryangry*'>";
$replace[87] = "<img class='smiley veryhappy' src='img/x.gif' alt='*veryhappy*' title='*veryhappy*'>";
$replace[88] = "<img class='smiley wink' src='img/x.gif' alt=';)' title=';)'>";
// replace alliance placeholders
$input = preg_replace_callback(
/* Basic BBCode */
$pattern[] = "/\[b\](.*?)\[\/b\]/is";
$replace[] = "<b>$1</b>";
$pattern[] = "/\[i\](.*?)\[\/i\]/is";
$replace[] = "<i>$1</i>";
$pattern[] = "/\[u\](.*?)\[\/u\]/is";
$replace[] = "<u>$1</u>";
/* Unit placeholders tid1 - tid50 */
for ($i = 1; $i <= 50; $i++) {
$pattern[] = "/\[tid{$i}\]/";
$replace[] = "<img class='unit u{$i}' src='img/x.gif' title='" . constant("U{$i}") . "' alt='" . constant("U{$i}") . "'>";
}
/* Hero */
$pattern[] = "/\[hero\]/";
$replace[] = "<img class='unit uhero' src='img/x.gif' title='" . U0 . "' alt='" . 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[] = "<img src='img/x.gif' class='r{$id}' title='{$name}' alt='{$name}'>";
}
/* Smilies & emoticons */
$smilies = [
"/\*aha\*/" => "<img class='smiley aha' src='img/x.gif' alt='*aha*' title='*aha*'>",
"/\*angry\*/" => "<img class='smiley angry' src='img/x.gif' alt='*angry*' title='*angry*'>",
"/\*cool\*/" => "<img class='smiley cool' src='img/x.gif' alt='*cool*' title='*cool*'>",
"/\*cry\*/" => "<img class='smiley cry' src='img/x.gif' alt='*cry*' title='*cry*'>",
"/\*cute\*/" => "<img class='smiley cute' src='img/x.gif' alt='*cute*' title='*cute*'>",
"/\*depressed\*/" => "<img class='smiley depressed' src='img/x.gif' alt='*depressed*' title='*depressed*'>",
"/\*eek\*/" => "<img class='smiley eek' src='img/x.gif' alt='*eek*' title='*eek*'>",
"/\*ehem\*/" => "<img class='smiley ehem' src='img/x.gif' alt='*ehem*' title='*ehem*'>",
"/\*emotional\*/" => "<img class='smiley emotional' src='img/x.gif' alt='*emotional*' title='*emotional*'>",
"/:D/" => "<img class='smiley grin' src='img/x.gif' alt=':D' title=':D'>",
"/:\)/" => "<img class='smiley happy' src='img/x.gif' alt=':)' title=':)'>",
"/\*hit\*/" => "<img class='smiley hit' src='img/x.gif' alt='*hit*' title='*hit*'>",
"/\*hmm\*/" => "<img class='smiley hmm' src='img/x.gif' alt='*hmm*' title='*hmm*'>",
"/\*hmpf\*/" => "<img class='smiley hmpf' src='img/x.gif' alt='*hmpf*' title='*hmpf*'>",
"/\*hrhr\*/" => "<img class='smiley hrhr' src='img/x.gif' alt='*hrhr*' title='*hrhr*'>",
"/\*huh\*/" => "<img class='smiley huh' src='img/x.gif' alt='*huh*' title='*huh*'>",
"/\*lazy\*/" => "<img class='smiley lazy' src='img/x.gif' alt='*lazy*' title='*lazy*'>",
"/\*love\*/" => "<img class='smiley love' src='img/x.gif' alt='*love*' title='*love*'>",
"/\*nocomment\*/" => "<img class='smiley nocomment' src='img/x.gif' alt='*nocomment*' title='*nocomment*'>",
"/\*noemotion\*/" => "<img class='smiley noemotion' src='img/x.gif' alt='*noemotion*' title='*noemotion*'>",
"/\*notamused\*/" => "<img class='smiley notamused' src='img/x.gif' alt='*notamused*' title='*notamused*'>",
"/\*pout\*/" => "<img class='smiley pout' src='img/x.gif' alt='*pout*' title='*pout*'>",
"/\*redface\*/" => "<img class='smiley redface' src='img/x.gif' alt='*redface*' title='*redface*'>",
"/\*rolleyes\*/" => "<img class='smiley rolleyes' src='img/x.gif' alt='*rolleyes*' title='*rolleyes*'>",
"/:\(/" => "<img class='smiley sad' src='img/x.gif' alt=':(' title=':('>",
"/\*shy\*/" => "<img class='smiley shy' src='img/x.gif' alt='*shy*' title='*shy*'>",
"/\*smile\*/" => "<img class='smiley smile' src='img/x.gif' alt='*smile*' title='*smile*'>",
"/\*tongue\*/" => "<img class='smiley tongue' src='img/x.gif' alt='*tongue*' title='*tongue*'>",
"/\*veryangry\*/" => "<img class='smiley veryangry' src='img/x.gif' alt='*veryangry*' title='*veryangry*'>",
"/\*veryhappy\*/" => "<img class='smiley veryhappy' src='img/x.gif' alt='*veryhappy*' title='*veryhappy*'>",
"/;\)/" => "<img class='smiley wink' src='img/x.gif' alt=';)' title=';)'>",
];
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 "<a href=allianz.php?aid=$matches[2]>".$aname."</a>";
else return "Alliance not found!";
if (!empty($aname)) {
return "<a href='allianz.php?aid={$matches[2]}'>{$aname}</a>";
}
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 "<a href=spieler.php?uid=$matches[2]>".$uname."</a>";
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 "<a href='spieler.php?uid={$matches[2]}'>{$uname}</a>";
}
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 "<a href=berichte.php?id=".$reportID.">".$report['topic']."</a>";
else return "Report not found!";
if (!empty($report)) {
return "<a href='berichte.php?id={$reportID}'>{$report['topic']}</a>";
}
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 "<a href=karte.php?d=".$wRef."&amp;c=".$cwref.">".$name." (".$coordinates[0]."|".$coordinates[1].")"."</a>";
if (!empty($name)) {
return "<a href='karte.php?d={$wRef}&amp;c={$cwref}'>{$name} ({$coordinates[0]}|{$coordinates[1]})</a>";
}
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);
?>
+5 -1
View File
@@ -1,11 +1,15 @@
<?php
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
## Filename Chat.php ##
## Developed by: TTMMTT ##
## 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 ##
## ##
#################################################################################
+3 -3
View File
@@ -6,13 +6,13 @@
## Filename Form.php ##
## License: TravianZ Project ##
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
## Refactored by: Shadow ##
## Refactored by: Shadow ##
## ##
## Refactor: Incremental cleanup (compatibility preserved) ##
## Notes: PHP 7+ / legacy safe ##
## ##
## URLs: http://travian.shadowss.ro ##
## https://github.com/Shadowss/TravianZ ##
## URLs: http://travian.shadowss.ro ##
## https://github.com/Shadowss/TravianZ ##
## ##
#################################################################################
+79 -64
View File
@@ -5,91 +5,106 @@
## --------------------------------------------------------------------------- ##
## Filename Mailer.php ##
## Developed by: Dixie ##
## Refactored: Shadow (PHP 7+ compatibility, cleanup, safety pass) ##
## License: TravianZ Project ##
## Copyright: TravianZ (c) 2010-2025. All rights reserved. ##
## ##
## URLs: https://travianz.org ##
## https://github.com/Shadowss/TravianZ ##
## ##
#################################################################################
class Mailer {
class Mailer
{
/**
* -------------------------------------------------------------------------
* SEND ACTIVATION EMAIL
* -------------------------------------------------------------------------
*/
function sendActivate($email, $username, $pass, $act)
{
$subject = "Welcome to " . SERVER_NAME;
function sendActivate($email,$username,$pass,$act) {
$message =
"Hello " . $username . "\n\n" .
"Thank you for your registration.\n\n" .
"----------------------------\n" .
"Name: " . $username . "\n" .
"Password: " . $pass . "\n" .
"Activation code: " . $act . "\n" .
"----------------------------\n\n" .
"Click the following link in order to activate your account:\n" .
SERVER . "activate.php?code=" . $act . "\n\n" .
"Greetings,\n" .
"Travian administration";
$subject = "Welcome to ".SERVER_NAME;
$headers = "From: " . ADMIN_EMAIL . "\r\n";
$message = "Hello ".$username."
Thank you for your registration.
----------------------------
Name: ".$username."
Password: ".$pass."
Activation code: ".$act."
----------------------------
Click the following link in order to activate your account:
".SERVER."activate.php?code=".$act."
Greetings,
Travian adminision";
$headers = "From: ".ADMIN_EMAIL."\n";
mail($email, $subject, $message, $headers);
@mail($email, $subject, $message, $headers);
}
function sendInvite($email,$uid,$text) {
/**
* -------------------------------------------------------------------------
* SEND INVITE EMAIL
* -------------------------------------------------------------------------
* FIX: $username was undefined -> 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;
?>
+203 -183
View File
@@ -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");
}
?>
?>
+90 -24
View File
@@ -1,37 +1,103 @@
<?php
############################################################
## ##
## Test functions so far mini template parser ##
## Author : Advocaite ##
## Project : TravianZ ##
## ##
############################################################
#################################################################################
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
## --------------------------------------------------------------------------- ##
## Project: TravianZ ##
## Version: 30.04.2026 ##
## Filename functions.php - mini template parser ##
## Developed by: Advocaite ##
## Refactor by: Shadow (PHP 7+ safe + optimized) ##
## License: TravianZ Project ##
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
## URLs: https://travianz.org ##
## https://github.com/Shadowss/TravianZ ##
## ##
#################################################################################
/**
* -------------------------------------------------------------------------
* TEMPLATE SUBSTITUTION REGISTER
* -------------------------------------------------------------------------
* Stores global placeholders used across templates.
* Example: {USERNAME}, {LEVEL}, etc.
*/
function addSub($subName, $sub)
{
$GLOBALS['subs']["{".$subName."}"] = $sub;
// Initialize storage if not set (safe legacy fix)
if (!isset($GLOBALS['subs']) || !is_array($GLOBALS['subs'])) {
$GLOBALS['subs'] = [];
}
$GLOBALS['subs']['{' . $subName . '}'] = $sub;
}
function template($filepath, $subs)
/**
* -------------------------------------------------------------------------
* SIMPLE TEMPLATE ENGINE (SAFE VERSION)
* -------------------------------------------------------------------------
* - Loads template file
* - Replaces placeholders
* - Executes NO PHP eval (security fix)
* - Returns rendered HTML
*
* Added:
* - file cache (static)
* - safe fallback handling
*/
function template($filepath, $subs = [])
{
global $s;
if(file_exists($filepath))
{
$text = file_get_contents($filepath);
} else {
print "File '$filepath' not found";
static $cache = [];
// Merge global subs + local subs (local overrides global)
$globalSubs = (isset($GLOBALS['subs']) && is_array($GLOBALS['subs']))
? $GLOBALS['subs']
: [];
if (!file_exists($filepath)) {
echo "File '" . $filepath . "' not found";
return false;
}
foreach($subs as $sub => $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();
}
?>