Commit 38f49c91 authored by Nemo Ma's avatar Nemo Ma

FEAT: Add reverse megration

parent cd36b1ec
...@@ -99,26 +99,26 @@ ...@@ -99,26 +99,26 @@
// 主从数据库配置 (Master-Slave Database Configuration) // 主从数据库配置 (Master-Slave Database Configuration)
// 以下配置项不能通过游戏后台修改,只能手动编辑或通过安装脚本配置 // 以下配置项不能通过游戏后台修改,只能手动编辑或通过安装脚本配置
$slave_level = 0; // 从服务器级别: 0=主服务器, 1=从服务器(手动迁移), 2=从服务器(自动同步), 3=从服务器(直接使用主数据库) $slave_level = 0; // 从服务器级别: -1=反向迁移模式(本地主→远端从), 0=主服务器, 1=从服务器(手动迁移), 2=从服务器(自动同步), 3=从服务器(直接使用主数据库)
// Slave level: 0=master, 1=slave(manual migration), 2=slave(auto sync), 3=slave(direct master db) // Slave level: -1=reverse migration(local master→remote slave), 0=master, 1=slave(manual migration), 2=slave(auto sync), 3=slave(direct master db)
$master_dbhost = ''; // 主数据库服务器地址 (仅在slave_level>0时有效) $master_dbhost = ''; // 目标数据库服务器地址 (slave_level>0时为主数据库,slave_level=-1时为远端从数据库)
// Master database server (only valid when slave_level>0) // Target database server (master db when slave_level>0, remote slave db when slave_level=-1)
$master_dbuser = ''; // 主数据库用户名 (仅在slave_level>0时有效) $master_dbuser = ''; // 目标数据库用户名 (slave_level>0时为主数据库,slave_level=-1时为远端从数据库)
// Master database username (only valid when slave_level>0) // Target database username (master db when slave_level>0, remote slave db when slave_level=-1)
$master_dbpw = ''; // 主数据库密码 (仅在slave_level>0时有效) $master_dbpw = ''; // 目标数据库密码 (slave_level>0时为主数据库,slave_level=-1时为远端从数据库)
// Master database password (only valid when slave_level>0) // Target database password (master db when slave_level>0, remote slave db when slave_level=-1)
$master_dbname = ''; // 主数据库名 (仅在slave_level>0时有效) $master_dbname = ''; // 目标数据库名 (slave_level>0时为主数据库,slave_level=-1时为远端从数据库)
// Master database name (only valid when slave_level>0) // Target database name (master db when slave_level>0, remote slave db when slave_level=-1)
$master_tablepre = ''; // 主数据库表前缀 (仅在slave_level>0时有效) $master_tablepre = ''; // 目标数据库表前缀 (slave_level>0时为主数据库,slave_level=-1时为远端从数据库)
// Master database table prefix (only valid when slave_level>0) // Target database table prefix (master db when slave_level>0, remote slave db when slave_level=-1)
$master_server_name = ''; // 主服务器名称 (用于显示) $master_server_name = ''; // 目标服务器名称 (用于显示,slave_level>0时为主服务器,slave_level=-1时为远端从服务器)
// Master server name (for display) // Target server name (for display, master server when slave_level>0, remote slave server when slave_level=-1)
// ============================================================================ // ============================================================================
......
修复数据库表不存在的错误
时间:2025年1月12日
问题描述:
在访问 user.php 时出现 MySQL 错误:
- SQL语句:SELECT * FROM acbra3_user_sync WHERE target_username = 'Amarillo_NMC'
- 数据库错误:1146 Table 'acdts.acbra3_user_sync' doesn't exist
问题原因:
1. `get_user_sync_status()` 函数直接查询 user_sync 表,但没有确保表存在
2. `get_user_sync_info()` 函数也有同样的问题
3. `get_reverse_migration_status()` 函数也可能遇到相同问题
4. 表创建函数中使用了不兼容的 'SILENT' 参数
修复内容:
### 1. 函数修复
#### 1.1 get_user_sync_status() 函数
**修复前:**
```php
function get_user_sync_status($username) {
global $db, $gtablepre;
$username = addslashes($username);
$result = $db->query("SELECT * FROM {$gtablepre}user_sync WHERE target_username = '$username'");
// ...
}
```
**修复后:**
```php
function get_user_sync_status($username) {
global $db, $gtablepre;
// 确保同步表存在
create_sync_table_if_not_exists();
$username = addslashes($username);
$result = $db->query("SELECT * FROM {$gtablepre}user_sync WHERE target_username = '$username'");
// ...
}
```
#### 1.2 get_user_sync_info() 函数
**修复前:**
```php
function get_user_sync_info($master_username) {
global $db, $gtablepre;
$master_username = addslashes($master_username);
$result = $db->query("SELECT * FROM {$gtablepre}user_sync WHERE master_username = '$master_username'");
// ...
}
```
**修复后:**
```php
function get_user_sync_info($master_username) {
global $db, $gtablepre;
// 确保同步表存在
create_sync_table_if_not_exists();
$master_username = addslashes($master_username);
$result = $db->query("SELECT * FROM {$gtablepre}user_sync WHERE master_username = '$master_username'");
// ...
}
```
#### 1.3 get_reverse_migration_status() 函数
**修复前:**
```php
function get_reverse_migration_status($username) {
global $db, $gtablepre;
$username = addslashes($username);
$result = $db->query("SELECT * FROM {$gtablepre}reverse_migration WHERE target_username = '$username'");
// ...
}
```
**修复后:**
```php
function get_reverse_migration_status($username) {
global $db, $gtablepre;
// 确保反向迁移表存在
create_reverse_migration_table_if_not_exists();
$username = addslashes($username);
$result = $db->query("SELECT * FROM {$gtablepre}reverse_migration WHERE target_username = '$username'");
// ...
}
```
### 2. 表创建函数修复
#### 2.1 create_sync_table_if_not_exists() 函数
**修复前:**
```php
$result = $db->query("SHOW TABLES LIKE '$table_name'", 'SILENT');
if(!$db->num_rows($result)) {
// 创建表
}
```
**修复后:**
```php
$result = $db->query("SHOW TABLES LIKE '$table_name'");
if(!$result || !$db->num_rows($result)) {
// 创建表
}
```
#### 2.2 create_reverse_migration_table_if_not_exists() 函数
**修复前:**
```php
$result = $db->query("SHOW TABLES LIKE '{$gtablepre}reverse_migration'");
if(!$db->num_rows($result)) {
// 创建表
}
```
**修复后:**
```php
$result = $db->query("SHOW TABLES LIKE '{$gtablepre}reverse_migration'");
if(!$result || !$db->num_rows($result)) {
// 创建表
}
```
### 3. 修复的技术要点
#### 3.1 自动表创建
- 所有查询函数在执行前都会确保相关表存在
- 避免了手动创建表的需要
- 提高了系统的健壮性
#### 3.2 错误处理改进
- 移除了不兼容的 'SILENT' 参数
- 添加了 `!$result` 检查,处理查询失败的情况
- 确保在各种数据库环境下都能正常工作
#### 3.3 表结构定义
**user_sync 表:**
```sql
CREATE TABLE `{$gtablepre}user_sync` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`target_username` char(15) NOT NULL DEFAULT '',
`master_username` char(15) NOT NULL DEFAULT '',
`sync_time` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `target_username` (`target_username`),
KEY `master_username` (`master_username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
```
**reverse_migration 表:**
```sql
CREATE TABLE `{$gtablepre}reverse_migration` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`target_username` char(15) NOT NULL DEFAULT '',
`master_username` char(15) NOT NULL DEFAULT '',
`sync_time` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `target_username` (`target_username`),
KEY `master_username` (`master_username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
```
### 4. 修复后的效果
#### 4.1 用户体验改进
- 用户访问 user.php 不再出现数据库错误
- 主从同步功能可以正常显示和使用
- 反向迁移功能可以正常显示和使用
#### 4.2 系统稳定性
- 自动创建必要的数据库表
- 避免了因表不存在导致的系统错误
- 提高了部署的便利性
#### 4.3 兼容性
- 移除了可能不兼容的数据库查询参数
- 增强了错误处理机制
- 适用于不同的 MySQL 版本和配置
### 5. 部署验证
#### 5.1 验证步骤
1. 访问 user.php 页面
2. 检查是否正常加载用户界面
3. 验证主从同步功能是否显示
4. 验证反向迁移功能是否显示
5. 检查数据库中是否自动创建了相关表
#### 5.2 预期结果
- 页面正常加载,无数据库错误
- 根据 slave_level 配置正确显示相应功能
- 数据库中自动创建 user_sync 和 reverse_migration 表
- 所有功能可以正常使用
这个修复确保了主从同步和反向迁移功能在首次部署时能够正常工作,无需手动创建数据库表,提高了系统的易用性和稳定性。
修正反向迁移身份验证逻辑
时间:2025年1月12日
问题描述:
之前的实现在身份验证方面存在逻辑错误,没有正确理解反向迁移的身份验证需求:
**错误理解:**
- 用户需要输入本地用户名和密码进行验证
- 但用户访问user页面时已经通过本地登录验证
**正确理解:**
- 用户已经在本地服务器登录(本地身份已验证)
- 要推送数据到远端从服务器,需要在远端从服务器有对应的账户
- 用户需要输入的是远端从服务器的用户名和密码,用于在远端服务器进行身份验证
修正内容:
### 1. 身份验证逻辑修正
#### 1.1 核心函数参数修正 (include/masterslave.func.php)
**修正前:**
```php
function reverse_migrate_user($username, $password, $target_username = null)
// 验证本地用户名和密码
```
**修正后:**
```php
function reverse_migrate_user($local_username, $remote_username, $remote_password, $target_username = null)
// $local_username: 本地用户名(已登录用户)
// $remote_username: 远端从服务器用户名
// $remote_password: 远端从服务器密码
```
#### 1.2 验证流程修正
**修正前:**
1. 验证本地数据库中的用户名和密码
2. 读取本地用户数据
3. 推送到远端
**修正后:**
1. 读取本地用户数据(本地用户已通过登录验证)
2. 连接远端从数据库
3. 验证远端从服务器的用户身份
4. 推送本地数据到远端
### 2. 界面文案修正
#### 2.1 用户界面 (templates/default/user.htm)
**修正前:**
- 本地用户名(只读)
- 本地密码
**修正后:**
- 远端用户名:在{$master_server_name}的用户名
- 远端密码:在{$master_server_name}的密码
#### 2.2 管理界面 (templates/default/admin_urlist.htm)
**修正前:**
- 本地用户密码
**修正后:**
- 远端用户名:远端从服务器用户名
- 远端密码:远端从服务器密码
#### 2.3 说明文字修正
**修正前:**
"验证本地身份,然后推送数据到远端从服务器"
**修正后:**
"需要远端服务器的有效账户进行身份验证"
### 3. 代码调用修正
#### 3.1 用户端调用 (user.php)
**修正前:**
```php
$migrate_result = reverse_migrate_user($master_username, md5($master_password), $cuser);
```
**修正后:**
```php
$migrate_result = reverse_migrate_user($cuser, $remote_username, md5($remote_password));
```
#### 3.2 管理端调用 (include/admin/urlist.php)
**修正前:**
```php
$migrate_result = reverse_migrate_user($username, md5($master_password), $username);
```
**修正后:**
```php
$migrate_result = reverse_migrate_user($username, $remote_username, md5($master_password));
```
### 4. 验证逻辑实现
#### 4.1 远端身份验证
```php
// 验证远端从服务器的用户身份
$remote_auth_result = $slave_db->query("SELECT * FROM {$master_tablepre}users WHERE username = '$remote_username' AND password = '$remote_password'");
if(!$slave_db->num_rows($remote_auth_result)) {
return array('success' => false, 'message' => '远端从服务器身份验证失败:用户名或密码错误');
}
```
#### 4.2 数据推送流程
1. 本地用户已登录(身份已验证)
2. 读取本地用户数据
3. 连接远端从数据库
4. 验证远端用户身份
5. 推送本地数据到远端
6. 记录迁移信息
### 5. 用户体验改进
#### 5.1 表单设计
- 明确标识"远端用户名"和"远端密码"
- 提供清晰的占位符文本
- 添加详细的操作说明
#### 5.2 错误提示
- 区分远端连接错误和身份验证错误
- 提供具体的错误原因
- 指导用户如何解决问题
#### 5.3 确认对话框
**修正前:**
"确定要将本地账户数据推送到远端从服务器吗?"
**修正后:**
"确定要将本地账户数据推送到远端从服务器吗?需要使用远端服务器的有效账户进行身份验证。本地数据不会受影响。"
### 6. 测试文件修正
#### 6.1 测试参数修正
**修正前:**
- 本地用户名
- 本地密码
**修正后:**
- 本地用户名
- 远端用户名
- 远端密码
- 目标用户名(可选)
#### 6.2 测试流程修正
1. 输入本地用户名(数据源)
2. 输入远端用户名和密码(身份验证)
3. 执行反向迁移测试
4. 验证推送结果
### 7. 安全性考虑
#### 7.1 身份验证安全
- 远端密码在传输前进行MD5加密
- 验证远端用户身份后才允许数据推送
- 记录所有迁移操作的日志
#### 7.2 数据安全
- 本地数据只读,不会被修改
- 远端数据根据验证结果进行创建或更新
- 完整的错误处理和回滚机制
### 8. 修正后的完整流程
#### 8.1 用户操作流程
1. 用户已登录本地服务器
2. 访问个人资料页面
3. 看到反向迁移功能
4. 输入远端从服务器的用户名和密码
5. 点击推送按钮
6. 系统验证远端身份
7. 推送本地数据到远端
8. 显示操作结果
#### 8.2 管理员操作流程
1. 管理员登录管理后台
2. 进入用户管理页面
3. 选择要推送的用户
4. 输入远端从服务器的用户名和密码
5. 执行批量反向迁移
6. 查看操作结果和统计
这个修正确保了反向迁移功能的身份验证逻辑正确,符合实际的使用场景和安全要求。用户可以安全地将本地数据推送到远端从服务器,同时保证了远端服务器的访问控制。
修正反向迁移概念和实现
时间:2025年1月12日
问题描述:
之前的实现错误理解了反向迁移的概念,将其理解为"从主服务器迁移到从服务器",但实际上反向迁移的正确概念是:
- 本地服务器是"主服务器"(数据源)
- config中配置的是"从服务器"(目标服务器)
- 反向迁移是将本地主服务器的数据推送到远端从服务器
- 只是复用了config中的主服务器配置项来连接目标从服务器
修正内容:
### 1. 核心概念修正
**原错误概念:**
- 从主数据库拉取数据到本地从数据库
- 用户输入主服务器的用户名密码
**正确概念:**
- 将本地数据库的数据推送到远端从数据库
- 用户输入本地的用户名密码进行身份验证
- config中的"主数据库"配置实际指向目标从数据库
### 2. 代码实现修正
#### 2.1 核心函数修正 (include/masterslave.func.php)
- `reverse_migrate_user()`: 修正数据流向,从本地读取,推送到远端
- `reverse_migrate_game_data()`: 修正游戏数据迁移方向
- 更新函数注释和变量命名,明确数据流向
#### 2.2 数据流向修正
**修正前:**
```
主数据库 → 验证用户 → 读取数据 → 写入本地从数据库
```
**修正后:**
```
本地数据库 → 验证用户 → 读取数据 → 写入远端从数据库
```
### 3. 界面文案修正
#### 3.1 配置管理界面 (templates/default/admin_configmng.htm)
- 从服务器级别说明:"-1=反向迁移模式(本地主→远端从)"
- 配置项标签:从"主数据库"改为"目标数据库"
- 配置项说明:明确在反向迁移模式下指向远端从数据库
#### 3.2 管理界面 (templates/default/admin_urlist.htm)
- 密码输入框:从"主服务器密码"改为"本地用户密码"
- 操作说明:明确是验证本地身份后推送到远端从服务器
#### 3.3 用户界面 (templates/default/user.htm)
- 功能标题:从"从主服务器迁移到本服务器"改为"推送到远端从服务器"
- 输入框:本地用户名(只读)和本地密码
- 按钮文案:从"迁移数据到本服务器"改为"推送数据到远端服务器"
- 说明文字:明确不会影响本地数据,只是推送到远端
### 4. 配置文件修正 (config.inc.php)
- 更新所有配置项的注释
- 明确在不同模式下配置项的实际含义
- slave_level>0时:配置项指向主数据库
- slave_level=-1时:配置项指向远端从数据库
### 5. 测试文件修正
- `test_reverse_migration.php`: 更新连接测试说明
- `test_user_reverse_migration.php`: 更新界面预览和测试表单
### 6. 修正后的正确流程
#### 6.1 管理员操作流程
1. 设置 slave_level = -1 启用反向迁移模式
2. 配置目标从服务器的数据库连接信息
3. 在用户管理界面选择要推送的用户
4. 输入本地用户密码进行验证
5. 系统将本地用户数据推送到远端从服务器
#### 6.2 用户操作流程
1. 用户访问个人资料页面
2. 看到反向迁移功能(推送到远端从服务器)
3. 输入本地密码进行身份验证
4. 系统将用户的本地数据推送到远端从服务器
5. 本地数据保持不变
### 7. 技术要点
#### 7.1 数据验证
- 在本地数据库验证用户名和密码
- 确保用户有权限推送自己的数据
#### 7.2 数据推送
- 从本地数据库读取用户数据和游戏角色数据
- 连接到远端从数据库(复用主数据库连接配置)
- 在远端创建或更新用户数据
#### 7.3 安全性
- 本地数据不会被修改或删除
- 远端从服务器接收推送的数据
- 记录推送历史和状态
### 8. 配置项复用说明
在反向迁移模式下,config.inc.php中的配置项含义:
- `$master_dbhost` → 远端从数据库服务器地址
- `$master_dbuser` → 远端从数据库用户名
- `$master_dbpw` → 远端从数据库密码
- `$master_dbname` → 远端从数据库名
- `$master_tablepre` → 远端从数据库表前缀
- `$master_server_name` → 远端从服务器名称(用于显示)
这种设计复用了现有的配置结构,避免了添加新的配置项,同时保持了代码的简洁性。
修正后的实现正确体现了反向迁移的核心概念:将本地主服务器的数据推送到远端从服务器,为数据分发和备份提供了有效的解决方案。
实现反向迁移功能 (slave_level = -1)
时间:2025年1月12日
功能描述:
当 slave_level 设置为 -1 时,启用反向迁移模式。在此模式下,管理员可以通过用户管理界面将主数据库的用户数据迁移到从数据库中,而不影响主数据库本身。
实现内容:
### 1. 配置管理界面更新
**文件:templates/default/admin_configmng.htm**
- 更新从服务器级别说明,添加 -1=反向迁移模式(主→从) 的描述
**文件:config.inc.php**
- 更新配置文件注释,添加对 slave_level = -1 的说明
### 2. 核心功能实现
**文件:include/masterslave.func.php**
- 添加 `is_reverse_migration_mode()` 函数:检查是否为反向迁移模式
- 添加 `reverse_migrate_user()` 函数:执行用户数据的反向迁移
- 添加 `reverse_migrate_game_data()` 函数:迁移游戏角色数据
- 添加 `set_reverse_migration_info()` 函数:记录反向迁移信息
- 添加 `create_reverse_migration_table_if_not_exists()` 函数:创建反向迁移记录表
- 添加 `get_reverse_migration_status()` 函数:获取反向迁移状态
### 3. 管理界面功能
**文件:include/admin/urlist.php**
- 引入 masterslave.func.php
- 在用户操作命令中添加 'reverse_migrate' 处理
- 实现反向迁移的具体逻辑,包括批量处理和错误处理
- 添加反向迁移显示变量设置
**文件:templates/default/admin_urlist.htm**
- 添加"反向迁移选中玩家"按钮(仅在反向迁移模式下显示)
- 添加主服务器密码输入框
- 添加反向迁移操作的说明文字
### 4. 数据库结构
**新增表:{$gtablepre}reverse_migration**
- id: 自增主键
- target_username: 目标用户名(从数据库中的用户名)
- master_username: 主服务器用户名
- sync_time: 迁移时间戳
### 5. 功能特点
1. **安全性**:
- 只在 slave_level = -1 时启用功能
- 需要输入主服务器密码进行验证
- 不影响主数据库,只向从数据库写入数据
2. **完整性**:
- 同时迁移用户账户数据和游戏角色数据
- 支持更新现有用户或创建新用户
- 记录迁移历史和状态
3. **批量操作**:
- 支持选择多个用户进行批量反向迁移
- 提供详细的成功/失败统计
- 记录管理员操作日志
4. **用户体验**:
- 界面清晰标识反向迁移功能
- 提供操作说明和注意事项
- 实时反馈操作结果
### 6. 使用流程
1. 将 config.inc.php 中的 $slave_level 设置为 -1
2. 配置主数据库连接信息
3. 进入管理后台 → 用户管理
4. 选择要迁移的用户
5. 输入主服务器密码
6. 点击"反向迁移选中玩家"按钮
7. 查看迁移结果
### 7. 技术要点
- 使用现有的主从数据库连接机制
- 复用用户数据同步的字段映射逻辑
- 独立的迁移记录表避免与正向同步冲突
- 完善的错误处理和日志记录
这个功能为管理员提供了一个安全、高效的方式来将主服务器的用户数据迁移到从服务器,特别适用于服务器迁移、数据备份恢复等场景。
修复测试文件访问权限问题
时间:2025年1月12日
问题描述:
在远端部署后,访问测试文件 https://dts.momobako.com/test_user_reverse_migration.php 时直接返回 "Access Denied"。
问题原因:
1. 测试文件没有使用正确的系统初始化流程
2. 缺少必要的安全检查和访问控制
3. 直接包含配置文件而不是通过 common.inc.php 进行标准初始化
修复内容:
### 1. 初始化流程修正
#### 1.1 修正前的错误做法
```php
// 错误的初始化方式
include './config.inc.php';
include './include/db_mysql.class.php';
include './include/masterslave.func.php';
// 手动初始化数据库连接
$db = new dbstuff;
$db->connect($dbhost,$dbuser,$dbpw,$dbname,$pconnect);
$db->select_db($dbname);
```
#### 1.2 修正后的正确做法
```php
// 正确的初始化方式
define('CURSCRIPT', 'test_user_reverse_migration');
require './include/common.inc.php';
require './include/masterslave.func.php';
```
### 2. 访问控制添加
#### 2.1 安全检查
```php
// 添加基本的访问控制 - 只允许管理员访问测试页面
if(!$cuser || !$udata || $udata['groupid'] < 9) {
exit('Access Denied - 仅管理员可访问测试页面');
}
```
#### 2.2 用户信息显示
```php
echo "<p style='color: #666; font-size: 12px;'>当前登录用户:{$cuser} (管理员权限)</p>";
```
### 3. 修复的文件
#### 3.1 test_user_reverse_migration.php
- 使用标准的系统初始化流程
- 添加管理员权限检查
- 显示当前登录用户信息
#### 3.2 test_reverse_migration.php
- 同样修正初始化流程
- 添加相同的访问控制
### 4. 系统初始化的重要性
#### 4.1 common.inc.php 提供的功能
- 定义系统常量和路径
- 初始化数据库连接(包括主从数据库逻辑)
- 加载必要的函数库
- 处理用户认证和会话管理
- 设置错误处理和安全过滤
- 初始化游戏相关的配置和状态
#### 4.2 直接包含配置文件的问题
- 缺少安全过滤和验证
- 没有用户认证机制
- 数据库连接可能不正确
- 缺少必要的常量定义
- 可能导致安全漏洞
### 5. 访问控制策略
#### 5.1 测试文件的访问级别
- **管理员专用**:只有 groupid >= 9 的用户可以访问
- **登录验证**:必须是已登录的有效用户
- **权限检查**:验证用户数据的完整性
#### 5.2 错误处理
- 明确的错误信息提示
- 安全的访问拒绝机制
- 不泄露系统内部信息
### 6. 部署后的验证
#### 6.1 访问流程
1. 用户必须先登录系统
2. 登录用户必须具有管理员权限
3. 通过权限验证后才能访问测试页面
4. 页面显示当前用户信息确认身份
#### 6.2 测试步骤
1. 访问主站点并登录管理员账户
2. 访问测试页面 URL
3. 验证页面正常加载并显示功能
4. 测试反向迁移功能是否正常工作
### 7. 安全考虑
#### 7.1 生产环境建议
- 测试文件应该在生产环境中删除或重命名
- 如果保留,应该添加更严格的访问控制
- 考虑添加 IP 白名单限制
- 记录访问日志用于安全审计
#### 7.2 开发环境使用
- 测试文件便于开发和调试
- 提供详细的功能状态信息
- 支持交互式测试和验证
### 8. 修复后的预期效果
#### 8.1 正常访问流程
1. 管理员登录后访问测试页面
2. 页面正常加载并显示系统状态
3. 可以进行反向迁移功能测试
4. 显示详细的测试结果和状态信息
#### 8.2 安全保护
- 未登录用户无法访问
- 普通用户无法访问
- 只有管理员可以使用测试功能
- 防止未授权的系统访问
这个修复确保了测试文件在远端部署后能够正常工作,同时保持了适当的安全控制,只允许有权限的管理员用户访问和使用测试功能。
实现用户端反向迁移功能
时间:2025年1月12日
功能描述:
复用现有的用户端迁移代码,为普通用户提供反向迁移功能。当 slave_level = -1 时,用户可以在个人资料页面进行反向迁移操作,将主服务器的账号数据迁移到本服务器。
实现内容:
### 1. 用户端处理逻辑
**文件:user.php**
- 添加 `mode == 'reverse_migrate'` 处理分支
- 复用现有的 AJAX 响应格式和错误处理机制
- 调用 `reverse_migrate_user()` 函数执行反向迁移
- 添加反向迁移相关的显示变量设置
### 2. 用户界面模板
**文件:templates/default/user.htm**
- 添加反向迁移功能区域(仅在反向迁移模式下显示)
- 复用现有的表单结构和样式设计
- 添加独立的 JavaScript 函数 `reverseMigrateData()`
- 优化显示逻辑,避免同时显示正向同步和反向迁移功能
### 3. 功能特点
#### 3.1 界面设计
- **颜色区分**:使用橙红色主题区分反向迁移功能
- **清晰标识**:明确标注"反向迁移功能 (从主服务器迁移到本服务器)"
- **状态显示**:显示当前模式和主服务器名称
- **历史记录**:显示已迁移的主服务器账户和迁移时间
#### 3.2 用户体验
- **表单复用**:复用现有的用户名密码输入框设计
- **确认机制**:JavaScript 确认对话框防止误操作
- **AJAX 提交**:无刷新提交,实时显示结果
- **详细说明**:提供操作说明和注意事项
#### 3.3 安全性
- **模式检查**:只在 slave_level = -1 时显示功能
- **密码验证**:需要输入主服务器密码进行验证
- **数据保护**:明确说明不会影响主服务器数据
### 4. 代码复用
#### 4.1 复用的现有功能
- **AJAX 处理框架**:复用 `postCmd()` 函数和响应格式
- **表单结构**:复用用户名密码输入表单设计
- **样式系统**:复用现有的 CSS 样式和布局
- **错误处理**:复用现有的错误信息显示机制
#### 4.2 新增的独立功能
- **反向迁移处理**:独立的 `mode == 'reverse_migrate'` 分支
- **显示变量**:独立的 `$show_reverse_migrate_button` 等变量
- **JavaScript 函数**:独立的 `reverseMigrateData()` 函数
- **状态查询**:使用 `get_reverse_migration_status()` 查询迁移状态
### 5. 界面逻辑
#### 5.1 显示条件
```php
// 正向同步:slave_level >= 1 且不是反向迁移模式
$show_sync_button = ($slave_level >= 1 && !empty($master_server_name));
// 反向迁移:slave_level == -1
$show_reverse_migrate_button = (is_reverse_migration_mode() && !empty($master_server_name));
```
#### 5.2 互斥显示
- 正向同步和反向迁移功能互斥显示
- 使用 `$show_sync_button && !$show_reverse_migrate_button` 确保不会同时显示
### 6. 用户操作流程
1. 用户访问个人资料页面 (user.php)
2. 系统检测到反向迁移模式,显示反向迁移功能区域
3. 用户输入主服务器的用户名和密码
4. 点击"迁移账号数据到本服务器"按钮
5. JavaScript 确认对话框确认操作
6. AJAX 提交到 user.php?mode=reverse_migrate
7. 系统执行反向迁移并返回结果
8. 页面显示迁移结果和状态更新
### 7. 技术实现要点
#### 7.1 数据处理
- 密码使用 `md5()` 加密后传递给后端函数
- 目标用户名默认使用当前登录用户名 `$cuser`
- 复用现有的 `compatible_json_encode()` 函数格式化响应
#### 7.2 错误处理
- 检查反向迁移模式状态
- 验证用户名密码输入
- 处理数据库连接错误
- 显示详细的错误信息
#### 7.3 状态管理
- 查询和显示用户的反向迁移历史
- 更新按钮文本显示当前状态
- 记录迁移时间和来源信息
### 8. 测试文件
**文件:test_user_reverse_migration.php**
- 提供用户端反向迁移功能的完整测试
- 模拟用户界面显示效果
- 测试数据库连接和迁移功能
- 显示界面预览和操作说明
### 9. 与管理端功能的区别
- **权限范围**:用户只能迁移自己的账号,管理员可以批量迁移
- **操作对象**:用户端固定迁移到当前登录用户,管理端可以指定目标
- **界面风格**:用户端使用更友好的界面设计和说明文字
- **功能入口**:用户端在个人资料页面,管理端在用户管理页面
这个实现为普通用户提供了一个安全、友好的反向迁移功能,让用户可以自主地将主服务器的数据迁移到本服务器,同时保持了与现有用户界面的一致性和易用性。
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
if(!defined('IN_ADMIN')) { if(!defined('IN_ADMIN')) {
exit('Access Denied'); exit('Access Denied');
} }
// 引入主从同步功能
include_once './include/masterslave.func.php';
if(!isset($urcmd)){$urcmd = '';} if(!isset($urcmd)){$urcmd = '';}
if($urcmd){ if($urcmd){
if(!isset($start)){$start = 0;} if(!isset($start)){$start = 0;}
...@@ -35,7 +38,7 @@ if($urcmd){ ...@@ -35,7 +38,7 @@ if($urcmd){
$resultinfo = '第'.$startno.'条-第'.$endno.'条记录'; $resultinfo = '第'.$startno.'条-第'.$endno.'条记录';
} }
} }
if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmessage') { if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmessage' || $urcmd == 'reverse_migrate') {
$operlist = $gfaillist = $ffaillist = array(); $operlist = $gfaillist = $ffaillist = array();
for($i=0;$i<$showlimit;$i++){ for($i=0;$i<$showlimit;$i++){
if(isset(${'user_'.$i})) { if(isset(${'user_'.$i})) {
...@@ -69,6 +72,8 @@ if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmes ...@@ -69,6 +72,8 @@ if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmes
}elseif($urcmd == 'del'){ }elseif($urcmd == 'del'){
$operword = '删除'; $operword = '删除';
$qryword = "DELETE FROM {$gtablepre}users "; $qryword = "DELETE FROM {$gtablepre}users ";
}elseif($urcmd == 'reverse_migrate'){
$operword = '反向迁移';
} }
if($operlist){ if($operlist){
if($urcmd == 'sendmessage'){ if($urcmd == 'sendmessage'){
...@@ -79,13 +84,42 @@ if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmes ...@@ -79,13 +84,42 @@ if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmes
$opernames = implode(',',($operlist)); $opernames = implode(',',($operlist));
$cmd_info .= " 给帐户 $opernames 发送了邮件 。<br>"; $cmd_info .= " 给帐户 $opernames 发送了邮件 。<br>";
adminlog($urcmd.'ur',$opernames,json_encode($stitle,$scontent,$senclosure)); adminlog($urcmd.'ur',$opernames,json_encode($stitle,$scontent,$senclosure));
}elseif($urcmd == 'reverse_migrate'){
// 处理反向迁移
if(!is_reverse_migration_mode()) {
$cmd_info .= " 错误:当前不是反向迁移模式 (slave_level != -1)。<br>";
} elseif(empty($master_password)) {
$cmd_info .= " 错误:请输入远端从服务器密码。<br>";
} elseif(empty($remote_username)) {
$cmd_info .= " 错误:请输入远端从服务器用户名。<br>";
} else {
$opernames = array();
$success_count = 0;
$fail_count = 0;
foreach($operlist as $uid => $username) {
// 使用本地用户名、远端用户名和密码进行反向迁移
$migrate_result = reverse_migrate_user($username, $remote_username, md5($master_password));
if($migrate_result['success']) {
$success_count++;
$opernames[] = $username . '(成功)';
} else {
$fail_count++;
$opernames[] = $username . '(失败: ' . $migrate_result['message'] . ')';
}
}
$opernames_str = implode(', ', $opernames);
$cmd_info .= " 反向迁移结果:成功 $success_count 个,失败 $fail_count 个。详情:$opernames_str<br>";
adminlog($urcmd.'ur', implode(',', array_values($operlist)), "成功:$success_count,失败:$fail_count");
}
}else{ }else{
$qrywhere = '('.implode(',',array_keys($operlist)).')'; $qrywhere = '('.implode(',',array_keys($operlist)).')';
$opernames = implode(',',($operlist)); $opernames = implode(',',($operlist));
$db->query("$qryword WHERE uid IN $qrywhere"); $db->query("$qryword WHERE uid IN $qrywhere");
$cmd_info .= " 帐户 $opernames$operword 。<br>"; $cmd_info .= " 帐户 $opernames$operword 。<br>";
} }
} }
if($gfaillist){ if($gfaillist){
$gfailnames = implode(',',($gfaillist)); $gfailnames = implode(',',($gfaillist));
...@@ -171,6 +205,10 @@ if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmes ...@@ -171,6 +205,10 @@ if($urcmd == 'ban' || $urcmd == 'unban' || $urcmd == 'del' || $urcmd == 'sendmes
} }
$urcmd = 'list'; $urcmd = 'list';
} }
// 设置反向迁移显示变量
$show_reverse_migration = is_reverse_migration_mode();
include template('admin_urlist'); include template('admin_urlist');
......
This diff is collapsed.
...@@ -49,37 +49,37 @@ ...@@ -49,37 +49,37 @@
<tr> <tr>
<td>从服务器级别</td> <td>从服务器级别</td>
<td><input type="text" value="$display_slave_level" size="30" disabled="true" style="background-color: #F5F5F5;"></td> <td><input type="text" value="$display_slave_level" size="30" disabled="true" style="background-color: #F5F5F5;"></td>
<td>0=主服务器, 1=从服务器(手动迁移), 2=从服务器(自动同步), 3=从服务器(直接使用主数据库)</td> <td>-1=反向迁移模式(本地主→远端从), 0=主服务器, 1=从服务器(手动迁移), 2=从服务器(自动同步), 3=从服务器(直接使用主数据库)</td>
</tr> </tr>
<tr> <tr>
<td>服务器名称</td> <td>目标服务器名称</td>
<td><input type="text" value="$display_master_server_name" size="30" disabled="true" style="background-color: #F5F5F5;"></td> <td><input type="text" value="$display_master_server_name" size="30" disabled="true" style="background-color: #F5F5F5;"></td>
<td>用于显示的主服务器名称</td> <td>用于显示的目标服务器名称(反向迁移模式下为远端从服务器)</td>
</tr> </tr>
<tr> <tr>
<td>数据库服务器</td> <td>目标数据库服务器</td>
<td><input type="text" value="$display_master_dbhost" size="30" disabled="true" style="background-color: #F5F5F5;"></td> <td><input type="text" value="$display_master_dbhost" size="30" disabled="true" style="background-color: #F5F5F5;"></td>
<td>主数据库服务器地址</td> <td>目标数据库服务器地址(反向迁移模式下为远端从数据库)</td>
</tr> </tr>
<tr> <tr>
<td>数据库用户名</td> <td>目标数据库用户名</td>
<td><input type="text" value="$display_master_dbuser" size="30" disabled="true" style="background-color: #F5F5F5;"></td> <td><input type="text" value="$display_master_dbuser" size="30" disabled="true" style="background-color: #F5F5F5;"></td>
<td>主数据库用户名</td> <td>目标数据库用户名(反向迁移模式下为远端从数据库)</td>
</tr> </tr>
<tr> <tr>
<td>数据库密码</td> <td>目标数据库密码</td>
<td><input type="password" value="$display_master_dbpw" size="30" disabled="true" style="background-color: #F5F5F5;"></td> <td><input type="password" value="$display_master_dbpw" size="30" disabled="true" style="background-color: #F5F5F5;"></td>
<td>主数据库密码</td> <td>目标数据库密码(反向迁移模式下为远端从数据库)</td>
</tr> </tr>
<tr> <tr>
<td>数据库名</td> <td>目标数据库名</td>
<td><input type="text" value="$display_master_dbname" size="30" disabled="true" style="background-color: #F5F5F5;"></td> <td><input type="text" value="$display_master_dbname" size="30" disabled="true" style="background-color: #F5F5F5;"></td>
<td>主数据库名</td> <td>目标数据库名(反向迁移模式下为远端从数据库)</td>
</tr> </tr>
<tr> <tr>
<td>数据库表前缀</td> <td>目标数据库表前缀</td>
<td><input type="text" value="$display_master_tablepre" size="30" disabled="true" style="background-color: #F5F5F5;"></td> <td><input type="text" value="$display_master_tablepre" size="30" disabled="true" style="background-color: #F5F5F5;"></td>
<td>主数据库表前缀</td> <td>目标数据库表前缀(反向迁移模式下为远端从数据库)</td>
</tr> </tr>
</table> </table>
<input type="submit" value="提交" onclick="$('command').value='edit';"> <input type="submit" value="提交" onclick="$('command').value='edit';">
......
...@@ -115,6 +115,9 @@ ...@@ -115,6 +115,9 @@
<input type="submit" name="submit" value="封停选中玩家" onclick="$('urcmd').value='ban'"> <input type="submit" name="submit" value="封停选中玩家" onclick="$('urcmd').value='ban'">
<input type="submit" name="submit" value="解封选中玩家" onclick="$('urcmd').value='unban'"> <input type="submit" name="submit" value="解封选中玩家" onclick="$('urcmd').value='unban'">
<input type="submit" name="submit" value="删除选中玩家" onclick="$('urcmd').value='del'"> <input type="submit" name="submit" value="删除选中玩家" onclick="$('urcmd').value='del'">
<!--{if $show_reverse_migration}-->
<input type="submit" name="submit" value="反向迁移选中玩家" onclick="$('urcmd').value='reverse_migrate'" style="background-color: #FFE4B5;">
<!--{/if}-->
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -129,6 +132,18 @@ ...@@ -129,6 +132,18 @@
<input type="submit" name="submit" value="发送站内邮件" onclick="$('urcmd').value='sendmessage'"> <input type="submit" name="submit" value="发送站内邮件" onclick="$('urcmd').value='sendmessage'">
</td> </td>
</tr> </tr>
<!--{if $show_reverse_migration}-->
<tr>
<td colspan=2 style="background-color: #FFE4B5; font-weight: bold;">反向迁移</td>
<td colspan=12 style="text-align:center; background-color: #FFF8DC;">
远端用户名:
<input type="text" name="remote_username" size="15" maxlength="30" placeholder="远端从服务器用户名">&nbsp;&nbsp;&nbsp;
远端密码:
<input type="password" name="master_password" size="15" maxlength="30" placeholder="远端从服务器密码">&nbsp;&nbsp;&nbsp;
<span style="color: #8B4513; font-size: 12px;">注意:将推送选中用户的数据到远端从服务器,需要远端服务器的有效账户进行身份验证</span>
</td>
</tr>
<!--{/if}-->
<!--{/if}--> <!--{/if}-->
</table> </table>
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
<input type="reset" id="reset" name="reset" value="{lang reset}"> <input type="reset" id="reset" name="reset" value="{lang reset}">
</div> </div>
</form> </form>
<!--{if $show_sync_button}--> <!--{if $show_sync_button && !$show_reverse_migrate_button}-->
<div style="margin-top: 20px; padding: 15px; border: 2px solid #FFD700; background-color: #FFFACD; border-radius: 5px;"> <div style="margin-top: 20px; padding: 15px; border: 2px solid #FFD700; background-color: #FFFACD; border-radius: 5px;">
<div style="text-align: center; font-weight: bold; color: #B8860B; margin-bottom: 10px;"> <div style="text-align: center; font-weight: bold; color: #B8860B; margin-bottom: 10px;">
主从数据库同步功能 主从数据库同步功能
...@@ -84,6 +84,66 @@ ...@@ -84,6 +84,66 @@
} }
</script> </script>
<!--{/if}--> <!--{/if}-->
<!--{if $show_reverse_migrate_button}-->
<div style="margin-top: 20px; padding: 15px; border: 2px solid #FF6347; background-color: #FFF5EE; border-radius: 5px;">
<div style="text-align: center; font-weight: bold; color: #CD5C5C; margin-bottom: 10px;">
反向迁移功能 (推送到远端从服务器)
</div>
<div style="text-align: center; font-size: 12px; color: #8B4513; margin-bottom: 10px;">
当前模式:反向迁移模式 | 目标服务器:{$master_server_name}
</div>
<form method="post" action="user.php" name="reversemigratedata" id="reversemigrateform">
<input type="hidden" name="mode" value="reverse_migrate">
<table align="center" style="border-collapse: collapse;">
<tr>
<td style="padding: 5px; text-align: right;">远端用户名:</td>
<td style="padding: 5px;">
<input type="text" name="remote_username" id="reverse_remote_username" size="20" placeholder="在{$master_server_name}的用户名">
</td>
</tr>
<tr>
<td style="padding: 5px; text-align: right;">远端密码:</td>
<td style="padding: 5px;">
<input type="password" name="remote_password" id="reverse_remote_password" size="20" placeholder="在{$master_server_name}的密码">
</td>
</tr>
<tr>
<td colspan="2" style="padding: 10px; text-align: center;">
<input type="button" value="{$reverse_migrate_button_text}" onclick="reverseMigrateData();" style="padding: 8px 15px; background-color: #FF6347; color: white; border: 1px solid #CD5C5C; border-radius: 3px; cursor: pointer;">
</td>
</tr>
</table>
</form>
<!--{if $user_reverse_migrate_status}-->
<div style="margin-top: 10px; text-align: center; font-size: 12px; color: #666;">
已推送到远端服务器:{$user_reverse_migrate_status['master_username']} (上次推送:{$user_reverse_migrate_status['sync_time_formatted']})
</div>
<!--{/if}-->
<div style="margin-top: 10px; text-align: center; font-size: 11px; color: #888;">
注意:反向迁移将把您的本地账户数据推送到远端从服务器 {$master_server_name},需要在远端服务器有有效账户进行身份验证。本地数据不会受影响。
</div>
</div>
<script type="text/javascript">
function reverseMigrateData() {
var username = document.getElementById('reverse_remote_username').value;
var password = document.getElementById('reverse_remote_password').value;
if(!username || !password) {
alert('请输入远端从服务器的用户名和密码');
return false;
}
if(!confirm('确定要将本地账户数据推送到远端从服务器吗?需要使用远端服务器的有效账户进行身份验证。本地数据不会受影响。')) {
return false;
}
postCmd('reversemigrateform', 'user.php');
return false;
}
</script>
<!--{/if}-->
</center> </center>
<br /> <br />
{template footer} {template footer}
\ No newline at end of file
<?php
/**
* 主从数据库同步功能测试脚本
* Master-Slave Database Sync Test Script
*/
define('CURSCRIPT', 'test_masterslave');
require './include/common.inc.php';
require './include/masterslave.func.php';
echo "<h2>主从数据库同步功能测试</h2>";
// 显示当前配置
echo "<h3>当前配置</h3>";
echo "从服务器级别 (slave_level): " . $slave_level . "<br>";
echo "主服务器名称 (master_server_name): " . $master_server_name . "<br>";
echo "主数据库服务器 (master_dbhost): " . $master_dbhost . "<br>";
echo "主数据库名 (master_dbname): " . $master_dbname . "<br>";
echo "主数据库表前缀 (master_tablepre): " . $master_tablepre . "<br>";
echo "<hr>";
// 测试连接主数据库
echo "<h3>测试主数据库连接</h3>";
if($slave_level > 0) {
$master_db = connect_master_db();
if($master_db) {
echo "<span style='color: green;'>✓ 主数据库连接成功</span><br>";
// 测试查询主数据库用户表
$result = $master_db->query("SELECT COUNT(*) as count FROM {$master_tablepre}users", 'SILENT');
if(!$master_db->error() && $master_db->num_rows($result)) {
$count_data = $master_db->fetch_array($result);
echo "主数据库用户数量: " . $count_data['count'] . "<br>";
} else {
echo "<span style='color: orange;'>⚠ 无法查询主数据库用户表</span><br>";
}
} else {
echo "<span style='color: red;'>✗ 主数据库连接失败</span><br>";
}
} else {
echo "<span style='color: blue;'>ℹ 当前为主服务器,无需连接主数据库</span><br>";
}
echo "<hr>";
// 测试同步表创建
echo "<h3>测试同步表</h3>";
create_sync_table_if_not_exists();
$result = $db->query("SHOW TABLES LIKE '{$gtablepre}user_sync'", 'SILENT');
if($db->num_rows($result)) {
echo "<span style='color: green;'>✓ 同步表存在</span><br>";
// 显示同步记录
$sync_result = $db->query("SELECT * FROM {$gtablepre}user_sync ORDER BY sync_time DESC LIMIT 5");
if($db->num_rows($sync_result)) {
echo "<h4>最近的同步记录:</h4>";
echo "<table border='1' cellpadding='5'>";
echo "<tr><th>目标用户名</th><th>主服务器用户名</th><th>同步时间</th></tr>";
while($sync_data = $db->fetch_array($sync_result)) {
echo "<tr>";
echo "<td>" . htmlspecialchars($sync_data['target_username']) . "</td>";
echo "<td>" . htmlspecialchars($sync_data['master_username']) . "</td>";
echo "<td>" . date('Y-m-d H:i:s', $sync_data['sync_time']) . "</td>";
echo "</tr>";
}
echo "</table>";
} else {
echo "暂无同步记录<br>";
}
} else {
echo "<span style='color: red;'>✗ 同步表不存在</span><br>";
}
echo "<hr>";
// 功能状态检查
echo "<h3>功能状态检查</h3>";
echo "是否需要自动同步: " . (should_auto_sync() ? "<span style='color: green;'>是</span>" : "<span style='color: gray;'>否</span>") . "<br>";
echo "是否直接使用主数据库: " . (should_use_master_db() ? "<span style='color: green;'>是</span>" : "<span style='color: gray;'>否</span>") . "<br>";
if($slave_level >= 1 && !empty($master_server_name)) {
echo "主从同步功能: <span style='color: green;'>已启用</span><br>";
} else {
echo "主从同步功能: <span style='color: gray;'>未启用</span><br>";
}
// 显示当前使用的数据库表前缀
echo "当前游戏表前缀 (gtablepre): " . $gtablepre . "<br>";
if($slave_level == 3) {
echo "<span style='color: blue;'>ℹ 当前直接使用主数据库</span><br>";
}
echo "<hr>";
// 测试表单(仅在从服务器模式下显示)
if($slave_level >= 1 && !empty($master_server_name)) {
echo "<h3>测试同步功能</h3>";
echo "<form method='post' action='test_masterslave.php'>";
echo "<table>";
echo "<tr><td>主服务器用户名:</td><td><input type='text' name='test_master_username' size='20'></td></tr>";
echo "<tr><td>主服务器密码:</td><td><input type='password' name='test_master_password' size='20'></td></tr>";
echo "<tr><td>目标用户名:</td><td><input type='text' name='test_target_username' size='20' placeholder='留空使用主服务器用户名'></td></tr>";
echo "<tr><td colspan='2'><input type='submit' name='test_sync' value='测试同步'></td></tr>";
echo "</table>";
echo "</form>";
// 处理测试同步
if(isset($_POST['test_sync'])) {
$test_master_username = $_POST['test_master_username'];
$test_master_password = $_POST['test_master_password'];
$test_target_username = $_POST['test_target_username'] ?: $test_master_username;
if($test_master_username && $test_master_password) {
echo "<h4>同步测试结果:</h4>";
$sync_result = sync_user_from_master($test_master_username, $test_master_password, $test_target_username);
if($sync_result['success']) {
echo "<span style='color: green;'>✓ " . htmlspecialchars($sync_result['message']) . "</span><br>";
} else {
echo "<span style='color: red;'>✗ " . htmlspecialchars($sync_result['message']) . "</span><br>";
}
} else {
echo "<span style='color: red;'>✗ 请输入用户名和密码</span><br>";
}
}
}
echo "<hr>";
echo "<p><a href='admin.php'>返回管理界面</a> | <a href='user.php'>用户资料</a> | <a href='index.php'>游戏首页</a></p>";
?>
...@@ -36,6 +36,26 @@ if($mode == 'sync_master') { ...@@ -36,6 +36,26 @@ if($mode == 'sync_master') {
echo $jgamedata; echo $jgamedata;
ob_end_flush(); ob_end_flush();
} elseif($mode == 'reverse_migrate') {
// 处理反向迁移
$gamedata=Array();$gamedata['innerHTML']['info'] = '';
if(is_reverse_migration_mode() && !empty($master_server_name)) {
if(!empty($remote_username) && !empty($remote_password)) {
$migrate_result = reverse_migrate_user($cuser, $remote_username, md5($remote_password));
$gamedata['innerHTML']['info'] .= $migrate_result['message'] . '<br>';
} else {
$gamedata['innerHTML']['info'] .= '请输入远端从服务器的用户名和密码<br>';
}
} else {
$gamedata['innerHTML']['info'] .= '当前服务器不是反向迁移模式或未配置目标服务器信息<br>';
}
ob_clean();
$jgamedata = compatible_json_encode($gamedata);
echo $jgamedata;
ob_end_flush();
} elseif($mode == 'edit') { } elseif($mode == 'edit') {
$gamedata=Array();$gamedata['innerHTML']['info'] = ''; $gamedata=Array();$gamedata['innerHTML']['info'] = '';
if($opass && $npass && $rnpass){ if($opass && $npass && $rnpass){
...@@ -137,6 +157,14 @@ if($mode == 'sync_master') { ...@@ -137,6 +157,14 @@ if($mode == 'sync_master') {
} }
$sync_button_text = $user_sync_status ? "从{$master_server_name}同步已绑定的账号数据" : "从{$master_server_name}迁移用户和成就数据"; $sync_button_text = $user_sync_status ? "从{$master_server_name}同步已绑定的账号数据" : "从{$master_server_name}迁移用户和成就数据";
// 反向迁移相关变量
$show_reverse_migrate_button = (is_reverse_migration_mode() && !empty($master_server_name));
$user_reverse_migrate_status = get_reverse_migration_status($cuser);
if($user_reverse_migrate_status) {
$user_reverse_migrate_status['sync_time_formatted'] = date('Y-m-d H:i:s', $user_reverse_migrate_status['sync_time']);
}
$reverse_migrate_button_text = $user_reverse_migrate_status ? "重新推送到{$master_server_name}" : "推送到{$master_server_name}";
include template('user'); include template('user');
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment