diff --git a/.gitignore b/.gitignore index 40ba29c..1baf1b3 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,18 @@ backup/ 新建*.txt 群戏归类.txt +# PHP Web 后端 +web/Web.db +web/debug_log_tail.txt +web/upload_debug.ps1 +web/api/*.bak* +# 敏感文件 - 禁止提交上传/调试脚本 +web/upload_*.php +web/self_update.php +web/version_check.php +web/debug_*.php +web/db/debug_*.php + # Windows 保留设备名(无法用普通 rm 删除) nul con diff --git a/web/db/debug_ip_v2.php b/web/db/debug_ip_v2.php deleted file mode 100644 index 4ac287a..0000000 --- a/web/db/debug_ip_v2.php +++ /dev/null @@ -1,615 +0,0 @@ - 0) { - ob_end_clean(); -} - -// 现在开始输出HTML -header('Content-Type: text/html; charset=utf-8'); -?> - - - - - IP查询调试 v2 - - - -

🔍 IP查询调试页面 v2

- -测试IP (" . count($allIps) . "个): " . implode(', ', $allIps) . ""; - -// ===== 第1步:检查数据库中的当前状态 ===== -echo "
"; -echo "

📊 步骤1: 检查数据库当前状态

"; - -try { - $db = getDB(); - - foreach ($allIps as $ip) { - echo "

$ip:

"; - - $stmt = $db->prepare("SELECT * FROM player_ip_locations WHERE ip_address = :ip"); - $stmt->bindValue(':ip', $ip, SQLITE3_TEXT); - $result = $stmt->execute(); - $row = $result->fetchArray(SQLITE3_ASSOC); - - if ($row) { - echo "
" . json_encode($row, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "
"; - } else { - echo "

数据库中无此IP记录

"; - } - } -} catch (Exception $e) { - echo "

错误: " . $e->getMessage() . "

"; -} -echo "
"; - -// ===== 第2步:测试4个API接口(直接调用,不包含admin.php) ===== -echo "
"; -echo "

🌐 步骤2: 测试4个API接口

"; - -// ★ 直接定义函数,不包含 admin.php -function testFetchPconline($ip) { - $url = 'https://whois.pconline.com.cn/ipJson.jsp?ip=' . urlencode($ip) . '&json=true'; - $ctx = stream_context_create([ - 'http' => [ - 'method' => 'GET', - 'timeout' => 5, - 'ignore_errors' => true, - 'header' => "Accept: application/json\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 SDF1_IP_Lookup/1.0" - ] - ]); - $response = @file_get_contents($url, false, $ctx); - - $result = [ - 'api' => 'PConline', - 'url' => $url, - 'raw_response' => $response ?: 'FAILED', - 'parsed' => null, - 'location' => null, - 'error' => null - ]; - - if ($response === false || empty(trim($response))) { - $result['error'] = '请求失败'; - return $result; - } - - // ★ 修复编码问题:太平洋返回GBK编码,需要转换为UTF-8 - $response = trim($response); - if (mb_detect_encoding($response, 'UTF-8', true) === false) { - $response = mb_convert_encoding($response, 'UTF-8', 'GBK'); - $result['raw_response'] = $response; // 更新原始响应为转换后的 - } - - $json = $response; - if (preg_match('/^\s*\(?[\'"]?(.*?)[\'"]?\)?\s*$/s', $json, $matches)) { - $json = $matches[1]; - } - - $data = json_decode($json, true); - $result['parsed'] = $data; - - if (!$data || !is_array($data)) { - $result['error'] = 'JSON解析失败'; - return $result; - } - - // 优先使用 addr 字段 - if (isset($data['addr']) && trim($data['addr']) !== '') { - $addr = trim($data['addr']); - if (strpos($addr, '中国 ') !== 0) { - $result['location'] = $addr; - return $result; - } - } - - // 尝试用 pro + city 手动拼接 - if (isset($data['pro']) && trim($data['pro']) !== '') { - $loc = trim($data['pro']); - if (isset($data['city']) && trim($data['city']) !== '') { - $loc .= trim($data['city']); - } - - if (isset($data['addr'])) { - $parts = preg_split('/\s+/', trim($data['addr']), -1, PREG_SPLIT_NO_EMPTY); - if (!empty($parts)) { - $op = end($parts); - if ($op !== '中国') { - $loc .= ' ' . $op; - } - } - } - - $result['location'] = strlen($loc) > 1 ? $loc : null; - } - - return $result; -} - -function testFetchBaidu($ip) { - $url = 'https://opendata.baidu.com/api.php?query=' . urlencode($ip) . '&resource_id=6006&oe=utf8&format=json'; - $ctx = stream_context_create([ - 'http' => [ - 'method' => 'GET', - 'timeout' => 5, - 'ignore_errors' => true, - 'header' => "Accept: application/json\r\nUser-Agent: Mozilla/5.0" - ] - ]); - $response = @file_get_contents($url, false, $ctx); - - $result = [ - 'api' => 'Baidu', - 'url' => $url, - 'raw_response' => $response ?: 'FAILED', - 'parsed' => null, - 'location' => null, - 'error' => null - ]; - - if ($response === false || empty(trim($response))) { - $result['error'] = '请求失败'; - return $result; - } - - $data = json_decode(trim($response), true); - $result['parsed'] = $data; - - if ($data && isset($data['data']) && is_array($data['data']) && !empty($data['data'])) { - $loc = $data['data'][0]['location'] ?? null; - if ($loc && $loc !== '--' && strpos($loc, '中国 ') !== 0) { - $result['location'] = $loc; - } - } - - return $result; -} - -function testFetchAa1($ip) { - $url = 'https://v.api.aa1.cn/api/ipcha-baidu/?ip=' . urlencode($ip); - $ctx = stream_context_create([ - 'http' => [ - 'method' => 'GET', - 'timeout' => 5, - 'ignore_errors' => true, - 'header' => "Accept: application/json\r\nUser-Agent: Mozilla/5.0" - ] - ]); - $response = @file_get_contents($url, false, $ctx); - - $result = [ - 'api' => 'aa1.cn', - 'url' => $url, - 'raw_response' => $response ?: 'FAILED', - 'parsed' => null, - 'location' => null, - 'error' => null - ]; - - if ($response === false || empty(trim($response))) { - $result['error'] = '请求失败'; - return $result; - } - - $data = json_decode(trim($response), true); - $result['parsed'] = $data; - - if ($data && isset($data['code']) && $data['code'] == 1) { - $loc = $data['ip_add'] ?? null; - if ($loc && $loc !== '未知' && strpos($loc, '中国 ') !== 0) { - $result['location'] = $loc; - } - } - - return $result; -} - -function testFetchIp9($ip) { - // ★ 使用正确的 API 地址:ip9.com.cn/get - $url = 'https://ip9.com.cn/get?ip=' . urlencode($ip); - $ctx = stream_context_create([ - 'http' => [ - 'method' => 'GET', - 'timeout' => 5, - 'ignore_errors' => true, - 'header' => "Accept: application/json, text/plain, */*\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\r\nReferer: https://ip9.com.cn/\r\nOrigin: https://ip9.com.cn" - ], - 'ssl' => [ - 'verify_peer' => false, - 'verify_peer_name' => false - ] - ]); - $response = @file_get_contents($url, false, $ctx); - - $result = [ - 'api' => 'IP9', - 'url' => $url, - 'raw_response' => $response ?: 'FAILED', - 'parsed' => null, - 'location' => null, - 'error' => null - ]; - - if ($response === false || empty(trim($response))) { - $result['error'] = '请求失败'; - return $result; - } - - $data = json_decode(trim($response), true); - $result['parsed'] = $data; - - $debug = []; - - // IP9 返回格式有两种可能: - // 旧版: {"ret":"200","data":[{"ip":"...","prov":"广东","city":"深圳","isp":"中国移动"}]} - // 新版: {"ret":"200","data":{"ip":"...","prov":"广东","city":"深圳","isp":"中国移动"}} - // ★ 兼容两种格式 - $item = null; - if (isset($data['data'][0]) && is_array($data['data'][0])) { - $item = $data['data'][0]; - $debug['format'] = 'array'; - } elseif (isset($data['data']) && is_array($data['data']) && isset($data['data']['prov'])) { - $item = $data['data']; - $debug['format'] = 'object'; - } else { - $debug['format'] = 'unknown'; - $debug['data_type'] = gettype($data['data'] ?? null); - } - - if ($item) { - $loc = ''; - $debug['item_prov'] = $item['prov'] ?? 'NOT_SET'; - $debug['item_city'] = $item['city'] ?? 'NOT_SET'; - $debug['item_isp'] = $item['isp'] ?? 'NOT_SET'; - - if (isset($item['prov'])) $loc .= $item['prov']; - if (isset($item['city'])) $loc .= $item['city']; - if (isset($item['isp'])) $loc .= ' ' . $item['isp']; - - $debug['loc'] = $loc; - $debug['loc_len'] = strlen($loc); - - if (strlen($loc) > 0) { - $result['location'] = $loc; - } - } - - $result['debug'] = $debug; - - return $result; -} - -// 测试每个IP -foreach ($allIps as $ip) { - echo "

