mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-08-14 23:31:02 +00:00
Fix something wrong
This commit is contained in:
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename config_instance.php ##
|
||||
## Type : Multi-instance configuration frontend ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project : TravianZ ##
|
||||
## Source code : https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
@set_time_limit(0);
|
||||
@session_start();
|
||||
|
||||
require_once dirname(__DIR__) . '/GameEngine/Instance/InstanceResolver.php';
|
||||
require_once dirname(__DIR__) . '/GameEngine/Instance/Instance.php';
|
||||
|
||||
$instanceId = strtolower(trim((string) ($_GET['instance'] ?? '')));
|
||||
if (!TravianZInstanceResolver::isValid($instanceId)) {
|
||||
http_response_code(400);
|
||||
exit('Invalid instance ID.');
|
||||
}
|
||||
|
||||
$root = dirname(__DIR__);
|
||||
$registryFile = $root . '/instances/registry.json';
|
||||
$registry = [];
|
||||
if (is_file($registryFile)) {
|
||||
$data = json_decode((string) file_get_contents($registryFile), true);
|
||||
if (is_array($data)) $registry = $data;
|
||||
}
|
||||
|
||||
if (!isset($registry[$instanceId]) || !is_array($registry[$instanceId])) {
|
||||
http_response_code(404);
|
||||
exit('Instance not found.');
|
||||
}
|
||||
|
||||
$instance = $registry[$instanceId];
|
||||
|
||||
// The existing installer template is the canonical source for all settings.
|
||||
// We reuse it instead of maintaining a second copy of the very large form.
|
||||
// Values controlled by the instance definition are injected into the rendered
|
||||
// form so every world gets its own DB/name/prefix while all other settings stay
|
||||
// exactly the same as the normal TravianZ installer.
|
||||
$_SESSION['install_random_prefix'] = (string) ($instance['prefix'] ?? ($instanceId . '_'));
|
||||
|
||||
ob_start();
|
||||
include $root . '/install/templates/config.tpl';
|
||||
$html = ob_get_clean();
|
||||
|
||||
$html = str_replace('action="process.php"', 'action="process_instance.php"', $html);
|
||||
$html = preg_replace(
|
||||
'/(<form\s+action="process_instance\.php"[^>]*>)/i',
|
||||
'$1\n<input type="hidden" name="instance_id" value="' . htmlspecialchars($instanceId, ENT_QUOTES, 'UTF-8') . '">\n<input type="hidden" name="action" value="config">',
|
||||
$html,
|
||||
1
|
||||
);
|
||||
|
||||
$dbName = (string) ($instance['database'] ?? ('travian_' . $instanceId));
|
||||
$prefix = (string) ($instance['prefix'] ?? ($instanceId . '_'));
|
||||
$name = (string) ($instance['name'] ?? ('TravianZ ' . strtoupper($instanceId)));
|
||||
|
||||
$html = preg_replace('/(<input[^>]+name="servername"[^>]+value=")[^"]*("[^>]*>)/i', '$1' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '$2', $html, 1);
|
||||
$html = preg_replace('/(<input[^>]+name="sdb"[^>]+value=")[^"]*("[^>]*>)/i', '$1' . htmlspecialchars($dbName, ENT_QUOTES, 'UTF-8') . '$2', $html, 1);
|
||||
$html = preg_replace('/(<input[^>]+name="prefix"[^>]+value=")[^"]*("[^>]*>)/i', '$1' . htmlspecialchars($prefix, ENT_QUOTES, 'UTF-8') . '$2', $html, 1);
|
||||
|
||||
$header = '<div style="margin:15px auto;max-width:1100px;padding:14px;background:#e8f5e9;border:1px solid #b7d7b9;font-family:Arial,sans-serif;">'
|
||||
. '<strong>Configuring instance ' . htmlspecialchars($instanceId, ENT_QUOTES, 'UTF-8') . '</strong>'
|
||||
. ' — ' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8')
|
||||
. ' — database: <code>' . htmlspecialchars($dbName, ENT_QUOTES, 'UTF-8') . '</code>'
|
||||
. '<br><a href="multi.php">← Back to multi-instance installer</a>'
|
||||
. '</div>';
|
||||
|
||||
$html = preg_replace('/<body([^>]*)>/i', '<body$1>' . $header, $html, 1);
|
||||
|
||||
echo $html;
|
||||
@@ -13,23 +13,16 @@
|
||||
## ##
|
||||
#################################################################################
|
||||
|
||||
|
||||
// verify form
|
||||
if (empty($_POST['mhpw']) || empty($_POST['spw'])) {
|
||||
if (defined('TRAVIANZ_INSTANCE_ID') && TRAVIANZ_INSTANCE_ID !== 'default') {
|
||||
header("Location: ../accounts_instance.php?instance=" . rawurlencode(TRAVIANZ_INSTANCE_ID) . "&err=1");
|
||||
} else {
|
||||
header("Location: ../index.php?s=4&err=1");
|
||||
}
|
||||
header("Location: ../index.php?s=4&err=1");
|
||||
exit;
|
||||
}
|
||||
|
||||
// don't allow creating Natars user
|
||||
if (!empty($_POST['aname']) && strtolower($_POST['aname']) == 'natars') {
|
||||
if (defined('TRAVIANZ_INSTANCE_ID') && TRAVIANZ_INSTANCE_ID !== 'default') {
|
||||
header("Location: ../accounts_instance.php?instance=" . rawurlencode(TRAVIANZ_INSTANCE_ID) . "&err=2");
|
||||
} else {
|
||||
header("Location: ../index.php?s=4&err=2");
|
||||
}
|
||||
header("Location: ../index.php?s=4&err=2");
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -38,21 +31,10 @@
|
||||
|
||||
$gameinstall = 1;
|
||||
|
||||
// The default installer keeps the legacy config path. A named world
|
||||
// always writes to its own instance config and never modifies another
|
||||
// world's configuration.
|
||||
if (!class_exists('TravianZInstanceBootstrap')) {
|
||||
$bootstrap = dirname(__DIR__, 2) . "/GameEngine/Instance/Bootstrap.php";
|
||||
if (is_file($bootstrap)) {
|
||||
require_once $bootstrap;
|
||||
}
|
||||
}
|
||||
$configFile = class_exists('TravianZInstance')
|
||||
? TravianZInstance::configPath()
|
||||
: "../../GameEngine/config.php";
|
||||
|
||||
include_once(dirname(__DIR__, 2) . "/GameEngine/Database.php");
|
||||
include_once(dirname(__DIR__, 2) . "/GameEngine/Admin/database.php");
|
||||
$configFile = "../../GameEngine/config.php";
|
||||
include_once($configFile);
|
||||
include_once("../../GameEngine/Database.php");
|
||||
include_once("../../GameEngine/Admin/database.php");
|
||||
require_once dirname(__DIR__, 2) . "/GameEngine/Lang/loader.php";
|
||||
tz_load_language(LANG);
|
||||
|
||||
@@ -174,32 +156,6 @@
|
||||
}
|
||||
|
||||
$gameinstall = 0;
|
||||
header("Location: ../index.php?s=5");
|
||||
|
||||
if (defined('TRAVIANZ_INSTANCE_ID') && TRAVIANZ_INSTANCE_ID !== 'default') {
|
||||
// The account step is the final step for a named world. Keep the
|
||||
// installed marker local to this instance and update only its
|
||||
// registry entry; the default world's legacy installer marker is
|
||||
// deliberately untouched.
|
||||
$instancePath = dirname(__DIR__, 2) . '/instances/' . TRAVIANZ_INSTANCE_ID;
|
||||
if (!is_dir($instancePath)) {
|
||||
@mkdir($instancePath, 0775, true);
|
||||
}
|
||||
@file_put_contents($instancePath . '/installed', date('c') . PHP_EOL, LOCK_EX);
|
||||
|
||||
$registryFile = dirname(__DIR__, 2) . '/instances/registry.json';
|
||||
if (is_file($registryFile)) {
|
||||
$registry = json_decode((string) @file_get_contents($registryFile), true);
|
||||
if (is_array($registry) && isset($registry[TRAVIANZ_INSTANCE_ID])) {
|
||||
$registry[TRAVIANZ_INSTANCE_ID]['status'] = 'installed';
|
||||
$registry[TRAVIANZ_INSTANCE_ID]['installed_at'] = date('c');
|
||||
$registry[TRAVIANZ_INSTANCE_ID]['updated_at'] = date('c');
|
||||
@file_put_contents($registryFile, json_encode($registry, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL, LOCK_EX);
|
||||
}
|
||||
}
|
||||
|
||||
header("Location: ../multi.php?instance=" . rawurlencode(TRAVIANZ_INSTANCE_ID));
|
||||
} else {
|
||||
header("Location: ../index.php?s=5");
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename multi.php ##
|
||||
## Type : Multi-instance installation manager ##
|
||||
## Project : TravianZ ##
|
||||
## Source code : https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
// Multi-instance installer manager.
|
||||
//
|
||||
// The normal TravianZ installer remains available for the legacy/default world.
|
||||
// This page manages isolated worlds from one code installation. Each world gets
|
||||
// its own config.php, database target, runtime directory and installed marker.
|
||||
|
||||
@set_time_limit(0);
|
||||
@session_start();
|
||||
|
||||
$root = dirname(__DIR__);
|
||||
$instancesDir = $root . DIRECTORY_SEPARATOR . 'instances';
|
||||
$registryFile = $instancesDir . DIRECTORY_SEPARATOR . 'registry.json';
|
||||
|
||||
if (!is_dir($instancesDir)) {
|
||||
@mkdir($instancesDir, 0775, true);
|
||||
}
|
||||
|
||||
function tz_multi_registry_read($file) {
|
||||
if (!is_file($file)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = json_decode((string) @file_get_contents($file), true);
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
function tz_multi_registry_write($file, array $data) {
|
||||
$tmp = $file . '.tmp';
|
||||
$json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
|
||||
if ($json === false || @file_put_contents($tmp, $json . PHP_EOL, LOCK_EX) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!@rename($tmp, $file)) {
|
||||
@unlink($tmp);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$registry = tz_multi_registry_read($registryFile);
|
||||
$message = '';
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_definitions'])) {
|
||||
$count = isset($_POST['server_count']) ? (int) $_POST['server_count'] : 1;
|
||||
$count = max(1, min(100, $count));
|
||||
|
||||
$newRegistry = $registry;
|
||||
$usedIds = [];
|
||||
|
||||
for ($i = 1; $i <= $count; $i++) {
|
||||
$id = strtolower(trim((string) ($_POST['instance_id'][$i] ?? '')));
|
||||
$name = trim((string) ($_POST['instance_name'][$i] ?? ''));
|
||||
$host = trim((string) ($_POST['instance_host'][$i] ?? ''));
|
||||
$db = trim((string) ($_POST['instance_db'][$i] ?? ''));
|
||||
$prefix = trim((string) ($_POST['instance_prefix'][$i] ?? ''));
|
||||
|
||||
if ($id === '') {
|
||||
$id = 's' . $i;
|
||||
}
|
||||
if (!preg_match('/^[a-z0-9][a-z0-9_-]{0,31}$/', $id)) {
|
||||
$error = 'Instance ID invalid la serverul ' . $i . '. Foloseste doar litere mici, cifre, _ sau -.';
|
||||
break;
|
||||
}
|
||||
if (isset($usedIds[$id])) {
|
||||
$error = 'Instance ID duplicat: ' . htmlspecialchars($id, ENT_QUOTES, 'UTF-8');
|
||||
break;
|
||||
}
|
||||
$usedIds[$id] = true;
|
||||
if ($name === '') $name = 'TravianZ ' . strtoupper($id);
|
||||
if ($db === '') $db = 'travian_' . preg_replace('/[^a-zA-Z0-9_]/', '_', $id);
|
||||
if ($prefix === '') $prefix = $id . '_';
|
||||
if (!preg_match('/^[A-Za-z0-9_$]+_$/', $prefix)) {
|
||||
$error = 'Prefix invalid la serverul ' . $i . '.';
|
||||
break;
|
||||
}
|
||||
|
||||
$instancePath = $instancesDir . DIRECTORY_SEPARATOR . $id;
|
||||
if (!is_dir($instancePath) && !@mkdir($instancePath, 0775, true)) {
|
||||
$error = 'Nu pot crea directorul instanței ' . $id . '.';
|
||||
break;
|
||||
}
|
||||
$runtimePath = $instancePath . DIRECTORY_SEPARATOR . 'runtime';
|
||||
if (!is_dir($runtimePath)) @mkdir($runtimePath, 0775, true);
|
||||
|
||||
$newRegistry[$id] = [
|
||||
'id' => $id,
|
||||
'name' => $name,
|
||||
'host' => $host,
|
||||
'database' => $db,
|
||||
'prefix' => $prefix,
|
||||
'status' => $newRegistry[$id]['status'] ?? 'defined',
|
||||
'created_at' => $newRegistry[$id]['created_at'] ?? date('c'),
|
||||
];
|
||||
}
|
||||
|
||||
if ($error === '') {
|
||||
if (!tz_multi_registry_write($registryFile, $newRegistry)) {
|
||||
$error = 'Nu pot scrie registry.json. Verifica permisiunile directorului instances/.';
|
||||
} else {
|
||||
$registry = $newRegistry;
|
||||
$message = 'Instanțele au fost definite. Acum configurează fiecare server și pornește pașii de instalare.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$serverCount = isset($_POST['server_count']) ? max(1, min(100, (int) $_POST['server_count'])) : max(1, count($registry));
|
||||
if ($serverCount < 1) $serverCount = 1;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>TravianZ Multi-Instance Installer</title>
|
||||
<style>
|
||||
body{font-family:Arial,sans-serif;background:#eee;margin:0;padding:30px;color:#333}
|
||||
.wrap{max-width:1200px;margin:auto;background:#fff;padding:25px;border-radius:8px}
|
||||
h1{margin-top:0}.notice{padding:12px;margin:15px 0;background:#e8f5e9}.error{padding:12px;margin:15px 0;background:#ffebee}
|
||||
.toolbar{display:flex;gap:12px;align-items:center;margin:20px 0}.toolbar input{width:80px;padding:8px}
|
||||
.server{border:1px solid #ccc;padding:18px;margin:12px 0;border-radius:6px;background:#fafafa}
|
||||
.grid{display:grid;grid-template-columns:repeat(5,1fr);gap:12px}.field label{display:block;font-weight:bold;margin-bottom:5px}.field input{width:100%;box-sizing:border-box;padding:9px}
|
||||
button,.btn{padding:9px 15px;cursor:pointer;text-decoration:none;border:1px solid #aaa;background:#f6f6f6;color:#222;border-radius:4px;display:inline-block}
|
||||
.btn-primary{background:#2d6cdf;color:#fff;border-color:#2d6cdf}.btn-success{background:#2e7d32;color:#fff;border-color:#2e7d32}.btn-warning{background:#ef6c00;color:#fff;border-color:#ef6c00}
|
||||
.muted{color:#666;font-size:13px}.status{font-weight:bold}.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:15px}
|
||||
code{background:#f1f1f1;padding:2px 5px}.step{padding:4px 8px;border-radius:4px;background:#eee;margin-right:5px;font-size:12px}
|
||||
@media(max-width:900px){.grid{grid-template-columns:1fr 1fr}.wrap{padding:15px}}
|
||||
</style>
|
||||
<script>
|
||||
function buildServers() {
|
||||
const count = Math.max(1, Math.min(100, parseInt(document.getElementById('server_count').value || '1', 10)));
|
||||
document.getElementById('server_count_post').value = count;
|
||||
const box = document.getElementById('servers');
|
||||
const existing = {};
|
||||
Array.from(box.querySelectorAll('.server')).forEach(function(el){
|
||||
const id = el.querySelector('[data-field="id"]');
|
||||
if (id) existing[el.dataset.index] = {
|
||||
id: id.value,
|
||||
name: el.querySelector('[data-field="name"]').value,
|
||||
host: el.querySelector('[data-field="host"]').value,
|
||||
db: el.querySelector('[data-field="db"]').value,
|
||||
prefix: el.querySelector('[data-field="prefix"]').value
|
||||
};
|
||||
});
|
||||
box.innerHTML = '';
|
||||
for (let i = 1; i <= count; i++) {
|
||||
const old = existing[i] || {};
|
||||
const id = old.id || ('s' + i);
|
||||
const div = document.createElement('div');
|
||||
div.className = 'server';
|
||||
div.dataset.index = i;
|
||||
div.innerHTML = '<h3>Server ' + i + '</h3>' +
|
||||
'<div class="grid">' +
|
||||
'<div class="field"><label>Instance ID</label><input data-field="id" name="instance_id['+i+']" value="'+escapeHtml(id)+'" required></div>' +
|
||||
'<div class="field"><label>Server name</label><input data-field="name" name="instance_name['+i+']" value="'+escapeHtml(old.name || ('TravianZ '+id.toUpperCase()))+'" required></div>' +
|
||||
'<div class="field"><label>Hostname / domain</label><input data-field="host" name="instance_host['+i+']" value="'+escapeHtml(old.host || '')+'"></div>' +
|
||||
'<div class="field"><label>Database name</label><input data-field="db" name="instance_db['+i+']" value="'+escapeHtml(old.db || ('travian_'+id))+'" required></div>' +
|
||||
'<div class="field"><label>Table prefix</label><input data-field="prefix" name="instance_prefix['+i+']" value="'+escapeHtml(old.prefix || (id+'_'))+'" required></div>' +
|
||||
'</div>';
|
||||
box.appendChild(div);
|
||||
}
|
||||
}
|
||||
function escapeHtml(value) { return String(value).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); }
|
||||
window.addEventListener('DOMContentLoaded', function(){
|
||||
if (!document.querySelector('#servers .server')) buildServers();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<h1>TravianZ Multi-Instance Installer</h1>
|
||||
<p class="muted">O singură instalare TravianZ, mai multe lumi izolate. Fiecare instanță are propriul config.php, database, runtime și marker <code>installed</code>.</p>
|
||||
|
||||
<?php if ($message !== ''): ?><div class="notice"><?=htmlspecialchars($message, ENT_QUOTES, 'UTF-8')?></div><?php endif; ?>
|
||||
<?php if ($error !== ''): ?><div class="error"><?=htmlspecialchars($error, ENT_QUOTES, 'UTF-8')?></div><?php endif; ?>
|
||||
|
||||
<h2>1. Definește serverele</h2>
|
||||
<div class="toolbar">
|
||||
<label for="server_count"><strong>Număr servere:</strong></label>
|
||||
<input id="server_count" name="server_count_ui" type="number" min="1" max="100" value="<?=$serverCount?>" onchange="buildServers()" oninput="buildServers()">
|
||||
</div>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="server_count" id="server_count_post" value="<?=$serverCount?>">
|
||||
<input type="hidden" name="create_definitions" value="1">
|
||||
<div id="servers">
|
||||
<?php $i = 0; foreach ($registry as $instance): $i++; ?>
|
||||
<div class="server" data-index="<?=$i?>">
|
||||
<h3>Server <?=$i?></h3>
|
||||
<div class="grid">
|
||||
<div class="field"><label>Instance ID</label><input data-field="id" name="instance_id[<?=$i?>]" value="<?=htmlspecialchars($instance['id'], ENT_QUOTES, 'UTF-8')?>" required></div>
|
||||
<div class="field"><label>Server name</label><input data-field="name" name="instance_name[<?=$i?>]" value="<?=htmlspecialchars($instance['name'], ENT_QUOTES, 'UTF-8')?>" required></div>
|
||||
<div class="field"><label>Hostname / domain</label><input data-field="host" name="instance_host[<?=$i?>]" value="<?=htmlspecialchars($instance['host'] ?? '', ENT_QUOTES, 'UTF-8')?>"></div>
|
||||
<div class="field"><label>Database name</label><input data-field="db" name="instance_db[<?=$i?>]" value="<?=htmlspecialchars($instance['database'], ENT_QUOTES, 'UTF-8')?>" required></div>
|
||||
<div class="field"><label>Table prefix</label><input data-field="prefix" name="instance_prefix[<?=$i?>]" value="<?=htmlspecialchars($instance['prefix'], ENT_QUOTES, 'UTF-8')?>" required></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<button class="btn-primary" type="submit">Save server definitions</button>
|
||||
</form>
|
||||
|
||||
<h2 style="margin-top:35px">2. Install each world</h2>
|
||||
<?php if (!$registry): ?>
|
||||
<p class="muted">Nu există încă instanțe. Definește cel puțin un server mai sus.</p>
|
||||
<?php else: ?>
|
||||
<?php foreach ($registry as $id => $instance): ?>
|
||||
<div class="server">
|
||||
<h3><?=htmlspecialchars($instance['name'], ENT_QUOTES, 'UTF-8')?> <small>(<?=htmlspecialchars($id, ENT_QUOTES, 'UTF-8')?>)</small></h3>
|
||||
<p>
|
||||
<span class="step">DB: <?=htmlspecialchars($instance['database'], ENT_QUOTES, 'UTF-8')?></span>
|
||||
<span class="step">Prefix: <?=htmlspecialchars($instance['prefix'], ENT_QUOTES, 'UTF-8')?></span>
|
||||
<span class="status">Status: <?=htmlspecialchars($instance['status'] ?? 'defined', ENT_QUOTES, 'UTF-8')?></span>
|
||||
</p>
|
||||
<div class="actions">
|
||||
<?php if (($instance['status'] ?? '') !== 'installed'): ?><a class="btn btn-primary" href="config_instance.php?instance=<?=rawurlencode($id)?>">Configure server</a><?php endif; ?>
|
||||
<?php if (($instance['status'] ?? '') === 'configured'): ?>
|
||||
<form method="post" action="process_instance.php" style="display:inline"><input type="hidden" name="instance_id" value="<?=htmlspecialchars($id, ENT_QUOTES, 'UTF-8')?>"><input type="hidden" name="action" value="structure"><button class="btn-warning" type="submit">Create database structure</button></form>
|
||||
<?php elseif (($instance['status'] ?? '') === 'structure_created'): ?>
|
||||
<form method="post" action="process_instance.php" style="display:inline"><input type="hidden" name="instance_id" value="<?=htmlspecialchars($id, ENT_QUOTES, 'UTF-8')?>"><input type="hidden" name="action" value="world"><button class="btn-warning" type="submit">Create world data</button></form>
|
||||
<?php elseif (($instance['status'] ?? '') === 'world_created'): ?>
|
||||
<a class="btn btn-success" href="accounts_instance.php?instance=<?=rawurlencode($id)?>">Create admin / MultiHunter / Support accounts</a>
|
||||
<?php elseif (($instance['status'] ?? '') === 'installed'): ?>
|
||||
<span class="btn btn-success">Installed</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<p style="margin-top:30px"><a href="index.php">← Back to normal installer</a></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,288 +0,0 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename process_instance.php ##
|
||||
## Type : Multi-instance installation process ##
|
||||
## Project : TravianZ ##
|
||||
## Source code : https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
// don't let SQL time out when 30-500 seconds (depending on php.ini) is not enough
|
||||
@set_time_limit(0);
|
||||
|
||||
require_once dirname(__DIR__) . '/GameEngine/Instance/InstanceResolver.php';
|
||||
require_once dirname(__DIR__) . '/GameEngine/Instance/Instance.php';
|
||||
require_once dirname(__DIR__) . '/GameEngine/Instance/ConfigRouter.php';
|
||||
require_once dirname(__DIR__) . '/GameEngine/Instance/ConfigWriter.php';
|
||||
|
||||
final class TravianZInstanceInstallProcess
|
||||
{
|
||||
private string $root;
|
||||
private string $instancesFile;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->root = dirname(__DIR__);
|
||||
$this->instancesFile = $this->root . '/instances/registry.json';
|
||||
}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||
$this->fail('Invalid request method.');
|
||||
}
|
||||
|
||||
$instanceId = strtolower(trim((string) ($_POST['instance_id'] ?? '')));
|
||||
if (!TravianZInstanceResolver::isValid($instanceId)) {
|
||||
$this->fail('Invalid instance ID.');
|
||||
}
|
||||
|
||||
// Select this instance before Bootstrap/Database are loaded.
|
||||
putenv('TRAVIANZ_INSTANCE=' . $instanceId);
|
||||
|
||||
$action = (string) ($_POST['action'] ?? 'config');
|
||||
|
||||
try {
|
||||
switch ($action) {
|
||||
case 'config':
|
||||
$this->writeConfig($instanceId);
|
||||
break;
|
||||
|
||||
case 'structure':
|
||||
$this->loadInstanceBootstrap();
|
||||
$this->createStructure($instanceId);
|
||||
break;
|
||||
|
||||
case 'world':
|
||||
$this->loadInstanceBootstrap();
|
||||
$this->createWorld($instanceId);
|
||||
break;
|
||||
|
||||
case 'accounts':
|
||||
$this->loadInstanceBootstrap();
|
||||
$this->createAccounts($instanceId);
|
||||
break;
|
||||
|
||||
case 'finalize':
|
||||
$this->finalize($instanceId);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->fail('Unknown installation action.');
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
$this->fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the existing installer POST fields into the placeholders used
|
||||
* by constant_format.tpl. This deliberately mirrors the normal installer
|
||||
* naming convention, with aliases only where the old form uses a different
|
||||
* name (for example tzone -> STIMEZONE and paypal-email -> PAYPAL_EMAIL).
|
||||
*/
|
||||
private function buildReplacements(): array
|
||||
{
|
||||
$templatePath = $this->root . '/install/data/constant_format.tpl';
|
||||
$text = file_get_contents($templatePath);
|
||||
if ($text === false) {
|
||||
$this->fail('Cannot read installer configuration template.');
|
||||
}
|
||||
|
||||
preg_match_all('/%([A-Z0-9_]+)%/', $text, $matches);
|
||||
$placeholders = array_unique($matches[0] ?? []);
|
||||
|
||||
$aliases = [
|
||||
'%STIMEZONE%' => 'tzone',
|
||||
'%SERVERNAME%' => 'servername',
|
||||
'%SSTARTDATE%' => 'start_date',
|
||||
'%SSTARTTIME%' => 'start_time',
|
||||
'%PAYPAL_EMAIL%' => 'paypal-email',
|
||||
'%PAYPAL_CURRENCY%' => 'paypal-currency',
|
||||
'%PLUS_PACKAGE_A_GOLD%' => 'plus-a-gold',
|
||||
'%PLUS_PACKAGE_A_PRICE%' => 'plus-a-price',
|
||||
'%PLUS_PACKAGE_B_GOLD%' => 'plus-b-gold',
|
||||
'%PLUS_PACKAGE_B_PRICE%' => 'plus-b-price',
|
||||
'%PLUS_PACKAGE_C_GOLD%' => 'plus-c-gold',
|
||||
'%PLUS_PACKAGE_C_PRICE%' => 'plus-c-price',
|
||||
'%PLUS_PACKAGE_D_GOLD%' => 'plus-d-gold',
|
||||
'%PLUS_PACKAGE_D_PRICE%' => 'plus-d-price',
|
||||
'%PLUS_PACKAGE_E_GOLD%' => 'plus-e-gold',
|
||||
'%PLUS_PACKAGE_E_PRICE%' => 'plus-e-price',
|
||||
'%GP_LOCATE%' => 'gp_locate',
|
||||
'%CRONKEY%' => null,
|
||||
'%STARTTIME%' => null,
|
||||
'%ERROR%' => 'error',
|
||||
];
|
||||
|
||||
$defaults = [
|
||||
'%SERVERNAME%' => 'TravianZ', '%SPEED%' => '1', '%INCSPEED%' => '1', '%EVASIONSPEED%' => '1',
|
||||
'%TRADERCAP%' => '1', '%CRANNYCAP%' => '1', '%TRAPPERCAP%' => '1', '%STORAGE_MULTIPLIER%' => '1',
|
||||
'%MAX%' => '100', '%LANG%' => 'en', '%STIMEZONE%' => 'Europe/Bucharest', '%BEGINNER%' => '43200',
|
||||
'%REG_OPEN%' => 'true', '%TS_THRESHOLD%' => '20', '%MEDALINTERVAL%' => '0', '%GREAT_WKS%' => 'false',
|
||||
'%WW%' => 'false', '%SHOW_NATARS%' => 'false', '%NATARS_UNITS%' => '100', '%NATARS_SPAWN_TIME%' => '260',
|
||||
'%NATARS_WW_SPAWN_TIME%' => '260', '%NATARS_WW_BUILDING_PLAN_SPAWN_TIME%' => '260', '%NATARS_WW_START_DELAY%' => '10',
|
||||
'%NATURE_REGTIME%' => '43200', '%OASIS_WOOD_MULTIPLIER%' => '40', '%OASIS_CLAY_MULTIPLIER%' => '40',
|
||||
'%OASIS_IRON_MULTIPLIER%' => '40', '%OASIS_CROP_MULTIPLIER%' => '40', '%CRONLOOP%' => '300',
|
||||
'%CRONTICK%' => '60', '%CLEANUPREPORTS%' => '14', '%CLEANUPCHAT%' => '7', '%CLEANUPMESSAGES%' => '0',
|
||||
'%HEROBASEREGEN%' => '10', '%HEROSILVERPERGOLD%' => '10', '%HEROSILVERTOGOLD%' => '25',
|
||||
'%HERORESALL%' => '3', '%HERORESONE%' => '10', '%ERRORREPORT%' => '0', '%GP%' => 'false',
|
||||
'%GP_LOCATE%' => 'gpack/travian_default/', '%ALLIANCEBONUSES%' => 'false', '%PLUSSTATS%' => 'true',
|
||||
'%PLUSSTATSHOURS%' => '6', '%PLUSSTATSKEEP%' => '0', '%USRNMSPECIAL%' => 'true', '%USRNMMIN%' => '3',
|
||||
'%USRNMMAX%' => '15', '%PWMIN%' => '4', '%WWIMAGE%' => 'true', '%PROTECTEDPLAYERS%' => '',
|
||||
'%ASUPPMSGS%' => 'true', '%ARAIDS%' => 'false', '%ARANK%' => 'false', '%CONNECTT%' => '1',
|
||||
'%DOMAIN%' => '', '%HOMEPAGE%' => '', '%SERVER%' => '', '%LIMIT_MAILBOX%' => '0', '%MAX_MAILS%' => '100',
|
||||
'%DEMOLISH%' => 'true', '%BOX1%' => 'false', '%BOX2%' => 'false', '%BOX3%' => 'false', '%VILLAGE_EXPAND%' => '0',
|
||||
'%PLUS_TIME%' => '0', '%PLUS_PRODUCTION%' => '0', '%PAYPAL_EMAIL%' => '', '%PAYPAL_CURRENCY%' => 'EUR',
|
||||
'%PEACE%' => '0', '%T4_COMING%' => 'false',
|
||||
];
|
||||
|
||||
$replacements = [];
|
||||
foreach ($placeholders as $placeholder) {
|
||||
$field = $aliases[$placeholder] ?? strtolower(trim($placeholder, '%'));
|
||||
if ($field === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($_POST[$field]) && !is_array($_POST[$field])) {
|
||||
$value = (string) $_POST[$field];
|
||||
} elseif (array_key_exists($placeholder, $defaults)) {
|
||||
$value = (string) $defaults[$placeholder];
|
||||
} else {
|
||||
$value = '';
|
||||
}
|
||||
|
||||
if ($placeholder === '%STIMEZONE%') {
|
||||
$tz = explode(',', $value, 2);
|
||||
$value = $tz[1] ?? $value;
|
||||
}
|
||||
|
||||
$replacements[$placeholder] = $value;
|
||||
}
|
||||
|
||||
$replacements['%STARTTIME%'] = time();
|
||||
$replacements['%CRONKEY%'] = bin2hex(random_bytes(24));
|
||||
|
||||
$registry = $this->readRegistry();
|
||||
if (isset($registry[(string) $_POST['instance_id']])) {
|
||||
$instance = $registry[(string) $_POST['instance_id']];
|
||||
$replacements['%SERVERNAME%'] = (string) ($instance['name'] ?? $replacements['%SERVERNAME%']);
|
||||
$replacements['%SDB%'] = (string) ($instance['database'] ?? '');
|
||||
$replacements['%PREFIX%'] = (string) ($instance['prefix'] ?? '');
|
||||
}
|
||||
|
||||
return $replacements;
|
||||
}
|
||||
|
||||
private function writeConfig(string $instanceId): void
|
||||
{
|
||||
$path = TravianZInstanceConfigWriter::write($instanceId, $this->buildReplacements());
|
||||
$this->updateStatus($instanceId, 'configured', ['config' => $path, 'configured_at' => date('c')]);
|
||||
$this->redirect('multi.php?instance=' . rawurlencode($instanceId));
|
||||
}
|
||||
|
||||
private function loadInstanceBootstrap(): void
|
||||
{
|
||||
require_once $this->root . '/GameEngine/Instance/Bootstrap.php';
|
||||
}
|
||||
|
||||
private function createStructure(string $instanceId): void
|
||||
{
|
||||
global $database;
|
||||
require_once $this->root . '/GameEngine/Database.php';
|
||||
require_once $this->root . '/GameEngine/Admin/database.php';
|
||||
|
||||
$result = $database->createDbStructure();
|
||||
if ($result === false) $this->fail('Database structure creation failed.');
|
||||
if ($result === -1) $this->fail('Database structure already exists or installation requires attention.');
|
||||
|
||||
$this->updateStatus($instanceId, 'structure_created', ['structure_at' => date('c')]);
|
||||
$this->redirect('multi.php?instance=' . rawurlencode($instanceId));
|
||||
}
|
||||
|
||||
private function createWorld(string $instanceId): void
|
||||
{
|
||||
global $database;
|
||||
require_once $this->root . '/GameEngine/Database.php';
|
||||
require_once $this->root . '/GameEngine/Admin/database.php';
|
||||
|
||||
$result = $database->populateWorldData();
|
||||
if ($result === false) $this->fail('World data creation failed.');
|
||||
if ($result === -1) $this->fail('World data already exists or installation requires attention.');
|
||||
|
||||
$this->updateStatus($instanceId, 'world_created', ['world_at' => date('c')]);
|
||||
$this->redirect('multi.php?instance=' . rawurlencode($instanceId));
|
||||
}
|
||||
|
||||
private function createAccounts(string $instanceId): void
|
||||
{
|
||||
// accounts.php contains the canonical account/village provisioning logic.
|
||||
// The instance environment is already selected before this include, and
|
||||
// the account script now resolves its config path through TravianZInstance.
|
||||
require $this->root . '/install/include/accounts.php';
|
||||
$this->fail('Account installation did not redirect as expected.');
|
||||
}
|
||||
|
||||
private function finalize(string $instanceId): void
|
||||
{
|
||||
$registry = $this->readRegistry();
|
||||
if (!isset($registry[$instanceId])) $this->fail('Instance not found.');
|
||||
|
||||
$instancePath = $this->root . '/instances/' . $instanceId;
|
||||
if (!is_dir($instancePath) && !mkdir($instancePath, 0775, true) && !is_dir($instancePath)) {
|
||||
$this->fail('Cannot create instance directory.');
|
||||
}
|
||||
|
||||
if (file_put_contents($instancePath . '/installed', date('c') . PHP_EOL, LOCK_EX) === false) {
|
||||
$this->fail('Cannot create instance installed marker.');
|
||||
}
|
||||
|
||||
$this->updateStatus($instanceId, 'installed', ['installed_at' => date('c')]);
|
||||
$this->redirect('multi.php?instance=' . rawurlencode($instanceId));
|
||||
}
|
||||
|
||||
private function readRegistry(): array
|
||||
{
|
||||
if (!is_file($this->instancesFile)) return [];
|
||||
$data = json_decode((string) file_get_contents($this->instancesFile), true);
|
||||
return is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
private function updateStatus(string $instanceId, string $status, array $extra = []): void
|
||||
{
|
||||
$registry = $this->readRegistry();
|
||||
if (!isset($registry[$instanceId]) || !is_array($registry[$instanceId])) return;
|
||||
|
||||
$registry[$instanceId]['status'] = $status;
|
||||
$registry[$instanceId]['updated_at'] = date('c');
|
||||
foreach ($extra as $key => $value) $registry[$instanceId][$key] = $value;
|
||||
|
||||
$tmp = $this->instancesFile . '.tmp';
|
||||
if (file_put_contents($tmp, json_encode($registry, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL, LOCK_EX) === false) {
|
||||
$this->fail('Cannot update instance registry.');
|
||||
}
|
||||
if (!rename($tmp, $this->instancesFile)) {
|
||||
@unlink($tmp);
|
||||
$this->fail('Cannot activate instance registry update.');
|
||||
}
|
||||
}
|
||||
|
||||
private function redirect(string $location): void
|
||||
{
|
||||
header('Location: ' . $location);
|
||||
exit;
|
||||
}
|
||||
|
||||
private function fail(string $message): void
|
||||
{
|
||||
http_response_code(500);
|
||||
echo '<h1>TravianZ Multi-Instance Installer</h1>';
|
||||
echo '<p>' . htmlspecialchars($message, ENT_QUOTES, 'UTF-8') . '</p>';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
(new TravianZInstanceInstallProcess())->run();
|
||||
Reference in New Issue
Block a user