query() / $db->resultQuery() // replaces with the configured table prefix (e.g. 'gsp_') via str_replace at // runtime. Using it directly in string literals below is intentional and is // the same mechanism used everywhere else in the panel. $tbl_profiles = 'OGP_DB_PREFIXworkshop_game_profiles'; // column_name => column definition (no AFTER clause for portability) // $col is always a value from this hardcoded array — not from user input. $columns = array( 'steam_app_id' => "VARCHAR(32) NOT NULL DEFAULT ''", 'steam_login_required' => "TINYINT(1) NOT NULL DEFAULT 0", 'steamcmd_login_mode' => "ENUM('anonymous','account') NOT NULL DEFAULT 'anonymous'", 'steamcmd_path' => "VARCHAR(512) NOT NULL DEFAULT ''", 'folder_naming_format' => "ENUM('@%mod_name%','@%workshop_id%','custom') NOT NULL DEFAULT '@%workshop_id%'", 'mod_launch_param' => "VARCHAR(512) NOT NULL DEFAULT ''", 'mod_separator' => "ENUM('semicolon','comma','space') NOT NULL DEFAULT 'semicolon'", 'copy_keys' => "TINYINT(1) NOT NULL DEFAULT 0", 'key_source_path' => "TEXT NULL", 'key_dest_path' => "TEXT NULL", 'pre_update_script' => "TEXT NULL", 'post_update_script' => "TEXT NULL", 'validation_notes' => "TEXT NULL", ); foreach ($columns as $col => $def) { // INFORMATION_SCHEMA.COLUMNS always returns one row for COUNT(*), // so resultQuery returns an array (never FALSE for this query form). // Escape $col when embedding it in the SQL string literal. $safe_col = $db->realEscapeSingle($col); $check = $db->resultQuery( "SELECT COUNT(*) AS n FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '" . $tbl_profiles . "' AND COLUMN_NAME = '" . $safe_col . "'" ); // If n > 0 the column already exists; skip it. if ($check !== false && isset($check[0]['n']) && (int)$check[0]['n'] > 0) { continue; } // $col is backtick-quoted so it is safe as an identifier. if (!$db->query( "ALTER TABLE `" . $tbl_profiles . "` ADD COLUMN `" . $col . "` " . $def )) { return false; } } return true; }, // Add custom_folder to server_workshop_mods (MySQL 5.7 safe). function($db) { // See note above: 'OGP_DB_PREFIX' is replaced by str_replace at runtime. $tbl_mods = 'OGP_DB_PREFIXserver_workshop_mods'; $check = $db->resultQuery( "SELECT COUNT(*) AS n FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '" . $tbl_mods . "' AND COLUMN_NAME = 'custom_folder'" ); if ($check !== false && isset($check[0]['n']) && (int)$check[0]['n'] > 0) { return true; // Column already exists. } return (bool)$db->query( "ALTER TABLE `" . $tbl_mods . "` ADD COLUMN `custom_folder` VARCHAR(255) NOT NULL DEFAULT ''" ); }, // New server-level settings table (CREATE IF NOT EXISTS is safe to re-run). "CREATE TABLE IF NOT EXISTS `".OGP_DB_PREFIX."server_workshop_settings` ( `home_id` INT NOT NULL, `workshop_enabled` TINYINT(1) NOT NULL DEFAULT 0, `profile_id` INT NULL, `update_mode` ENUM('manual','scheduled','on_restart') NOT NULL DEFAULT 'manual', `restart_behavior` ENUM('none','queue','stop_update_start') NOT NULL DEFAULT 'none', `update_queued` TINYINT(1) NOT NULL DEFAULT 0, `last_update_status` VARCHAR(20) NOT NULL DEFAULT '', `last_update_error` TEXT NULL, `last_update_time` DATETIME NULL, `last_success_time` DATETIME NULL, `updated_at` DATETIME NULL, PRIMARY KEY (`home_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" );