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推送的游戏登录状态)
-
- ⚠️ 表为空!没有玩家被标记为游戏中已登录
-
-
- 玩家名 登录时间 时间戳
-
-
- = htmlspecialchars($p['player_name']) ?>
- = date('Y-m-d H:i:s', (int)$p['login_time']) ?>
- = $p['login_time'] ?>
-
-
-
-
- 总数: = $result['online_players_count'] ?>
-
- 2. 心跳 (online_player_hb)
-
- 上次心跳: = date('Y-m-d H:i:s', (int)$result['heartbeat']['last_seen']) ?> (= $result['heartbeat_ago'] ?> )
- 120) echo '⚠️ 心跳超过120秒,下次同步时PHP会清空online_players表!
';
- elseif ($ago > 60) echo '⚠️ 心跳超过60秒
';
- else echo '✅ 心跳正常
';
- ?>
-
- ⚠️ 无心跳记录
-
-
- 3. weblogin_tokens (Web登录Token)
-
- ⚠️ 无Token记录
-
-
- 玩家 创建时间 有效期(秒)
-
-
- = htmlspecialchars($t['player_name']) ?>
- = $t['created_time'] ?>
- = $t['expire_seconds'] ?>
-
-
-
-
-
- 4. web_session_log (Web会话记录)
-
- ⚠️ 无会话记录
-
-
- 玩家 登录时间 时间戳
-
-
- = htmlspecialchars($s['player_name']) ?>
- = $s['login_time_str'] ?>
- = $s['login_time'] ?>
-
-
-
-
-
- 5. web_login_verified (Web密码验证)
-
- ⚠️ 无验证记录
-
-
- 玩家 验证时间
-
-
- = htmlspecialchars($v['player_name']) ?>
- = date('Y-m-d H:i:s', (int)$v['verified_at']) ?>
-
-
-
-
-
- 6. users表 (玩家注册状态)
-
- ⚠️ 无注册玩家
-
-
- 玩家名 logged_in
-
-
- = htmlspecialchars($u['player_name']) ?>
- = $u['logged_in'] ? '✅ 已登录' : '❌ 未登录' ?>
-
-
-
-
-
- 原始JSON
- = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) ?>
-
-
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 "ip_address location player_name updated_at ";
- $result = $db->query("SELECT * FROM player_ip_locations ORDER BY updated_at DESC LIMIT 20");
- while ($r = $result->fetchArray(SQLITE3_ASSOC)) {
- echo "";
- echo "" . htmlspecialchars($r['ip_address']) . " ";
- echo "" . htmlspecialchars($r['location']) . " ";
- echo "" . htmlspecialchars($r['player_name']) . " ";
- echo "" . date('Y-m-d H:i:s', $r['updated_at']) . " ";
- echo " ";
- }
- echo "
";
- } 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 "player_name new_ip changed_at ";
- $result = $db->query("SELECT * FROM player_ip_changes ORDER BY changed_at DESC LIMIT 20");
- while ($r = $result->fetchArray(SQLITE3_ASSOC)) {
- echo "";
- echo "" . htmlspecialchars($r['player_name']) . " ";
- echo "" . htmlspecialchars($r['new_ip']) . " ";
- echo "" . date('Y-m-d H:i:s', $r['changed_at']) . " ";
- echo " ";
- }
- echo "
";
- } 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