测试IP: $ip

"; - - // API1: PConline - echo "
"; - echo "

API1 - PConline:

"; - $start = microtime(true); - $r1 = testFetchPconline($ip); - $time1 = (microtime(true) - $start) * 1000; - echo "
";
-    echo "耗时: " . round($time1, 2) . "ms\n";
-    echo "原始响应: " . substr($r1['raw_response'], 0, 500) . "\n";
-    echo "解析结果: " . json_encode($r1['parsed'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n";
-    echo "提取位置: " . ($r1['location'] ?? 'null') . "\n";
-    echo "错误: " . ($r1['error'] ?? '无');
-    echo "
"; - echo "
"; - - // API2: Baidu - echo "
"; - echo "

API2 - Baidu:

"; - $start = microtime(true); - $r2 = testFetchBaidu($ip); - $time2 = (microtime(true) - $start) * 1000; - echo "
";
-    echo "耗时: " . round($time2, 2) . "ms\n";
-    echo "原始响应: " . substr($r2['raw_response'], 0, 500) . "\n";
-    echo "解析结果: " . json_encode($r2['parsed'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n";
-    echo "提取位置: " . ($r2['location'] ?? 'null') . "\n";
-    echo "错误: " . ($r2['error'] ?? '无');
-    echo "
"; - echo "
"; - - // API3: aa1.cn - echo "
"; - echo "

API3 - aa1.cn:

"; - $start = microtime(true); - $r3 = testFetchAa1($ip); - $time3 = (microtime(true) - $start) * 1000; - echo "
";
-    echo "耗时: " . round($time3, 2) . "ms\n";
-    echo "原始响应: " . substr($r3['raw_response'], 0, 500) . "\n";
-    echo "解析结果: " . json_encode($r3['parsed'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n";
-    echo "提取位置: " . ($r3['location'] ?? 'null') . "\n";
-    echo "错误: " . ($r3['error'] ?? '无');
-    echo "
"; - echo "
"; - - // API4: IP9 - echo "
"; - echo "

API4 - IP9:

"; - $start = microtime(true); - $r4 = testFetchIp9($ip); - $time4 = (microtime(true) - $start) * 1000; - echo "
";
-    echo "耗时: " . round($time4, 2) . "ms\n";
-    echo "原始响应: " . substr($r4['raw_response'], 0, 500) . "\n";
-    echo "解析结果: " . json_encode($r4['parsed'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n";
-    echo "提取位置: " . ($r4['location'] ?? 'null') . "\n";
-    echo "错误: " . ($r4['error'] ?? '无') . "\n";
-    echo "调试信息: " . json_encode($r4['debug'] ?? [], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
-    echo "
"; - echo "
"; - - echo "
"; -} -echo "
"; - -// ===== 第3步:模拟入库逻辑 ===== -echo "
"; -echo "

🔄 步骤3: 模拟入库逻辑

"; - -echo "

以下是服务器处理IP归属地的完整流程:

"; - -// 模拟 queryIpLocation 函数的逻辑 -foreach ($allIps as $ip) { - echo "

模拟IP: $ip

"; - - echo "

1. 检查是否是内网IP

"; - if (!$ip || $ip === '-' || $ip === '127.0.0.1' || strpos($ip, '10.') === 0 || strpos($ip, '192.168.') === 0) { - echo "

是内网IP,返回 '内网IP'

"; - continue; - } - echo "

不是内网IP,继续查询

"; - - echo "

2. 检查数据库缓存

"; - $stmt = $db->prepare("SELECT location FROM player_ip_locations WHERE ip_address = :ip LIMIT 1"); - $stmt->bindValue(':ip', $ip, SQLITE3_TEXT); - $result = $stmt->execute(); - $row = $result->fetchArray(SQLITE3_ASSOC); - - if ($row && isset($row['location'])) { - $cachedLoc = $row['location']; - echo "

找到缓存: $cachedLoc

"; - - // ★ 使用统一校验函数 - $isValidFormat = isValidIpLocationFormat($cachedLoc); - if (!$isValidFormat) { - echo "

无效格式: " . htmlspecialchars($cachedLoc) . "

"; - } - - echo "

格式验证结果: " . ($isValidFormat ? "✅ 有效" : "❌ 无效") . "

"; - - if (!$isValidFormat) { - echo "

将删除此缓存并重新查询

"; - $stmt2 = $db->prepare("DELETE FROM player_ip_locations WHERE ip_address = :ip"); - $stmt2->bindValue(':ip', $ip, SQLITE3_TEXT); - $stmt2->execute(); - } else { - echo "

格式有效,直接使用缓存

"; - continue; - } - } else { - echo "

无缓存,需要查询

"; - } - - echo "

3. 调用API查询(格式无效则继续下一个)

"; - - // ★ 与 admin.php 的 doQueryIpLocation() 一致:每个API返回后先验证格式 - $location = null; - $bestResult = null; - - // API1: PConline - echo "

尝试 API1 (PConline)...

"; - $r1 = testFetchPconline($ip); - if ($r1['location']) { - echo "

返回: " . htmlspecialchars($r1['location']) . "

"; - if (isValidIpLocationFormat($r1['location'])) { - $location = $r1['location']; - echo "

✅ 格式有效: $location

"; - } else { - echo "

⚠️ 格式无效,继续尝试下一个API

"; - $bestResult = $r1['location']; - } - } else { - echo "

❌ API1 无结果

"; - } - - // API2: Baidu(仅当前面没有有效结果时才尝试) - if (!$location) { - echo "

尝试 API2 (Baidu)...

"; - $r2 = testFetchBaidu($ip); - if ($r2['location']) { - echo "

返回: " . htmlspecialchars($r2['location']) . "

"; - if (isValidIpLocationFormat($r2['location'])) { - $location = $r2['location']; - echo "

✅ 格式有效: $location

"; - } else { - echo "

⚠️ 格式无效,继续尝试下一个API

"; - if (!$bestResult) $bestResult = $r2['location']; - } - } else { - echo "

❌ API2 无结果

"; - } - } - - // API3: aa1.cn(仅当前面没有有效结果时才尝试) - if (!$location) { - echo "

尝试 API3 (aa1.cn)...

"; - $r3 = testFetchAa1($ip); - if ($r3['location']) { - echo "

返回: " . htmlspecialchars($r3['location']) . "

"; - if (isValidIpLocationFormat($r3['location'])) { - $location = $r3['location']; - echo "

✅ 格式有效: $location

"; - } else { - echo "

⚠️ 格式无效,继续尝试下一个API

"; - if (!$bestResult) $bestResult = $r3['location']; - } - } else { - echo "

❌ API3 无结果

"; - } - } - - // API4: IP9(仅当前面没有有效结果时才尝试) - if (!$location) { - echo "

尝试 API4 (IP9)...

"; - $r4 = testFetchIp9($ip); - if ($r4['location']) { - echo "

返回: " . htmlspecialchars($r4['location']) . "

"; - if (isValidIpLocationFormat($r4['location'])) { - $location = $r4['location']; - echo "

✅ 格式有效: $location

"; - } else { - echo "

⚠️ 格式无效,继续尝试下一个API

"; - if (!$bestResult) $bestResult = $r4['location']; - } - } else { - echo "

❌ API4 无结果

"; - } - } - - // 所有API都没返回有效格式:标记为查询失败 - if (!$location) { - $location = '查询失败'; - echo '

❌ 所有API均失败或格式无效,标记为"查询失败"

'; - } - - echo "

4. 格式验证和修复(与 admin.php 一致)

"; - echo "

原始位置: $location

"; - - // 格式修复逻辑 - if ($location && $location !== '查询失败') { - $loc = $location; - - // 1. 过滤英文格式 - if (strpos($loc, 'China - ') === 0 || strpos($loc, 'China -') === 0) { - echo "

拒绝英文格式: $loc

"; - $location = null; - } - - // 2. 过滤不完整的中文格式 - if (strpos($loc, '中国 - -') === 0 || strpos($loc, '中国 - -') === 0) { - echo "

拒绝不完整格式: $loc

"; - $location = null; - } - - // 3. 格式修复:确保"位置"和"运营商"之间有空格 - // 仅在没有空格时修复(如"广东省移动"→"广东省 移动") - if ($location && strpos($loc, ' ') === false) { - // 无空格,尝试添加空格 - if (preg_match('/^(.*?(?:省|市|州|盟|地区|区|县))(.+)$/u', $loc, $matches)) { - $loc = $matches[1] . ' ' . $matches[2]; - echo "

格式修复: $location => $loc

"; - $location = $loc; - } - } - - // ★ 4. 存储前格式验证(使用统一校验函数) - if ($location) { - $shouldStore = isValidIpLocationFormat($location); - if (!$shouldStore) { - echo "

格式无效(不满足入库条件): " . htmlspecialchars($location) . "

"; - $location = null; - } - } - } - - echo "

5. 存入数据库

"; - if ($location && $location !== '查询失败') { - echo "

将存储: $location

"; - - // 模拟存储(不实际执行) - echo "
INSERT OR REPLACE INTO player_ip_locations (player_name, ip_address, location, updated_at) VALUES ('global', '$ip', '$location', " . time() . ")
"; - } else { - echo "

不存储(查询失败或格式无效)

"; - } - - echo "
"; -} -echo "
"; - -// ===== 第4步:显示所有无效格式的记录 ===== -echo "
"; -echo "

❌ 步骤4: 显示所有无效格式的记录

"; - -$invalidStmt = $db->query(" - SELECT ip_address, location - FROM player_ip_locations - WHERE location LIKE 'China%' - OR location = '-' - OR location = '--' - OR location = '查询失败' - OR location = '' - OR ip_address LIKE '127.%' - OR ip_address LIKE '192.168.%' - OR ip_address LIKE '10.%' - OR location LIKE '中国 - -%' - OR location LIKE '中国 - -%' - OR (location NOT LIKE '% %' AND (location LIKE '%省%' OR location LIKE '%市%')) -"); -$invalidCount = 0; -while ($row = $invalidStmt->fetchArray(SQLITE3_ASSOC)) { - echo "

" . $row['ip_address'] . " => " . $row['location'] . "

"; - $invalidCount++; -} - -if ($invalidCount == 0) { - echo "

没有发现无效格式的记录

"; -} else { - echo "

发现 $invalidCount 条无效格式的记录

"; -} -echo "
"; - -echo "
"; -echo "

💡 此页面用于调试IP查询流程,检查每个API的返回结果和入库逻辑。

"; -?> - - - diff --git a/web/debug_admin_api.php b/web/debug_admin_api.php deleted file mode 100644 index 3dfbc7f..0000000 --- a/web/debug_admin_api.php +++ /dev/null @@ -1,144 +0,0 @@ - 0) { @ob_end_clean(); } -header('Content-Type: text/plain; charset=utf-8'); -error_reporting(E_ALL); -ini_set('display_errors', '1'); - -echo "=== Admin API Diagnostic ===\n\n"; - -require_once __DIR__ . '/core.php'; - -echo "1. Core loaded: " . (function_exists('getDB') ? 'YES' : 'NO') . "\n"; -echo "2. ADMIN_PASS defined: " . (defined('ADMIN_PASS') ? 'YES' : 'NO') . "\n"; - -// Test database connection -echo "\n--- Database ---\n"; -try { - $db = getDB(); - echo "DB opened OK\n"; - - // List all tables - $result = $db->query("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"); - $tables = []; - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $tables[] = $row['name']; - } - echo "Tables (" . count($tables) . "): " . implode(', ', $tables) . "\n"; - - // Check player_ip_changes structure - if (in_array('player_ip_changes', $tables)) { - $result = $db->query("PRAGMA table_info(player_ip_changes)"); - echo "\nplayer_ip_changes columns:\n"; - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - echo " - {$row['name']} ({$row['type']}) PK=" . ($row['pk'] ? 'YES' : 'no') . "\n"; - } - $cnt = $db->query("SELECT COUNT(*) as c FROM player_ip_changes")->fetchArray(SQLITE3_ASSOC)['c']; - echo " Rows: $cnt\n"; - } - - // Check player_ip_locations structure - if (in_array('player_ip_locations', $tables)) { - $result = $db->query("PRAGMA table_info(player_ip_locations)"); - echo "\nplayer_ip_locations columns:\n"; - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - echo " - {$row['name']} ({$row['type']}) PK=" . ($row['pk'] ? 'YES' : 'no') . "\n"; - } - $cnt = $db->query("SELECT COUNT(*) as c FROM player_ip_locations")->fetchArray(SQLITE3_ASSOC)['c']; - echo " Rows: $cnt\n"; - // Show a sample - $result = $db->query("SELECT ip_address, location FROM player_ip_locations LIMIT 5"); - if ($result) { - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - echo " Sample: {$row['ip_address']} => {$row['location']}\n"; - } - } - } - - // Check users table - if (in_array('users', $tables)) { - $cnt = $db->query("SELECT COUNT(*) as c FROM users")->fetchArray(SQLITE3_ASSOC)['c']; - echo "\nusers rows: $cnt\n"; - } - - // Check online_players - if (in_array('online_players', $tables)) { - $cnt = $db->query("SELECT COUNT(*) as c FROM online_players")->fetchArray(SQLITE3_ASSOC)['c']; - echo "online_players rows: $cnt\n"; - } - - // Check web_session_log - if (in_array('web_session_log', $tables)) { - $cnt = $db->query("SELECT COUNT(*) as c FROM web_session_log")->fetchArray(SQLITE3_ASSOC)['c']; - echo "web_session_log rows: $cnt\n"; - } - - // Test batchGetPlayerIps - echo "\n--- Test batchGetPlayerIps ---\n"; - if (function_exists('batchGetPlayerIps') || class_exists('adminListUsersPaginated')) { - echo "batchGetPlayerIps function NOT available in this scope\n"; - } else { - echo "Function not available (defined in api/admin.php, not core.php)\n"; - } - - // Test simple queries that adminListUsersPaginated would run - echo "\n--- Test Query Simulation ---\n"; - try { - $sql = "SELECT player_name, register_time, last_login_time, points, total_online_time, email FROM users ORDER BY register_time DESC LIMIT 10 OFFSET 0"; - $result = $db->query($sql); - $count = 0; - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $count++; - } - echo "Users query OK, got $count rows\n"; - } catch (\Throwable $e) { - echo "Users query FAILED: " . $e->getMessage() . "\n"; - } - - // Test player_ip_changes query - try { - $stmt = $db->prepare("SELECT player_name, new_ip AS ip_address FROM player_ip_changes WHERE player_name IN ('test') ORDER BY changed_at DESC"); - echo "player_ip_changes simple query: OK (prepared)\n"; - } catch (\Throwable $e) { - echo "player_ip_changes query FAILED: " . $e->getMessage() . "\n"; - } - - // Test player_ip_locations query - try { - $stmt = $db->prepare("SELECT ip_address, location FROM player_ip_locations WHERE ip_address IN ('1.2.3.4')"); - echo "player_ip_locations query: OK (prepared)\n"; - } catch (\Throwable $e) { - echo "player_ip_locations query FAILED: " . $e->getMessage() . "\n"; - } - - // Test location search query - try { - $stmt = $db->prepare("SELECT player_name, new_ip FROM player_ip_changes WHERE new_ip != '' AND new_ip != '-' AND new_ip NOT LIKE '10.%' ORDER BY changed_at DESC LIMIT 5"); - $result = $stmt->execute(); - $ips = []; - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - $ips[] = $row['new_ip']; - } - echo "Location search pre-query: OK, got " . count($ips) . " IPs\n"; - } catch (\Throwable $e) { - echo "Location search pre-query FAILED: " . $e->getMessage() . "\n"; - } - - // Test region search SQL - try { - $searchBound = "%长沙%"; - $stmt = $db->prepare("SELECT COUNT(*) as cnt FROM player_ip_locations WHERE location LIKE :region"); - $stmt->bindValue(':region', $searchBound, SQLITE3_TEXT); - $cnt = $stmt->execute()->fetchArray(SQLITE3_ASSOC)['cnt']; - echo "Region cache check: $cnt matching records\n"; - } catch (\Throwable $e) { - echo "Region cache check FAILED: " . $e->getMessage() . "\n"; - } - -} catch (\Throwable $e) { - echo "\nFATAL ERROR: " . $e->getMessage() . "\n"; - echo "File: " . $e->getFile() . ":" . $e->getLine() . "\n"; - echo "Stack: " . $e->getTraceAsString() . "\n"; -} - -echo "\n=== Done ===\n"; diff --git a/web/debug_online.php b/web/debug_online.php deleted file mode 100644 index 1c4a19f..0000000 --- a/web/debug_online.php +++ /dev/null @@ -1,210 +0,0 @@ -query("SELECT * FROM online_players ORDER BY login_time DESC")->fetchArray(SQLITE3_ASSOC); - $onlinePlayers = []; - while ($row = $db->query("SELECT * FROM online_players ORDER BY login_time DESC")->fetchArray(SQLITE3_ASSOC)) { - $onlinePlayers[] = $row; - } - // 重新查询 - $stmt = $db->query("SELECT * FROM online_players ORDER BY login_time DESC"); - $onlinePlayers = []; - while ($row = $stmt->fetchArray(SQLITE3_ASSOC)) { - $onlinePlayers[] = $row; - } - $result['online_players'] = $onlinePlayers; - $result['online_players_count'] = count($onlinePlayers); -} catch (Exception $e) { - $result['online_players_error'] = $e->getMessage(); -} - -// 2. online_player_hb表(心跳) -try { - $stmt = $db->query("SELECT * FROM online_player_hb"); - $hb = $stmt->fetchArray(SQLITE3_ASSOC); - $result['heartbeat'] = $hb; - if ($hb) { - $result['heartbeat_ago'] = time() - (int)$hb['last_seen'] . '秒前'; - } -} catch (Exception $e) { - $result['heartbeat_error'] = $e->getMessage(); -} - -// 3. weblogin_tokens表 -try { - $stmt = $db->query("SELECT player_name, created_at, expire_seconds, datetime(created_at, 'unixepoch', 'localtime') as created_time FROM weblogin_tokens ORDER BY created_at DESC LIMIT 20"); - $tokens = []; - while ($row = $stmt->fetchArray(SQLITE3_ASSOC)) { - $tokens[] = $row; - } - $result['weblogin_tokens'] = $tokens; -} catch (Exception $e) { - $result['tokens_error'] = $e->getMessage(); -} - -// 4. web_session_log表 -try { - $stmt = $db->query("SELECT player_name, login_time, datetime(login_time, 'unixepoch', 'localtime') as login_time_str FROM web_session_log ORDER BY login_time DESC LIMIT 20"); - $sessions = []; - while ($row = $stmt->fetchArray(SQLITE3_ASSOC)) { - $sessions[] = $row; - } - $result['web_session_log'] = $sessions; -} catch (Exception $e) { - $result['sessions_error'] = $e->getMessage(); -} - -// 5. web_login_verified表 -try { - $stmt = $db->query("SELECT * FROM web_login_verified ORDER BY verified_at DESC LIMIT 20"); - $verified = []; - while ($row = $stmt->fetchArray(SQLITE3_ASSOC)) { - $verified[] = $row; - } - $result['web_login_verified'] = $verified; -} catch (Exception $e) { - $result['verified_error'] = $e->getMessage(); -} - -// 6. users表(部分) -try { - $stmt = $db->query("SELECT player_name, logged_in FROM users LIMIT 20"); - $users = []; - while ($row = $stmt->fetchArray(SQLITE3_ASSOC)) { - $users[] = $row; - } - $result['users'] = $users; -} catch (Exception $e) { - $result['users_error'] = $e->getMessage(); -} -?> - - - - 调试 - Online Players - - - -

🔍 Online Players 调试页面

- -

当前时间:

- -

1. online_players 表 (Java推送的游戏登录状态)

- -

⚠️ 表为空!没有玩家被标记为游戏中已登录

- - - - - - - - - - -
玩家名登录时间时间戳
- -

总数:

- -

2. 心跳 (online_player_hb)

- -

上次心跳: ()

- 120) echo '

⚠️ 心跳超过120秒,下次同步时PHP会清空online_players表!

'; - elseif ($ago > 60) echo '

⚠️ 心跳超过60秒

'; - else echo '

✅ 心跳正常

'; - ?> - -

⚠️ 无心跳记录

- - -

3. weblogin_tokens (Web登录Token)

- -

⚠️ 无Token记录

- - - - - - - - - - -
玩家创建时间有效期(秒)
- - -

4. web_session_log (Web会话记录)

- -

⚠️ 无会话记录

- - - - - - - - - - -
玩家登录时间时间戳
- - -

5. web_login_verified (Web密码验证)

- -

⚠️ 无验证记录

- - - - - - - - - -
玩家验证时间
- - -

6. users表 (玩家注册状态)

- -

⚠️ 无注册玩家

- - - - - - - - - -
玩家名logged_in
- - -

原始JSON

-
- - diff --git a/web/debug_region.php b/web/debug_region.php deleted file mode 100644 index cc2d23e..0000000 --- a/web/debug_region.php +++ /dev/null @@ -1,142 +0,0 @@ -调试地区搜索"; - -// 1. player_ip_locations 表内容 -echo "

player_ip_locations 表

"; -try { - $result = $db->query("SELECT COUNT(*) as cnt FROM player_ip_locations"); - $row = $result->fetchArray(SQLITE3_ASSOC); - echo "总记录数: " . $row['cnt'] . "
"; - - if ($row['cnt'] > 0) { - echo ""; - echo ""; - $result = $db->query("SELECT * FROM player_ip_locations ORDER BY updated_at DESC LIMIT 20"); - while ($r = $result->fetchArray(SQLITE3_ASSOC)) { - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - } - echo "
ip_addresslocationplayer_nameupdated_at
" . htmlspecialchars($r['ip_address']) . "" . htmlspecialchars($r['location']) . "" . htmlspecialchars($r['player_name']) . "" . date('Y-m-d H:i:s', $r['updated_at']) . "
"; - } else { - echo "表为空!
"; - } -} catch (Exception $e) { - echo "错误: " . $e->getMessage() . "
"; -} - -// 2. player_ip_changes 表内容 -echo "

player_ip_changes 表

"; -try { - $result = $db->query("SELECT COUNT(*) as cnt FROM player_ip_changes"); - $row = $result->fetchArray(SQLITE3_ASSOC); - echo "总记录数: " . $row['cnt'] . "
"; - - if ($row['cnt'] > 0) { - echo ""; - echo ""; - $result = $db->query("SELECT * FROM player_ip_changes ORDER BY changed_at DESC LIMIT 20"); - while ($r = $result->fetchArray(SQLITE3_ASSOC)) { - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; - } - echo "
player_namenew_ipchanged_at
" . htmlspecialchars($r['player_name']) . "" . htmlspecialchars($r['new_ip']) . "" . date('Y-m-d H:i:s', $r['changed_at']) . "
"; - } else { - echo "表为空!
"; - } -} catch (Exception $e) { - echo "错误: " . $e->getMessage() . "
"; -} - -// 3. 地区搜索SQL测试 -echo "

地区搜索SQL测试

"; -$search = '长沙'; -$regionKey = $search; - -// 测试JOIN -$sql = "SELECT c.player_name FROM player_ip_changes c - INNER JOIN player_ip_locations l ON c.new_ip = l.ip_address - WHERE l.location LIKE '%$regionKey%' AND c.new_ip != '' AND c.new_ip != '-' - GROUP BY c.player_name"; -echo "SQL:
" . htmlspecialchars($sql) . "
"; - -try { - $result = $db->query($sql); - $count = 0; - $players = []; - while ($r = $result->fetchArray(SQLITE3_ASSOC)) { - $count++; - $players[] = $r['player_name']; - } - echo "匹配玩家数: $count
"; - if ($count > 0) { - echo "匹配玩家: " . implode(', ', $players) . "
"; - } -} catch (Exception $e) { - echo "SQL错误: " . $e->getMessage() . "
"; -} - -// 4. 检查所有location中包含"长沙"的 -echo "

包含'长沙'的location记录

"; -try { - $result = $db->query("SELECT ip_address, location, player_name FROM player_ip_locations WHERE location LIKE '%长沙%'"); - $found = false; - while ($r = $result->fetchArray(SQLITE3_ASSOC)) { - $found = true; - echo "IP: " . htmlspecialchars($r['ip_address']) . " → " . htmlspecialchars($r['location']) . "
"; - } - if (!$found) { - echo "没有找到包含'长沙'的location记录
"; - } -} catch (Exception $e) { - echo "错误: " . $e->getMessage() . "
"; -} - -// 5. 检查users表中是否有来自长沙的玩家(通过IP推断) -echo "

测试:直接搜索users表

"; -try { - $result = $db->query("SELECT player_name, email FROM users LIMIT 10"); - while ($r = $result->fetchArray(SQLITE3_ASSOC)) { - echo "玩家: " . htmlspecialchars($r['player_name']) . " (email: " . htmlspecialchars($r['email']) . ")
"; - } -} catch (Exception $e) { - echo "错误: " . $e->getMessage() . "
"; -} - -// 6. 尝试手动查询一个IP的归属地 -echo "

测试:手动查询IP归属地

"; -try { - $result = $db->query("SELECT DISTINCT new_ip FROM player_ip_changes WHERE new_ip != '' AND new_ip != '-' AND new_ip NOT LIKE '10.%' AND new_ip NOT LIKE '192.168.%' AND new_ip != '127.0.0.1' LIMIT 5"); - $ips = []; - while ($r = $result->fetchArray(SQLITE3_ASSOC)) { - $ips[] = $r['new_ip']; - } - - if (!empty($ips)) { - echo "测试查询以下IP的归属地: " . implode(', ', $ips) . "
"; - require_once 'api/admin.php'; - foreach ($ips as $ip) { - $loc = queryIpLocationWithTimeout($ip, 3); - echo "IP: $ip → " . ($loc ? $loc['location'] : 'null') . "
"; - } - } else { - echo "没有找到可用的外部IP
"; - } -} catch (Exception $e) { - echo "错误: " . $e->getMessage() . "
"; -} -?> diff --git a/web/debug_region_search.php b/web/debug_region_search.php deleted file mode 100644 index 82a838d..0000000 --- a/web/debug_region_search.php +++ /dev/null @@ -1,167 +0,0 @@ - 0) { @ob_end_clean(); } -header('Content-Type: text/plain; charset=utf-8'); -error_reporting(E_ALL); -ini_set('display_errors', '1'); - -echo "=== Region Search Debug v2 ===\n\n"; - -require_once __DIR__ . '/core.php'; - -try { - $db = getDB(); - echo "DB opened OK\n\n"; - - // 1. Check tables and data - echo "--- Data Overview ---\n"; - $tables = ['users', 'player_ip_changes', 'player_ip_locations', 'web_session_log']; - foreach ($tables as $table) { - try { - $cnt = $db->query("SELECT COUNT(*) as c FROM $table")->fetchArray(SQLITE3_ASSOC)['c']; - echo "$table: $cnt rows\n"; - } catch (\Throwable $e) { - echo "$table: ERROR - " . $e->getMessage() . "\n"; - } - } - - // 2. Check player_ip_locations samples - echo "\n--- player_ip_locations Samples ---\n"; - try { - $result = $db->query("SELECT ip_address, location, player_name FROM player_ip_locations LIMIT 10"); - while ($row = $result->fetchArray(SQLITE3_ASSOC)) { - echo " {$row['ip_address']} => '{$row['location']}' (player: {$row['player_name']})\n"; - } - } catch (\Throwable $e) { - echo " ERROR: " . $e->getMessage() . "\n"; - } - - // 3. Test region search for "长沙" - $regionKey = '长沙'; - echo "\n--- Testing Region Search: '$regionKey' ---\n"; - - // Step 1: Find IPs with matching location - try { - $locStmt = $db->prepare("SELECT ip_address FROM player_ip_locations WHERE location LIKE :region"); - $locStmt->bindValue(':region', "%$regionKey%", SQLITE3_TEXT); - $locResult = $locStmt->execute(); - $matchedIps = []; - while ($locRow = $locResult->fetchArray(SQLITE3_ASSOC)) { - $matchedIps[] = $locRow['ip_address']; - } - echo "Step 1: Found " . count($matchedIps) . " IPs with '$regionKey' location\n"; - if (!empty($matchedIps)) { - echo " IPs: " . implode(', ', array_slice($matchedIps, 0, 10)) . "\n"; - } - } catch (\Throwable $e) { - echo "Step 1 ERROR: " . $e->getMessage() . "\n"; - $matchedIps = []; - } - - // Step 2: Find players using those IPs - $matchedPlayers = []; - if (!empty($matchedIps)) { - $ipPlaceholders = implode(',', array_fill(0, count($matchedIps), '?')); - - // From player_ip_changes - try { - $pStmt = $db->prepare("SELECT DISTINCT player_name FROM player_ip_changes WHERE new_ip IN ($ipPlaceholders)"); - $idx = 1; - foreach ($matchedIps as $ip) { $pStmt->bindValue($idx++, $ip, SQLITE3_TEXT); } - $pResult = $pStmt->execute(); - while ($pRow = $pResult->fetchArray(SQLITE3_ASSOC)) { - $matchedPlayers[] = $pRow['player_name']; - } - echo "Step 2a (player_ip_changes): Found " . count($matchedPlayers) . " players\n"; - } catch (\Throwable $e) { - echo "Step 2a ERROR: " . $e->getMessage() . "\n"; - } - - // From web_session_log - try { - $wStmt = $db->prepare("SELECT DISTINCT player_name FROM web_session_log WHERE ip_address IN ($ipPlaceholders)"); - $idx = 1; - foreach ($matchedIps as $ip) { $wStmt->bindValue($idx++, $ip, SQLITE3_TEXT); } - $wResult = $wStmt->execute(); - $beforeCount = count($matchedPlayers); - while ($wRow = $wResult->fetchArray(SQLITE3_ASSOC)) { - if (!in_array($wRow['player_name'], $matchedPlayers)) { - $matchedPlayers[] = $wRow['player_name']; - } - } - echo "Step 2b (web_session_log): Found " . (count($matchedPlayers) - $beforeCount) . " new players\n"; - } catch (\Throwable $e) { - echo "Step 2b ERROR: " . $e->getMessage() . "\n"; - } - - echo "Step 2 Total: " . count($matchedPlayers) . " players\n"; - if (!empty($matchedPlayers)) { - echo " Players: " . implode(', ', array_slice($matchedPlayers, 0, 10)) . "\n"; - } - } - - // Step 3: Query users - if (!empty($matchedPlayers)) { - $namePlaceholders = implode(',', array_fill(0, count($matchedPlayers), '?')); - try { - $uStmt = $db->prepare("SELECT player_name, email FROM users WHERE player_name IN ($namePlaceholders) LIMIT 5"); - $idx = 1; - foreach ($matchedPlayers as $pn) { $uStmt->bindValue($idx++, $pn, SQLITE3_TEXT); } - $uResult = $uStmt->execute(); - $users = []; - while ($uRow = $uResult->fetchArray(SQLITE3_ASSOC)) { - $users[] = $uRow; - } - echo "Step 3: Found " . count($users) . " users\n"; - foreach ($users as $u) { - echo " {$u['player_name']} ({$u['email']})\n"; - } - } catch (\Throwable $e) { - echo "Step 3 ERROR: " . $e->getMessage() . "\n"; - } - } else { - echo "Step 3: Skipped (no matching players)\n"; - } - - // 4. Also check what batchGetPlayerIps would return for all users - echo "\n--- batchGetPlayerIps Check ---\n"; - try { - $allUsers = $db->query("SELECT player_name FROM users")->fetchArray(SQLITE3_ASSOC); - // Get a sample user - $sampleUser = 'youpaishidifu'; - $stmt = $db->prepare("SELECT player_name, new_ip FROM player_ip_changes WHERE player_name = :name ORDER BY changed_at DESC LIMIT 1"); - $stmt->bindValue(':name', $sampleUser, SQLITE3_TEXT); - $result = $stmt->execute()->fetchArray(SQLITE3_ASSOC); - if ($result) { - echo "$sampleUser IP from player_ip_changes: {$result['new_ip']}\n"; - // Check if this IP has location - $locStmt = $db->prepare("SELECT location FROM player_ip_locations WHERE ip_address = :ip"); - $locStmt->bindValue(':ip', $result['new_ip'], SQLITE3_TEXT); - $locResult = $locStmt->execute()->fetchArray(SQLITE3_ASSOC); - echo " Location: " . ($locResult ? $locResult['location'] : 'NOT FOUND') . "\n"; - } else { - echo "$sampleUser NOT in player_ip_changes\n"; - // Check web_session_log - $stmt2 = $db->prepare("SELECT ip_address FROM web_session_log WHERE player_name = :name ORDER BY login_time DESC LIMIT 1"); - $stmt2->bindValue(':name', $sampleUser, SQLITE3_TEXT); - $result2 = $stmt2->execute()->fetchArray(SQLITE3_ASSOC); - if ($result2) { - echo "$sampleUser IP from web_session_log: {$result2['ip_address']}\n"; - $locStmt2 = $db->prepare("SELECT location FROM player_ip_locations WHERE ip_address = :ip"); - $locStmt2->bindValue(':ip', $result2['ip_address'], SQLITE3_TEXT); - $locResult2 = $locStmt2->execute()->fetchArray(SQLITE3_ASSOC); - echo " Location: " . ($locResult2 ? $locResult2['location'] : 'NOT FOUND') . "\n"; - } else { - echo "$sampleUser NOT in web_session_log either\n"; - } - } - } catch (\Throwable $e) { - echo "batchGetPlayerIps check ERROR: " . $e->getMessage() . "\n"; - } - -} catch (\Throwable $e) { - echo "\nFATAL ERROR: " . $e->getMessage() . "\n"; -} - -echo "\n=== Done ===\n"; -?> \ No newline at end of file diff --git a/web/self_update.php b/web/self_update.php deleted file mode 100644 index 2c7240f..0000000 --- a/web/self_update.php +++ /dev/null @@ -1,98 +0,0 @@ - \ No newline at end of file diff --git a/web/upload_debug.php b/web/upload_debug.php deleted file mode 100644 index 58c7f36..0000000 --- a/web/upload_debug.php +++ /dev/null @@ -1,32 +0,0 @@ - \ No newline at end of file diff --git a/web/upload_via_http.php b/web/upload_via_http.php deleted file mode 100644 index 05fb00d..0000000 --- a/web/upload_via_http.php +++ /dev/null @@ -1,295 +0,0 @@ -enableExceptions(false); - - echo "\n=== Table Row Counts ===\n"; - $tables = ['users', 'player_ip_changes', 'player_ip_locations', 'web_session_log', 'online_players', 'player_daily_logins', 'player_checkins']; - foreach ($tables as $t) { - try { - $cnt = $db->querySingle("SELECT COUNT(*) FROM $t"); - echo "$t: $cnt rows\n"; - } catch (\Throwable $e) { - echo "$t: ERROR - " . $e->getMessage() . "\n"; - } - } - - // 检查 player_ip_locations 中的格式 - echo "\n=== IP Location Samples (first 10) ===\n"; - try { - $r = $db->query("SELECT ip_address, location, player_name FROM player_ip_locations LIMIT 10"); - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - echo $row['ip_address'] . " => " . $row['location'] . " (player: " . $row['player_name'] . ")\n"; - } - } catch (\Throwable $e) { - echo "ERROR: " . $e->getMessage() . "\n"; - } - - // 检查 player_ip_changes 中的玩家IP - echo "\n=== Player IP Changes Samples (first 10) ===\n"; - try { - $r = $db->query("SELECT player_name, new_ip, changed_at FROM player_ip_changes ORDER BY changed_at DESC LIMIT 10"); - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - echo $row['player_name'] . " => " . $row['new_ip'] . " (at: " . date('Y-m-d H:i:s', $row['changed_at']) . ")\n"; - } - } catch (\Throwable $e) { - echo "ERROR: " . $e->getMessage() . "\n"; - } - - // 检查 web_session_log 中的玩家IP - echo "\n=== Web Session Log Samples (first 10) ===\n"; - try { - $r = $db->query("SELECT player_name, ip_address, login_time FROM web_session_log ORDER BY login_time DESC LIMIT 10"); - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - echo $row['player_name'] . " => " . $row['ip_address'] . " (at: " . date('Y-m-d H:i:s', $row['login_time']) . ")\n"; - } - } catch (\Throwable $e) { - echo "ERROR: " . $e->getMessage() . "\n"; - } - - // 检查 region 搜索模拟 - echo "\n=== Region Search Simulation for '长沙' ===\n"; - echo "Step 1: player_ip_locations with '长沙':\n"; - try { - $r = $db->query("SELECT ip_address, location FROM player_ip_locations WHERE location LIKE '%长沙%'"); - $cnt = 0; - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - echo " " . $row['ip_address'] . " => " . $row['location'] . "\n"; - $cnt++; - } - echo " Found: $cnt IPs\n"; - } catch (\Throwable $e) { - echo " ERROR: " . $e->getMessage() . "\n"; - } - - // 查找有长沙IP的玩家 - echo "\nStep 2: Players with 长沙 IPs:\n"; - try { - $r = $db->query(" - SELECT DISTINCT c.player_name - FROM player_ip_changes c - INNER JOIN player_ip_locations l ON c.new_ip = l.ip_address - WHERE l.location LIKE '%长沙%' - UNION - SELECT DISTINCT w.player_name - FROM web_session_log w - INNER JOIN player_ip_locations l ON w.ip_address = l.ip_address - WHERE l.location LIKE '%长沙%' - "); - $cnt = 0; - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - echo " " . $row['player_name'] . "\n"; - $cnt++; - } - echo " Found: $cnt players\n"; - } catch (\Throwable $e) { - echo " ERROR: " . $e->getMessage() . "\n"; - } - - $db->close(); - } else { - echo "Database not found!\n"; - } - - echo "\n=== admin.php Version ===\n"; - $adminFile = __DIR__ . '/api/admin.php'; - if (file_exists($adminFile)) { - $content = file_get_contents($adminFile); - echo "File size: " . filesize($adminFile) . " bytes\n"; - echo "Has _region_debug: " . (strpos($content, '_region_debug') !== false ? 'YES' : 'NO') . "\n"; - echo "Has regionDebugEnabled: " . (strpos($content, 'regionDebugEnabled') !== false ? 'YES' : 'NO') . "\n"; - echo "Has batchGetPlayerIps: " . (strpos($content, 'function batchGetPlayerIps') !== false ? 'YES' : 'NO') . "\n"; - } else { - echo "admin.php not found!\n"; - } - - // ★ 模拟 admin 的精确 region search 逻辑 - echo "\n=== Simulate Admin Region Search Logic ===\n"; - $db = new SQLite3(DB_PATH); - $db->enableExceptions(false); - - $regionKey = '长沙'; - - // Step 1: Get all player names - $allPlayerNames = []; - $r = $db->query("SELECT player_name FROM users"); - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - $allPlayerNames[] = $row['player_name']; - } - echo "All players: " . count($allPlayerNames) . "\n"; - - // Step 2: Build playerIpMap from player_ip_changes - $playerIpMap = []; - $stmt = $db->prepare("SELECT player_name, new_ip FROM player_ip_changes WHERE new_ip != '' AND new_ip != '-' AND new_ip NOT LIKE '10.%' AND new_ip NOT LIKE '192.168.%' AND new_ip != '127.0.0.1'"); - $r = $stmt->execute(); - $changesCount = 0; - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - $changesCount++; - $pn = $row['player_name']; - $ip = trim($row['new_ip']); - if (!isset($playerIpMap[$pn])) $playerIpMap[$pn] = []; - if (!in_array($ip, $playerIpMap[$pn])) $playerIpMap[$pn][] = $ip; - } - echo "player_ip_changes rows: $changesCount\n"; - echo "Players with IPs from changes: " . count($playerIpMap) . "\n"; - - // web_session_log is empty, skip - echo "web_session_log rows: 0 (skipped)\n"; - - // Step 3: Get IP locations - $ipLocMap = []; - $r = $db->query("SELECT ip_address, location FROM player_ip_locations"); - while ($row = $r->fetchArray(SQLITE3_ASSOC)) { - $loc = trim($row['location'] ?? ''); - $ip = trim($row['ip_address'] ?? ''); - if ($loc && $ip) { - $ipLocMap[$ip] = $loc; - } - } - echo "IP locations cached: " . count($ipLocMap) . "\n"; - - // Show some sample IP from playerIpMap vs ipLocMap - echo "\n--- IP Comparison ---\n"; - $samplePlayers = array_slice(array_keys($playerIpMap), 0, 5); - foreach ($samplePlayers as $pn) { - $ips = $playerIpMap[$pn]; - echo "Player: $pn => IPs: " . implode(', ', $ips) . "\n"; - foreach ($ips as $ip) { - if (isset($ipLocMap[$ip])) { - echo " FOUND in cache: $ip => " . $ipLocMap[$ip] . "\n"; - } else { - echo " NOT in cache: $ip\n"; - } - } - } - - // Step 4: PHP matching - $matchedPlayers = []; - $matchDebug = []; - foreach ($playerIpMap as $pn => $ips) { - foreach ($ips as $ip) { - if (isset($ipLocMap[$ip])) { - $loc = $ipLocMap[$ip]; - if (mb_stripos($loc, $regionKey) !== false) { - if (!in_array($pn, $matchedPlayers)) $matchedPlayers[] = $pn; - $matchDebug[] = "$ip=>$loc ($pn)"; - break; - } - } - } - } - echo "\n=== PHP Match Result ===\n"; - echo "Matched players: " . count($matchedPlayers) . "\n"; - foreach ($matchedPlayers as $pn) { - echo " $pn\n"; - } - - // Check if any 长沙 IPs are NOT in the playerIpMap - echo "\n--- All 长沙 IPs in cache ---\n"; - foreach ($ipLocMap as $ip => $loc) { - if (mb_stripos($loc, $regionKey) !== false) { - echo " $ip => $loc\n"; - // Check which player has this IP - $foundPlayer = false; - foreach ($playerIpMap as $pn => $ips) { - if (in_array($ip, $ips)) { - echo " Has player: $pn\n"; - $foundPlayer = true; - break; - } - } - if (!$foundPlayer) { - echo " NO player found with this IP!\n"; - // Try partial match - foreach ($playerIpMap as $pn => $ips) { - foreach ($ips as $pip) { - if (strpos($ip, $pip) !== false || strpos($pip, $ip) !== false) { - echo " Partial match: $pip (player: $pn)\n"; - } - } - } - } - } - } - - $db->close(); - -} elseif ($action === 'upload' || (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK)) { - // 通过 POST 上传文件 - // 支持 target= 和 path= 两种参数名 - $target = $_POST['target'] ?? $_POST['path'] ?? ''; - $allowed = ['api/admin.php', 'api/sync.php', 'api/cdk.php', 'api/ticket.php', 'api/register.php', 'api/shop.php', 'api/balance.php', 'core.php', 'config.php', 'player.php', 'admin.php', 'service.php', 'upload_via_http.php']; - - if (!in_array($target, $allowed)) { - echo "ERROR: Target not allowed: $target\nAllowed: " . implode(', ', $allowed) . "\n"; - exit; - } - - $targetPath = __DIR__ . '/' . $target; - - if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) { - $content = file_get_contents($_FILES['file']['tmp_name']); - } elseif (isset($_POST['content'])) { - $content = base64_decode($_POST['content']); - } else { - $content = file_get_contents('php://input'); - } - - if (empty($content)) { - echo "ERROR: No content\n"; - exit; - } - - if (file_exists($targetPath)) { - copy($targetPath, $targetPath . '.bak'); - } - - $bytes = file_put_contents($targetPath, $content); - echo "Wrote $bytes bytes to $target\n"; - echo "MD5: " . md5_file($targetPath) . "\n"; - - if (function_exists('opcache_invalidate')) { - @opcache_invalidate($targetPath, true); - } - if (function_exists('opcache_reset')) { - @opcache_reset(); - } - echo "OPCache cleared\n"; -} - -echo "\nDone.\n"; -@ob_end_flush(); -?> \ No newline at end of file diff --git a/web/version_check.php b/web/version_check.php deleted file mode 100644 index d01ed4d..0000000 --- a/web/version_check.php +++ /dev/null @@ -1,8 +0,0 @@ - \ No newline at end of file