diff --git a/docs/GSP_INSTALLER.md b/docs/GSP_INSTALLER.md new file mode 100644 index 00000000..2300a570 --- /dev/null +++ b/docs/GSP_INSTALLER.md @@ -0,0 +1,118 @@ +# GSP Installer – Differences from Original OGP `install.php` + +## Overview + +`install.php` in this repository is a customized installer for the +**GSP (Game Server Panel)** maintained by WDS. It is based on the original +OGP installer at + +but has been adapted for the GSP/WDS environment. + +--- + +## Key differences + +### 1. Default table prefix: `gsp_` + +The original OGP installer defaults to `ogp_`. Our installer defaults to +`gsp_` (the `$table_prefix` form field pre-fills with `gsp_`). You may +change this during installation. + +### 2. Config file now includes `$db_port` + +The generated `includes/config.inc.php` includes a `$db_port` variable: + +```php +$db_host="HOST"; +$db_port="3306"; +$db_user="USER"; +$db_pass="PASSWORD"; +$db_name="DATABASE"; +$table_prefix="gsp_"; +$db_type="mysql"; +``` + +Existing config files that predate this installer and lack `$db_port` +continue to work because the parameter defaults to `NULL` (MySQL default +port 3306). + +### 3. MySQLi connection uses the port + +`includes/database_mysqli.php` – `OGPDatabaseMySQL::connect()` – now +accepts an optional `$db_port` argument and passes it to `mysqli_connect()`: + +```php +$this->link = mysqli_connect($db_host, $db_user, $db_pass, $db_name, $port); +``` + +`includes/helpers.php` – `createDatabaseConnection()` – likewise accepts +and forwards `$db_port`. + +All panel entry points (`home.php`, `index.php`, `ogp_api.php`, +`server_status.php`, `modules/billing/cron-shop.php`, +`modules/billing/includes/panel_bridge.php`) pass +`isset($db_port) ? $db_port : NULL` when calling +`createDatabaseConnection()`. + +### 4. Default admin account created automatically + +After modules are installed, the installer automatically creates an `admin` +account with password `admin` using the existing `OGPDatabaseMySQL::addUser()` +method (which stores passwords as `MD5`). If an admin user already exists it +is **not** duplicated. + +**Change the default password immediately after your first login.** + +### 5. No prerequisite checks + +Step 0 shows a welcome screen and language selector only. The original OGP +installer checks for required PHP extensions, Pear, etc. GSP skips those +checks because the deployment environment is pre-validated by our bootstrap +scripts. + +### 6. All modules installed automatically + +Every directory found under `modules/` is installed via +`install_module()`. Prerequisite failures for individual modules are treated +as warnings (not hard failures) so that the overall installation succeeds +even if optional dependencies are missing. + +### 7. `ogp_` → `gsp_` table migration (optional, safe) + +If the database already contains tables prefixed with `ogp_`: + +* For each `ogp_X` table, if the corresponding `gsp_X` table does **not** + exist, it is renamed to `gsp_X`. +* If `gsp_X` already exists, the rename is skipped silently. +* The installer never aborts due to pre-existing tables. + +This allows upgrading an existing OGP installation to GSP without losing data. + +### 8. Branding + +The installer title and default site settings reference **GSP – Game Server +Panel** and **WDS** instead of "Open Game Panel". + +--- + +## Running the installer + +1. Upload/deploy the panel files. +2. Ensure `includes/config.inc.php` is writable (or does not exist yet). +3. Open `https://yoursite/install.php` in a browser. +4. Select your language and click **Next**. +5. Enter database credentials and click **Next**. +6. The installer writes config, migrates tables (if needed), installs + modules, and creates the default admin account. +7. **Delete `install.php`** from the server after installation. +8. Optionally `chmod 644 includes/config.inc.php` for security. + +--- + +## Rollback + +* To re-run the installer, simply navigate to `install.php` again. +* If the wrong prefix was chosen, edit `includes/config.inc.php` manually or + re-run `install.php`. +* Renamed (`ogp_` → `gsp_`) tables can be manually renamed back with + `RENAME TABLE gsp_X TO ogp_X` in MySQL. diff --git a/home.php b/home.php index d499283c..d695f86c 100644 --- a/home.php +++ b/home.php @@ -39,7 +39,7 @@ define("CONFIG_FILE","includes/config.inc.php"); require_once CONFIG_FILE; // Connect to the database server and select database. -$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix); +$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : NULL); // Load languages. include_once("includes/lang.php"); diff --git a/includes/database_mysqli.php b/includes/database_mysqli.php index f3f5e289..2a2b2886 100644 --- a/includes/database_mysqli.php +++ b/includes/database_mysqli.php @@ -52,7 +52,7 @@ class OGPDatabaseMySQL extends OGPDatabase /// \return -11 When connection to database could not be established /// \return -12 When database was not valid. /// \return -99 When mysql php module is not available. - public function connect($db_host, $db_user, $db_pass, $db_name, $table_prefix = NULL) { + public function connect($db_host, $db_user, $db_pass, $db_name, $table_prefix = NULL, $db_port = NULL) { if ( !extension_loaded("mysqli") ) return -99; @@ -62,7 +62,9 @@ class OGPDatabaseMySQL extends OGPDatabase if ( $db_host === NULL ) return -1; - $this->link = mysqli_connect( $db_host, $db_user, $db_pass, $db_name ); + // Use explicit port when provided; otherwise fall back to MySQL default (3306). + $port = ($db_port !== NULL && $db_port !== '') ? (int)$db_port : NULL; + $this->link = mysqli_connect( $db_host, $db_user, $db_pass, $db_name, $port ); if ( $this->link === FALSE ) return -11; diff --git a/includes/helpers.php b/includes/helpers.php index 50f918ba..e110f5e1 100644 --- a/includes/helpers.php +++ b/includes/helpers.php @@ -45,7 +45,7 @@ if(file_exists(__DIR__ . "/lang.php")){ /// \return the database object when the creation was successfull. /// \return FALSE if database type was invalid. /// \return negative value in case of error -function createDatabaseConnection($db_type,$db_host,$db_user,$db_pass,$db_name,$table_prefix) +function createDatabaseConnection($db_type,$db_host,$db_user,$db_pass,$db_name,$table_prefix,$db_port=NULL) { if ( $db_type == "mysql" ) { @@ -54,7 +54,7 @@ function createDatabaseConnection($db_type,$db_host,$db_user,$db_pass,$db_name,$ else die("

OGP requires the mysqli PHP extension. Please install it, and then try again.

"); $database = new OGPDatabaseMysql(); - $connect_value = $database->connect($db_host,$db_user,$db_pass,$db_name,$table_prefix); + $connect_value = $database->connect($db_host,$db_user,$db_pass,$db_name,$table_prefix,$db_port); if ($connect_value === TRUE) return $database; diff --git a/index.php b/index.php index e1713bf0..89ffcb12 100644 --- a/index.php +++ b/index.php @@ -56,7 +56,7 @@ if ( '' == file_get_contents(CONFIG_FILE) ) { require_once CONFIG_FILE; // Connect to the database server and select database. -$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix); +$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : NULL); // Load languages. include_once("includes/lang.php"); diff --git a/install.php b/install.php new file mode 100644 index 00000000..0064e1cb --- /dev/null +++ b/install.php @@ -0,0 +1,398 @@ +", " "); + $replace = array(""", "'", "\", """, "'", "<", ">", " "); + $text = str_replace($search, $replace, $text); + return $text; +} + +session_start(); + +if (!isset($_SESSION['users_lang'])) + $_SESSION['users_lang'] = "English"; + +if (isset($_GET['localeset'])) + $_SESSION['users_lang'] = $_GET['localeset']; + +require_once("includes/helpers.php"); +require_once("includes/view.php"); +require_once("includes/lang.php"); +require_once("includes/html_functions.php"); +require_once("includes/functions.php"); +ogpLang(); + +$view = new OGPView(); +$view->setCharset(get_lang('lang_charset')); + +?> + + +
+".get_lang('install_lang')."
"; + echo "\n"; + $counter = 0; + for ($i = 0; $i < count($locale_files); $i++) { + if ($counter != 0 && ($counter % $columns == 0)) echo "\n\n"; + echo "\n"; + $counter++; + } + echo "\n
"; + if ($locale_files[$i] == $_SESSION['users_lang']) + echo "
  • ".$locale_files[$i]."
  • "; + else + echo "
  • ".htmlspecialchars($locale_files[$i])."
  • "; + echo "
    \n"; + + echo "
    GSP / WDS Panel Installer
    "; + echo "

    Welcome to the GSP (Game Server Panel) installer, maintained by WDS.

    "; + echo "

    GSP is a heavily customized fork of OGP. This installer will:

    "; + echo ""; + echo "

    ".get_lang('next')."

    "; + echo "\n"; + } + + // ---------------------------------------------------------------- + // Step 1 – Database settings form + // ---------------------------------------------------------------- + elseif ($step == "1") { + if (is_readable('includes/config.inc.php')) + require_once "includes/config.inc.php"; + + echo "
    \n"; + echo "
    "; + echo "\n"; + echo ""; + echo ""; + + // Host + $OS = strtoupper(substr(PHP_OS, 0, 3)); + $default_host = ($OS === 'WIN' || $OS === 'CYG') ? "127.0.0.1" : "localhost"; + echo " + "; + + // Port (GSP addition) + echo " + "; + + // User + echo " + "; + + // Password + echo " + "; + + // Name + echo " + "; + + // Prefix – default gsp_ + echo " + "; + + echo "
    ".get_lang('database_settings')."
    ".get_lang('database_type').":MySQL
    ".get_lang('database_hostname').":
    Database Port:
    ".get_lang('database_username').":
    ".get_lang('database_password').":
    ".get_lang('database_name').":
    ".get_lang('database_prefix').":
    \n"; + echo "

    "; + echo "

    ".get_lang('back')."

    "; + echo "
    \n"; + } + + // ---------------------------------------------------------------- + // Step 2 – Write config, migrate tables, install modules, create admin + // ---------------------------------------------------------------- + elseif ($step == "2") { + echo "
    \n"; + + if (!isset($_POST['db_host'])) { + print_failure("No form data received. Please go back and fill in the database settings."); + echo "

    ".get_lang('back')."

    "; + echo "
    \n"; + return; + } + + $db_host = stripinput($_POST['db_host']); + $db_port = stripinput($_POST['db_port']); + $db_user = stripinput($_POST['db_user']); + $db_pass = stripinput($_POST['db_pass']); + $db_name = stripinput($_POST['db_name']); + $table_prefix = stripinput($_POST['table_prefix']); + $db_type = "mysql"; + + // Default prefix to gsp_ if empty + if (empty($table_prefix)) $table_prefix = "gsp_"; + // Default port to 3306 if empty + if (empty($db_port)) $db_port = "3306"; + + // --- Write config.inc.php --- + $config = ""; + + $temp = @fopen("includes/config.inc.php", "w"); + if (!@fwrite($temp, $config)) { + print_failure(get_lang('unable_to_write_config')); + echo "

    ".get_lang('back')."

    "; + fclose($temp); + echo "\n"; + return; + } + fclose($temp); + print_success(get_lang('config_written')); + + // --- Connect to database using port --- + $db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, (int)$db_port); + $error_text = ""; + if (get_db_error_text($db, $error_text)) { + print_failure($error_text); + echo "

    ".get_lang('back')."

    "; + echo "\n"; + return; + } + + // --- Optional ogp_ → gsp_ migration --- + gsp_migrate_tables($db, $table_prefix); + + // --- Create base module management tables --- + $db->query("DROP TABLE IF EXISTS `".$table_prefix."modules`"); + $db->query("CREATE TABLE IF NOT EXISTS `".$table_prefix."modules` ( + `id` smallint(5) unsigned NOT NULL auto_increment, + `title` varchar(100) NOT NULL default '', + `folder` varchar(100) NOT NULL default '', + `version` varchar(10) NOT NULL default '0', + `db_version` int(10) NOT NULL default '0', + PRIMARY KEY (`id`), + UNIQUE KEY `folder` (`folder`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;"); + + $db->query("DROP TABLE IF EXISTS `".$table_prefix."module_menus`"); + $db->query("CREATE TABLE IF NOT EXISTS `".$table_prefix."module_menus` ( + `module_id` int(11) NOT NULL COMMENT 'This references to modules.id', + `subpage` varchar(64) NOT NULL default '', + `group` varchar(32) NOT NULL, + `menu_name` varchar(128) NOT NULL, + `pos` INT UNSIGNED NOT NULL, + PRIMARY KEY (`module_id`, `subpage`, `group`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;"); + + // --- Install all modules --- + require_once("modules/modulemanager/module_handling.php"); + @add_lang_module('modulemanager'); + $modules = list_available_modules(); + + // Install modulemanager first + if (in_array('modulemanager', $modules)) { + gsp_install_module($db, 'modulemanager'); + } + + foreach ($modules as $module) { + if ($module == 'modulemanager') continue; + gsp_install_module($db, $module); + } + print_success(get_lang('database_created')); + + // --- Default site settings --- + $site_settings = array( + "title" => "GSP - Game Server Panel", + "slogan" => get_lang('slogan'), + "ogp_version" => "0", + "version_type" => "GSP", + "theme" => "Revolution", + "welcome_title" => "1", + "welcome_title_message"=> "".get_lang('default_welcome_title_message')."", + "page_auto_refresh" => "1", + ); + $db->setSettings($site_settings); + + // --- Auto-create default admin user --- + $existing_admin = $db->getUser('admin'); + if (!$existing_admin) { + $db->addUser('admin', 'admin', 'admin', 'admin@localhost'); + print_success("Default admin account created (username: admin, password: admin)."); + } else { + echo "

    Admin user already exists – skipped creation.

    "; + } + + // --- Update game configs --- + updateGameConfigsPostInstall(); + + echo "

    ".get_lang('remove_install_and_secure_config')."

    "; + echo "

    Change the default admin password after your first login!

    "; + echo "

    ".get_lang('go_to_panel')."

    "; + echo "\n"; + echo "\n"; + } + + else { + echo "

    Unknown step. Start over

    "; + } +} + +/** + * Install a single module, treating prerequisite failures as warnings + * (not hard failures) per GSP policy: "Do not run prerequisite checks – + * our environment is customized." + * + * Returns the same values as install_module(), but the caller does not + * abort the overall install when -2 is returned. + */ +function gsp_install_module($db, $module) { + $result = install_module($db, $module, FALSE); + // -1 = module.php missing or malformed (genuine hard error) + // -2 = prereq missing or DB query failed; treat as warning + // 0 = already installed + // 1 = installed successfully + // 2 = optional, skipped + if ($result === -1) { + // Already printed by install_module(); just note it. + } + return $result; +} + +/** + * Optional ogp_ → configured-prefix migration. + * + * Rules: + * - If a table named ogp_X exists AND the corresponding prefix_X does NOT + * exist, rename ogp_X -> prefix_X. + * - If prefix_X already exists, skip that table (never fail). + * - If no ogp_ tables exist at all, do nothing. + */ +function gsp_migrate_tables($db, $table_prefix) { + if ($table_prefix === 'ogp_') { + // Already using ogp_ prefix – nothing to migrate. + return; + } + + // Fetch all tables starting with ogp_ + $rows = $db->resultQuery("SHOW TABLES LIKE 'ogp\\_%'"); + if (!$rows || !is_array($rows)) return; + + $renamed = 0; + $skipped = 0; + foreach ($rows as $row) { + $ogp_table = array_values($row)[0]; // e.g. ogp_users + $suffix = substr($ogp_table, 4); // strip leading "ogp_" + $new_table = $table_prefix . $suffix; + + // Check if destination table already exists + $exists = $db->resultQuery("SHOW TABLES LIKE '".str_replace("_", "\\_", $new_table)."'"); + if ($exists && is_array($exists) && count($exists) > 0) { + $skipped++; + continue; + } + + // Rename + $ok = $db->query("RENAME TABLE `".mysqli_real_escape_string_compat($ogp_table)."` TO `".mysqli_real_escape_string_compat($new_table)."`"); + if ($ok) { + $renamed++; + } + } + + if ($renamed > 0) + print_success("Migrated {$renamed} table(s) from ogp_ to {$table_prefix} prefix."); + if ($skipped > 0) + echo "

    {$skipped} table(s) already existed under the {$table_prefix} prefix – skipped.

    "; +} + +/** + * Helper to escape a table name for use in RENAME TABLE. + * We can't use $db->realEscapeSingle() easily for identifiers here, + * so we strip everything except alphanumeric and underscores. + */ +function mysqli_real_escape_string_compat($identifier) { + return preg_replace('/[^a-zA-Z0-9_]/', '', $identifier); +} + +$view->printView(); +?> diff --git a/modules/billing/cron-shop.php b/modules/billing/cron-shop.php index 6b3a4fce..62d2afdf 100644 --- a/modules/billing/cron-shop.php +++ b/modules/billing/cron-shop.php @@ -51,7 +51,7 @@ require_once("modules/config_games/server_config_parser.php"); require_once("includes/lib_remote.php"); require_once CONFIG_FILE; // Connect to the database server and select database. -$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix); +$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : NULL); $panel_settings = $db->getSettings(); if( isset($panel_settings['time_zone']) && $panel_settings['time_zone'] != "" ) diff --git a/modules/billing/includes/panel_bridge.php b/modules/billing/includes/panel_bridge.php index 477c0f01..ccfdf930 100644 --- a/modules/billing/includes/panel_bridge.php +++ b/modules/billing/includes/panel_bridge.php @@ -66,7 +66,7 @@ if (!function_exists('billing_panel_bootstrap')) { return null; } - $panelDb = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix); + $panelDb = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : NULL); if (!($panelDb instanceof OGPDatabase)) { error_log('billing_panel_bootstrap: failed to connect to panel database'); return null; diff --git a/ogp_api.php b/ogp_api.php index b7f0d880..625349a1 100644 --- a/ogp_api.php +++ b/ogp_api.php @@ -97,7 +97,7 @@ if(function_exists($function)) // API tokens table define("API_TABLE", $table_prefix."api_tokens"); // Connect to the database server and select database. - $db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix); + $db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : NULL); $settings = $db->getSettings(); if(!is_authorized()) diff --git a/server_status.php b/server_status.php index 786ac979..62b78d1b 100644 --- a/server_status.php +++ b/server_status.php @@ -41,7 +41,7 @@ require_once CONFIG_FILE; require_once('includes/lib_remote.php'); // Connect to the database server and select database. -$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix); +$db = createDatabaseConnection($db_type, $db_host, $db_user, $db_pass, $db_name, $table_prefix, isset($db_port) ? $db_port : NULL); // Load languages. include_once("includes/lang.php");