fix: 限时折扣过期逻辑修复 + Minecraft OAuth功能改进
This commit is contained in:
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user