fix: 修复Web轮询500错误 — 移除只读函数的BEGIN IMMEDIATE、catch(Exception)→catch(Throwable)、增加错误日志
This commit is contained in:
+69
-61
@@ -517,8 +517,8 @@ function syncTransactions() {
|
||||
)");
|
||||
|
||||
// 索引用于查询加速
|
||||
try { $db->exec("CREATE INDEX IF NOT EXISTS idx_gt_player ON game_transactions(player_name, tx_time)"); } catch (Exception $e) {}
|
||||
try { $db->exec("CREATE INDEX IF NOT EXISTS idx_gt_type ON game_transactions(type)"); } catch (Exception $e) {}
|
||||
try { $db->exec("CREATE INDEX IF NOT EXISTS idx_gt_player ON game_transactions(player_name, tx_time)"); } catch (\Throwable $e) {}
|
||||
try { $db->exec("CREATE INDEX IF NOT EXISTS idx_gt_type ON game_transactions(type)"); } catch (\Throwable $e) {}
|
||||
|
||||
$now = time();
|
||||
$count = 0;
|
||||
@@ -558,7 +558,7 @@ function syncTransactions() {
|
||||
}
|
||||
}
|
||||
$db->exec("COMMIT");
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
$db->exec("ROLLBACK");
|
||||
@error_log("[syncTransactions] Transaction failed, rolled back: " . $e->getMessage());
|
||||
throw $e;
|
||||
@@ -571,7 +571,7 @@ function syncTransactions() {
|
||||
]);
|
||||
|
||||
success(['synced' => $count, 'skipped' => $skipped, 'total' => count($transactions)], "同步了{$count}笔游戏交易");
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[syncTransactions] EXCEPTION: " . $e->getMessage() . " at " . $e->getTraceAsString());
|
||||
error('syncTransactions异常: ' . $e->getMessage());
|
||||
}
|
||||
@@ -655,7 +655,7 @@ function syncLogin() {
|
||||
$db->exec("DELETE FROM users WHERE player_name IN ('" . $nameList . "')");
|
||||
debugLog("sync_login: 清理了 " . count($orphanedUsers) . " 个孤立的 users 记录", ['orphaned' => $orphanedUsers]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
debugLog("sync_login: 清理孤立 users 记录失败", ['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
@@ -676,7 +676,7 @@ function syncLogin() {
|
||||
$db->exec("DELETE FROM weblogin_credentials WHERE player_name IN ('" . $nameList . "')");
|
||||
debugLog("sync_login: 清理了 " . count($orphaned) . " 个孤立的 weblogin_credentials 记录", ['orphaned' => $orphaned]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
debugLog("sync_login: 清理孤立 weblogin_credentials 记录失败", ['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
@@ -684,23 +684,23 @@ function syncLogin() {
|
||||
try {
|
||||
$expireTime = time() - 600;
|
||||
$db->exec("DELETE FROM weblogin_tokens WHERE created_at < " . $expireTime);
|
||||
} catch (Exception $e) {}
|
||||
} catch (\Throwable $e) {}
|
||||
|
||||
// 清理 web_login_verified:只清理已过期的
|
||||
try {
|
||||
$expireTime = time() - 600;
|
||||
$db->exec("DELETE FROM web_login_verified WHERE verified_at < " . $expireTime);
|
||||
} catch (Exception $e) {}
|
||||
} catch (\Throwable $e) {}
|
||||
|
||||
// 清理 web_session_log:只清理过期的
|
||||
try {
|
||||
$expireTime = time() - 600;
|
||||
$db->exec("DELETE FROM web_session_log WHERE login_time < " . $expireTime);
|
||||
} catch (Exception $e) {}
|
||||
} catch (\Throwable $e) {}
|
||||
|
||||
$db->exec("COMMIT");
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
}
|
||||
|
||||
debugLog("sync_login: 同步完成", ['synced_count' => $count, 'cleared_users' => ($orphanedUsers ?? []) ? count($orphanedUsers) : 0]);
|
||||
@@ -739,7 +739,7 @@ function deleteUser() {
|
||||
$stmt->bindValue(':player', $playerName, SQLITE3_TEXT);
|
||||
$stmt->execute();
|
||||
$deleted++;
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// 表可能不存在,跳过
|
||||
}
|
||||
}
|
||||
@@ -889,7 +889,7 @@ function syncOnlinePlayers() {
|
||||
$db->exec("INSERT INTO online_player_hb (id, last_seen) VALUES (1, $oldVal)");
|
||||
@error_log("[syncOnlinePlayers] 迁移online_player_hb表结构完成,旧值: $oldVal");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[syncOnlinePlayers] 迁移online_player_hb失败: " . $e->getMessage());
|
||||
}
|
||||
|
||||
@@ -906,7 +906,7 @@ function syncOnlinePlayers() {
|
||||
$db->exec("DELETE FROM online_players");
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@@ -945,7 +945,7 @@ function syncOnlinePlayers() {
|
||||
$stmt->bindValue(':time', $loginTime, SQLITE3_INTEGER);
|
||||
$stmt->execute();
|
||||
$synced++;
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[syncOnlinePlayers] FAIL insert $name: " . $e->getMessage());
|
||||
}
|
||||
|
||||
@@ -970,7 +970,7 @@ function syncOnlinePlayers() {
|
||||
$ipStmt->execute();
|
||||
@error_log("[syncOnlinePlayers] IP更新: {$name} {$oldIp}→{$ip}");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[syncOnlinePlayers] IP写入失败 {$name}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -981,13 +981,13 @@ function syncOnlinePlayers() {
|
||||
$hbSql = $db->prepare("INSERT OR REPLACE INTO online_player_hb (id, last_seen) VALUES (1, :time)");
|
||||
$hbSql->bindValue(':time', $now, SQLITE3_INTEGER);
|
||||
$hbSql->execute();
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[syncOnlinePlayers] heartbeat update error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$db->exec("COMMIT");
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[syncOnlinePlayers] Transaction failed: " . $e->getMessage());
|
||||
}
|
||||
|
||||
@@ -1038,8 +1038,8 @@ function syncDailyLogins() {
|
||||
}
|
||||
$db->exec("COMMIT");
|
||||
success(['synced' => $count], "同步了{$count}条登录记录");
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[syncDailyLogins] Error: " . $e->getMessage());
|
||||
error('同步失败: ' . $e->getMessage());
|
||||
}
|
||||
@@ -1081,8 +1081,8 @@ function syncCheckins() {
|
||||
}
|
||||
$db->exec("COMMIT");
|
||||
success(['synced' => $count], "同步了{$count}条签到记录");
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[syncCheckins] Error: " . $e->getMessage());
|
||||
error('同步失败: ' . $e->getMessage());
|
||||
}
|
||||
@@ -1182,8 +1182,8 @@ function syncPlayerIps() {
|
||||
}
|
||||
|
||||
$db->exec("COMMIT");
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[syncPlayerIps] Transaction failed: " . $e->getMessage());
|
||||
}
|
||||
|
||||
@@ -1274,8 +1274,8 @@ function receiveToken() {
|
||||
$count++;
|
||||
}
|
||||
$db->exec('COMMIT');
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec('ROLLBACK'); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec('ROLLBACK'); } catch (\Throwable $e2) {}
|
||||
@error_log("[receiveToken] Exception: " . $e->getMessage());
|
||||
error('Token注册失败: ' . $e->getMessage());
|
||||
}
|
||||
@@ -1392,7 +1392,7 @@ function apiValidateWebloginToken() {
|
||||
}
|
||||
|
||||
success(['player' => $row['player_name']], 'Token有效');
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
error('Token验证失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -1533,7 +1533,7 @@ function pushPlayerLoginStatus() {
|
||||
$ipStmt->execute();
|
||||
@error_log("[pushPlayerLoginStatus] IP更新: {$player} {$oldIp}→{$playerIp}");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[pushPlayerLoginStatus] IP写入失败 {$player}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -1555,7 +1555,7 @@ function pushPlayerLoginStatus() {
|
||||
$userStmt->bindValue(':time', $now, SQLITE3_INTEGER);
|
||||
$userStmt->bindValue(':player', $player, SQLITE3_TEXT);
|
||||
$userStmt->execute();
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
// users表可能不存在或其他错误,忽略
|
||||
}
|
||||
}
|
||||
@@ -1583,8 +1583,7 @@ function checkWebLoginConfirmations() {
|
||||
$db = getDB();
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS web_login_confirmations (player_name TEXT PRIMARY KEY, confirmed_at INTEGER NOT NULL, consumed INTEGER DEFAULT 0)");
|
||||
|
||||
// ★ 事务包裹所有写操作
|
||||
$db->exec("BEGIN IMMEDIATE");
|
||||
// ★ 不使用BEGIN IMMEDIATE(纯读+更新,减少锁冲突)
|
||||
try {
|
||||
// ★ 清理超过10分钟的过期确认记录
|
||||
$expireTime = time() - 600;
|
||||
@@ -1608,10 +1607,8 @@ function checkWebLoginConfirmations() {
|
||||
// 清理30分钟前的已消费记录
|
||||
$db->exec("DELETE FROM web_login_confirmations WHERE consumed = 1 AND confirmed_at < " . (time() - 1800));
|
||||
}
|
||||
|
||||
$db->exec("COMMIT");
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[checkWebLoginConfirmations] error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
success($confirmations);
|
||||
@@ -1858,7 +1855,7 @@ function checkWebLoginResult() {
|
||||
'message' => $resultData['error'] ?? '密码错误'
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
error('数据库查询失败: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -1881,17 +1878,15 @@ function checkPendingWebLogins() {
|
||||
result_time INTEGER DEFAULT 0
|
||||
)");
|
||||
|
||||
// ★ 事务包裹清理操作
|
||||
$db->exec("BEGIN IMMEDIATE");
|
||||
// ★ 只读查询不需要BEGIN IMMEDIATE(避免与其它并发请求抢锁导致500)
|
||||
// 清理10分钟前的过期请求(DELETE即使失败也不影响读取pending)
|
||||
try {
|
||||
// 清理10分钟前的过期请求
|
||||
$db->exec("DELETE FROM web_login_requests WHERE request_time < " . (time() - 600));
|
||||
$db->exec("COMMIT");
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[checkPendingWebLogins] cleanup error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
// 获取所有pending请求(只返回id、player_name、password,不返回密码明文给前端)
|
||||
// 获取所有pending请求
|
||||
$stmt = $db->prepare("SELECT id, player_name, password FROM web_login_requests WHERE status = 'pending'");
|
||||
$result = $stmt->execute();
|
||||
|
||||
@@ -2115,7 +2110,7 @@ function webAccessCheck() {
|
||||
$isExpired = $age > $expire ? 'EXPIRED' : 'valid';
|
||||
@error_log("[web_access_check] DB token: player=" . $row['player_name'] . ", token=" . $row['token_prefix'] . "..., age={$age}s, expire={$expire}s, status={$isExpired}");
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[web_access_check] DB query error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
@@ -2189,7 +2184,9 @@ function checkPendingTransactions() {
|
||||
try {
|
||||
$stmt = $db->query("SELECT name FROM sqlite_master WHERE type='table' AND name='web_transactions'");
|
||||
$hasTable = ($stmt && $stmt->fetchArray());
|
||||
} catch (Exception $e) {}
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[checkPendingTransactions] table check error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
if (!$hasTable) {
|
||||
success(['pending' => 0], 'no table');
|
||||
@@ -2203,7 +2200,9 @@ function checkPendingTransactions() {
|
||||
$row = $stmt->fetchArray(SQLITE3_ASSOC);
|
||||
$count = (int)($row['cnt'] ?? 0);
|
||||
}
|
||||
} catch (Exception $e) {}
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[checkPendingTransactions] count error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
success(['pending' => $count], $count > 0 ? '有交易待处理' : '无待处理');
|
||||
}
|
||||
@@ -2250,8 +2249,8 @@ function pullPendingTransactions() {
|
||||
$db->exec("UPDATE web_transactions SET status = 'processing', processed_at = " . time() . " WHERE id IN ($idList)");
|
||||
}
|
||||
$db->exec('COMMIT');
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec('ROLLBACK'); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec('ROLLBACK'); } catch (\Throwable $e2) {}
|
||||
@error_log("[pullPendingTransactions] 事务失败: " . $e->getMessage());
|
||||
// 降级:不做标记,直接返回(下一轮会重新拉取)
|
||||
}
|
||||
@@ -2286,8 +2285,8 @@ function confirmTransaction() {
|
||||
$stmt->bindValue(':id', (int)$txId, SQLITE3_INTEGER);
|
||||
$stmt->execute();
|
||||
$db->exec('COMMIT');
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec('ROLLBACK'); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec('ROLLBACK'); } catch (\Throwable $e2) {}
|
||||
@error_log("[confirmTransaction] 失败: " . $e->getMessage());
|
||||
}
|
||||
|
||||
@@ -2338,11 +2337,17 @@ function checkShopStockChanged() {
|
||||
if (!$secret || $secret !== SECRET_KEY) error('认证失败');
|
||||
|
||||
$db = getDB();
|
||||
try {
|
||||
$stmt = $db->prepare("SELECT MAX(last_modified) as max_lm, SUM(CASE WHEN admin_stock IS NOT NULL THEN 1 ELSE 0 END) as admin_count FROM shop_items");
|
||||
$result = $stmt->execute();
|
||||
$row = $result->fetchArray(SQLITE3_ASSOC);
|
||||
$maxModified = $row['max_lm'] ? (int)$row['max_lm'] : 0;
|
||||
$adminCount = $row['admin_count'] ? (int)$row['admin_count'] : 0;
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[checkShopStockChanged] error: " . $e->getMessage());
|
||||
$maxModified = 0;
|
||||
$adminCount = 0;
|
||||
}
|
||||
|
||||
// ★ 如果admin_stock非NULL(管理员改了库存但Java还没拉取),强制返回changed=true
|
||||
$clientLastModified = (int)getParam('last_modified', 0);
|
||||
@@ -2423,8 +2428,8 @@ function resendPendingTransactions() {
|
||||
}
|
||||
|
||||
$db->exec("COMMIT");
|
||||
} catch (Exception $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (Exception $e2) {}
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[resendPendingTransactions] Transaction failed: " . $e->getMessage());
|
||||
error('数据库操作失败: ' . $e->getMessage());
|
||||
}
|
||||
@@ -2535,7 +2540,7 @@ function sendEmailCode() {
|
||||
// SMTP失败,返回验证码供调试
|
||||
success(['player' => $player, 'masked_email' => $maskedEmail, 'code' => $code], '邮件发送中(验证码:' . $code . ')');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
error('邮件发送失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -2742,7 +2747,7 @@ function sendResetPasswordLink() {
|
||||
try {
|
||||
smtpSendEmail($smtpHost, $smtpPort, $smtpUser, $smtpPass, $email, $subject, $htmlBody, $headers, SMTP_USE_SSL);
|
||||
success(['player' => $player, 'email' => $email], '重置链接已发送到邮箱');
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
error('邮件发送失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -2895,7 +2900,7 @@ function adminSendResetLink() {
|
||||
try {
|
||||
smtpSendEmail($smtpHost, $smtpPort, $smtpUser, $smtpPass, $email, $subject, $htmlBody, $headers, SMTP_USE_SSL);
|
||||
success(['player' => $player, 'email' => $email], '重置链接已发送到邮箱');
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
error('邮件发送失败:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -2992,7 +2997,7 @@ function checkPendingWebRegisterRequests() {
|
||||
$db = getDB();
|
||||
try {
|
||||
$db->exec("SELECT id FROM web_register_requests LIMIT 0");
|
||||
} catch (Exception $e) {
|
||||
} catch (\Throwable $e) {
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS web_register_requests (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player_name TEXT NOT NULL,
|
||||
@@ -3006,10 +3011,13 @@ function checkPendingWebRegisterRequests() {
|
||||
)");
|
||||
}
|
||||
|
||||
// ★ 事务包裹DELETE+标记processing,防止database is locked
|
||||
$db->exec("BEGIN IMMEDIATE");
|
||||
// ★ 只读查询不需要BEGIN IMMEDIATE(避免与其它并发请求抢锁导致500)
|
||||
// 清理过期请求 + 标记processing(非原子操作也OK,最坏情况是多拉一次)
|
||||
try {
|
||||
$db->exec("DELETE FROM web_register_requests WHERE created_at < " . (time() - 1800));
|
||||
} catch (\Throwable $e) {
|
||||
@error_log("[checkPendingWebRegisterRequests] cleanup error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("SELECT id, player_name, password_hash, salt, email, ip_address, created_at FROM web_register_requests WHERE status = 'pending' ORDER BY created_at ASC");
|
||||
$result = $stmt->execute();
|
||||
@@ -3021,14 +3029,14 @@ function checkPendingWebRegisterRequests() {
|
||||
$ids[] = (int)$row['id'];
|
||||
}
|
||||
|
||||
// 使用事务标记为processing
|
||||
// 标记为processing(允许失败,下次还会拉到)
|
||||
if (!empty($ids)) {
|
||||
try {
|
||||
$idList = implode(',', $ids);
|
||||
$db->exec("UPDATE web_register_requests SET status = 'processing', processed_at = " . time() . " WHERE id IN ($idList)");
|
||||
}
|
||||
$db->exec("COMMIT");
|
||||
} catch (\Throwable $e) {
|
||||
try { $db->exec("ROLLBACK"); } catch (\Throwable $e2) {}
|
||||
@error_log("[checkPendingWebRegisterRequests] mark processing error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
success(['requests' => $requests, 'count' => count($requests)]);
|
||||
|
||||
Reference in New Issue
Block a user