fix: 限时折扣过期逻辑修复 + Minecraft OAuth功能改进

This commit is contained in:
ypsdf1
2026-07-17 16:51:38 +08:00
parent ff83406013
commit 1d5f500a28
3 changed files with 63 additions and 115 deletions
-105
View File
@@ -1,105 +0,0 @@
<?php
/**
* 诊断脚本:检查shop_configs表中的discount_price字段
*/
// 加载支付密钥
$secretsFile = __DIR__ . '/pay_secrets.php';
if (@is_file($secretsFile) && @is_readable($secretsFile)) {
@require_once $secretsFile;
}
// 获取数据库路径 - 尝试多种可能的路径
$possiblePaths = [
dirname(__DIR__) . '/db/orders.db',
dirname(__DIR__) . '/data/orders.db',
dirname(__DIR__) . '/orders.db',
dirname(__DIR__) . '/../db/orders.db',
dirname(__DIR__) . '/../data/orders.db',
dirname(__DIR__) . '/../orders.db',
];
$dbPath = null;
foreach ($possiblePaths as $path) {
if (is_file($path)) {
$dbPath = $path;
break;
}
}
if (!$dbPath) {
echo "数据库文件不存在,尝试的路径:\n";
foreach ($possiblePaths as $path) {
echo " - $path\n";
}
// 列出可能的目录内容
echo "\n当前目录内容:\n";
$dir = dirname(__DIR__);
$items = scandir($dir);
foreach ($items as $item) {
if ($item != '.' && $item != '..') {
$fullPath = $dir . '/' . $item;
$type = is_dir($fullPath) ? '[目录]' : '[文件]';
echo " $type $item\n";
}
}
exit(1);
}
if (!is_file($dbPath)) {
echo "数据库文件不存在: $dbPath\n";
exit(1);
}
$db = new SQLite3($dbPath);
$db->busyTimeout(5000);
$db->exec('PRAGMA journal_mode=WAL');
// 检查表结构
echo "=== shop_configs表结构 ===\n";
$result = $db->query("PRAGMA table_info(shop_configs)");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
echo "{$row['cid']}: {$row['name']} ({$row['type']})" . (isset($row['notnull']) && $row['notnull'] ? ' NOT NULL' : '') . (isset($row['dflt_value']) ? " DEFAULT {$row['dflt_value']}" : '') . "\n";
}
// 检查现有数据
echo "\n=== 现有商品数据 ===\n";
$result = $db->query("SELECT * FROM shop_configs ORDER BY id DESC LIMIT 5");
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
echo "ID: {$row['id']}, 名称: {$row['item_name']}, 原价: {$row['price']}, 折扣价: " . (isset($row['discount_price']) ? $row['discount_price'] : '字段不存在') . "\n";
}
// 测试插入(带折扣价格)
echo "\n=== 测试插入带折扣价格的商品 ===\n";
$stmt = $db->prepare("INSERT INTO shop_configs (item_name, stock, temporary_offer, offer_expire, price, discount_price, bond_reward, is_active, created_at, updated_at) VALUES (:name, :stock, :offer, :expire, :price, :discount_price, :bond, :active, :created, :updated)");
$stmt->bindValue(':name', '测试折扣商品', SQLITE3_TEXT);
$stmt->bindValue(':stock', -1, SQLITE3_INTEGER);
$stmt->bindValue(':offer', '', SQLITE3_TEXT);
$stmt->bindValue(':expire', '', SQLITE3_TEXT);
$stmt->bindValue(':price', 10.00, SQLITE3_FLOAT);
$stmt->bindValue(':discount_price', 8.50, SQLITE3_FLOAT);
$stmt->bindValue(':bond', '1-10', SQLITE3_TEXT);
$stmt->bindValue(':active', 1, SQLITE3_INTEGER);
$stmt->bindValue(':created', time(), SQLITE3_INTEGER);
$stmt->bindValue(':updated', time(), SQLITE3_INTEGER);
$stmt->execute();
$testId = $db->lastInsertRowID();
echo "测试商品ID: $testId\n";
// 验证插入
$result = $db->query("SELECT * FROM shop_configs WHERE id = $testId");
$row = $result->fetchArray(SQLITE3_ASSOC);
if ($row) {
echo "验证: 原价={$row['price']}, 折扣价={$row['discount_price']}\n";
if ($row['discount_price'] == 8.50) {
echo "✅ 折扣价格保存成功!\n";
} else {
echo "❌ 折扣价格保存失败!\n";
}
}
// 清理测试数据
$db->exec("DELETE FROM shop_configs WHERE id = $testId");
echo "已清理测试数据\n";
$db->close();
+38 -5
View File
@@ -535,6 +535,7 @@ switch ($action) {
// Microsoft返回错误
if ($msError) {
header('Content-Type: text/html; charset=utf-8');
$errorDesc = getParam('error_description', 'Microsoft登录被拒绝');
if ($state) {
$stmt = $db->prepare("UPDATE mc_auth_sessions SET status = 'failed' WHERE session_id = ?");
@@ -550,6 +551,7 @@ switch ($action) {
}
if (empty($code) || empty($state)) {
header('Content-Type: text/html; charset=utf-8');
echo "<!DOCTYPE html><html><head><meta charset='utf-8'><title>参数错误</title></head><body><h1>参数错误</h1></body></html>";
exit;
}
@@ -560,6 +562,7 @@ switch ($action) {
$session = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$session) {
header('Content-Type: text/html; charset=utf-8');
echo "<!DOCTYPE html><html><head><meta charset='utf-8'><title>会话不存在</title></head><body><h1>会话不存在或已过期</h1></body></html>";
exit;
}
@@ -567,6 +570,7 @@ switch ($action) {
if (time() > $session['expires_at']) {
$stmt = $db->prepare("UPDATE mc_auth_sessions SET status = 'expired' WHERE session_id = ?");
$stmt->execute([$state]);
header('Content-Type: text/html; charset=utf-8');
echo "<!DOCTYPE html><html><head><meta charset='utf-8'><title>会话过期</title></head><body><h1>会话已过期,请返回游戏重新发起验证</h1></body></html>";
exit;
}
@@ -578,6 +582,7 @@ switch ($action) {
// 验证失败
$stmt = $db->prepare("UPDATE mc_auth_sessions SET status = 'failed' WHERE session_id = ?");
$stmt->execute([$state]);
header('Content-Type: text/html; charset=utf-8');
echo "<!DOCTYPE html><html><head><meta charset='utf-8'><title>验证失败</title>
<style>body{font-family:sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#1a1a2e;color:#fff;}
.card{background:#16213e;padding:40px;border-radius:16px;text-align:center;max-width:400px;}
@@ -594,6 +599,7 @@ switch ($action) {
// 显示成功页面
$mcName = htmlspecialchars($result['name']);
$mcUuid = htmlspecialchars($result['uuid']);
header('Content-Type: text/html; charset=utf-8');
echo "<!DOCTYPE html><html><head><meta charset='utf-8'><title>验证成功</title>
<style>body{font-family:sans-serif;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#1a1a2e;color:#fff;}
.card{background:#16213e;padding:40px;border-radius:16px;text-align:center;max-width:400px;}
@@ -622,6 +628,13 @@ switch ($action) {
if (empty($sessionId)) error('缺少session_id参数');
if (empty($code)) error('缺少code参数(授权码)');
// 自动从URL中提取code参数
if (strpos($code, 'code=') !== false || strpos($code, 'http') === 0) {
if (preg_match('/[?&]code=([^&]+)/', $code, $m)) {
$code = urldecode($m[1]);
}
}
// 密钥验证:Java调用需要secret,浏览器表单用session_id自身认证
if (!empty($secret)) {
if ($secret !== MC_AUTH_SECRET) error('密钥错误', 403);
@@ -702,6 +715,7 @@ switch ($action) {
// ===== 网页粘贴授权码页面(公共客户端流程) =====
case 'paste_code_page': {
header('Content-Type: text/html; charset=utf-8');
$sessionId = getParam('session_id');
if (empty($sessionId)) {
echo "<!DOCTYPE html><html><head><meta charset='utf-8'><title>参数错误</title></head><body><h1>缺少session_id参数</h1></body></html>";
@@ -718,6 +732,7 @@ switch ($action) {
}
$playerName = htmlspecialchars($session['player_name']);
$authUrl = htmlspecialchars(getAuthUrl($sessionId));
echo <<<HTML
<!DOCTYPE html>
<html lang="zh-CN">
@@ -749,22 +764,40 @@ button:disabled{opacity:0.5;cursor:not-allowed;transform:none}
<div class="card">
<h2>🎮 正版验证</h2>
<p class="player">玩家: <b>$playerName</b></p>
<div style="margin-bottom:20px">
<a href="$authUrl" target="_blank" style="display:inline-block;padding:12px 24px;background:#4ade80;color:#0f0f23;text-decoration:none;border-radius:8px;font-weight:bold;font-size:16px">点击打开Microsoft登录</a>
</div>
<ol class="steps">
<li>在上方Microsoft页面<b>复制授权码</b></li>
<li>将授权码<b>粘贴</b>到下方输入框</li>
<li>点击上方<b>"打开Microsoft登录"</b>按钮</li>
<li>登录Microsoft账号</li>
<li>登录成功后,<b>复制浏览器地址栏的完整URL</b></li>
<li>将URL<b>粘贴</b>到下方输入框(会自动提取授权码)</li>
<li>点击"提交验证"</li>
</ol>
<div class="input-group">
<input type="text" id="codeInput" placeholder="粘贴授权码到这里" autofocus autocomplete="off">
<input type="text" id="codeInput" placeholder="粘贴完整URL或授权码" autofocus autocomplete="off">
</div>
<button id="submitBtn" onclick="submitCode()">提交验证</button>
<div class="msg" id="msg"></div>
</div>
<script>
var sessionId="{$sessionId}";
function extractCode(input){
input=input.trim();
// 如果包含code=参数,从中提取
var m=input.match(/[?&]code=([^&]+)/);
if(m) return decodeURIComponent(m[1]);
// 如果不包含http/https,当作原始code
if(input.indexOf('http')===-1 && input.indexOf('code=')===-1) return input;
// 尝试解析URL
try{var u=new URL(input);var p=new URLSearchParams(u.search);if(p.has('code'))return p.get('code');}catch(e){}
return input;
}
function submitCode(){
var code=document.getElementById('codeInput').value.trim();
if(!code){showMsg('请输入授权码','err');return}
var raw=document.getElementById('codeInput').value.trim();
if(!raw){showMsg('请输入授权码或URL','err');return}
var code=extractCode(raw);
if(!code){showMsg('无法从输入中提取授权码','err');return}
var btn=document.getElementById('submitBtn');
btn.disabled=true;btn.textContent='验证中...';
var xhr=new XMLHttpRequest();
+25 -5
View File
@@ -315,9 +315,19 @@ function createOrder($token, $productId = 0) {
error('商品已售罄');
}
// 使用折扣价格(如果有)
// ★ 检查限时折扣是否已过期
$actualPrice = $product['price'];
if (isset($product['discount_price']) && $product['discount_price'] > 0) {
$offerExpired = false;
if (!empty($product['temporary_offer']) && !empty($product['offer_expire'])) {
$expireInfo = parseExpireDate($product['offer_expire']);
if (!$expireInfo['valid']) {
// 折扣已过期 → 使用原价,不使用折扣价
$offerExpired = true;
}
}
// 使用折扣价格(如果折扣未过期)
if (!$offerExpired && isset($product['discount_price']) && $product['discount_price'] > 0) {
$actualPrice = $product['discount_price'];
}
$money = number_format($actualPrice, 2, '.', '');
@@ -956,7 +966,12 @@ function parseExpireDate($expireStr) {
if (preg_match('/^\d{4}-\d{1,2}-\d{1,2}$/', $expireStr)) {
$time = strtotime($expireStr . ' 23:59:59');
if ($time !== false) {
return ['valid' => true, 'timestamp' => $time, 'display' => date('Y-m-d', $time) . ' 到期'];
$now = time();
return [
'valid' => $time >= $now,
'timestamp' => $time,
'display' => date('Y-m-d', $time) . ($time >= $now ? ' 到期' : ' 已过期')
];
}
}
@@ -1105,9 +1120,13 @@ function getShopProducts() {
// 解析有效期
$expireInfo = parseExpireDate($row['offer_expire']);
// 计算实际显示价格(如果有折扣价格且折扣价格>0)
// 计算实际显示价格(如果有折扣价格且折扣未过期且折扣价格>0)
$displayPrice = $row['price'];
if (isset($row['discount_price']) && $row['discount_price'] > 0) {
$discountActive = false;
if (!empty($row['temporary_offer']) && !empty($row['offer_expire'])) {
$discountActive = $expireInfo['valid'];
}
if ($discountActive && isset($row['discount_price']) && $row['discount_price'] > 0) {
$displayPrice = $row['discount_price'];
}
@@ -1121,6 +1140,7 @@ function getShopProducts() {
'expire_display' => $expireInfo['display'],
'price' => $row['price'],
'discount_price' => $row['discount_price'] ?? 0,
'discount_active' => $discountActive,
'display_price' => $displayPrice,
'bond_reward' => $bondReward,
'bond_min' => $bondMin,