356 lines
15 KiB
PHP
356 lines
15 KiB
PHP
<?php
|
||
session_start();
|
||
require_once __DIR__ . '/db/config.php';
|
||
require_once __DIR__ . '/api/LocalLubanApi.php';
|
||
|
||
// Price multiplier to earn profit (User requested 1.5 - 2x)
|
||
const PRICE_MULTIPLIER = 1.8;
|
||
|
||
$pdo = db();
|
||
|
||
// Ensure apikey is loaded
|
||
$stmt = $pdo->prepare("SELECT setting_value FROM settings WHERE setting_key = 'lubansms_apikey'");
|
||
$stmt->execute();
|
||
$db_apikey = $stmt->fetchColumn();
|
||
|
||
$api = new LubanSMS($db_apikey);
|
||
|
||
$action = $_GET['action'] ?? '';
|
||
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
|
||
// Basic Auth check
|
||
if (!isset($_SESSION['user_id']) && $action !== 'login') {
|
||
echo json_encode(['code' => 401, 'msg' => '未登录或登录已过期']);
|
||
exit;
|
||
}
|
||
|
||
function check_trc20_payment($address, $target_amount, $order_time) {
|
||
if (!$address || $address == 'TEm1B...TRC20_ADDRESS_HERE') return false;
|
||
|
||
// TronScan API to check transactions
|
||
$url = "https://apilist.tronscan.org/api/token_trc20/transfers?limit=20&start=0&direction=1&address=" . urlencode($address);
|
||
|
||
$ch = curl_init();
|
||
curl_setopt($ch, CURLOPT_URL, $url);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
||
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
$response = curl_exec($ch);
|
||
curl_close($ch);
|
||
|
||
if (!$response) return false;
|
||
$data = json_decode($response, true);
|
||
if (!isset($data['token_transfers'])) return false;
|
||
|
||
foreach ($data['token_transfers'] as $tx) {
|
||
if ($tx['symbol'] !== 'USDT') continue;
|
||
|
||
$amount = (float)$tx['quant'] / pow(10, $tx['tokenInfo']['tokenDecimal']);
|
||
$tx_time = (int)($tx['block_ts'] / 1000);
|
||
$order_ts = strtotime($order_time);
|
||
|
||
if (abs($amount - $target_amount) < 0.01 && $tx_time > $order_ts) {
|
||
return $tx['transaction_id'];
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
switch ($action) {
|
||
case 'get_balance':
|
||
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
$balance = $stmt->fetchColumn();
|
||
echo json_encode(['code' => 0, 'balance' => number_format((float)$balance, 2)]);
|
||
break;
|
||
|
||
case 'get_countries':
|
||
if (!$db_apikey) {
|
||
echo json_encode(['code' => 500, 'msg' => 'API Key not configured in DB'], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
}
|
||
$res = $api->getCountries();
|
||
if ($res && (int)($res['code'] ?? -1) === 0) {
|
||
$data = $res['msg'] ?? $res['data'] ?? [];
|
||
echo json_encode(['code' => 0, 'data' => $data], JSON_UNESCAPED_UNICODE);
|
||
} else {
|
||
echo json_encode($res ?: ['code' => 500, 'msg' => 'API接口响应异常'], JSON_UNESCAPED_UNICODE);
|
||
}
|
||
break;
|
||
|
||
case 'get_services':
|
||
if (!$db_apikey) {
|
||
echo json_encode(['code' => 500, 'msg' => 'API Key not configured in DB'], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
}
|
||
$country = $_GET['country'] ?? '';
|
||
$service = $_GET['service'] ?? '';
|
||
$res = $api->getServices($country, $service);
|
||
|
||
if ($res && (int)($res['code'] ?? -1) === 0) {
|
||
$data = $res['msg'] ?? $res['data'] ?? [];
|
||
if (!is_array($data)) $data = [];
|
||
foreach ($data as &$item) {
|
||
if (isset($item['cost'])) {
|
||
$item['cost'] = round((float)$item['cost'] * PRICE_MULTIPLIER, 2);
|
||
}
|
||
}
|
||
echo json_encode(['code' => 0, 'data' => $data], JSON_UNESCAPED_UNICODE);
|
||
} else {
|
||
echo json_encode($res ?: ['code' => 500, 'msg' => '获取项目列表失败'], JSON_UNESCAPED_UNICODE);
|
||
}
|
||
break;
|
||
|
||
case 'get_number':
|
||
if (!$db_apikey) {
|
||
echo json_encode(['code' => 500, 'msg' => 'API Key not configured in DB'], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
}
|
||
$service_id = $_GET['service_id'] ?? '';
|
||
$country_name = $_GET['country_name'] ?? '未知国家';
|
||
$service_name = $_GET['service_name'] ?? '未知项目';
|
||
$price = (float)($_GET['price'] ?? 0);
|
||
|
||
if (!$service_id) {
|
||
echo json_encode(['code' => 400, 'msg' => 'Service ID is required']);
|
||
break;
|
||
}
|
||
|
||
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
$balance = (float)$stmt->fetchColumn();
|
||
|
||
if ($balance < $price) {
|
||
echo json_encode(['code' => 400, 'msg' => '余额不足,请先充值']);
|
||
break;
|
||
}
|
||
|
||
$res = $api->getNumber($service_id);
|
||
if ($res && (int)($res['code'] ?? -1) === 0) {
|
||
$pdo->beginTransaction();
|
||
try {
|
||
$stmt = $pdo->prepare("UPDATE users SET balance = balance - ? WHERE id = ?");
|
||
$stmt->execute([$price, $_SESSION['user_id']]);
|
||
|
||
$stmt = $pdo->prepare("INSERT INTO sms_orders (user_id, request_id, number, service_name, country_name, cost, status, expire_at) VALUES (?, ?, ?, ?, ?, ?, 'pending', DATE_ADD(NOW(), INTERVAL 10 MINUTE))");
|
||
$stmt->execute([$_SESSION['user_id'], $res['request_id'], $res['number'], $service_name, $country_name, $price]);
|
||
$pdo->commit();
|
||
echo json_encode($res, JSON_UNESCAPED_UNICODE);
|
||
} catch (Exception $e) {
|
||
$pdo->rollBack();
|
||
echo json_encode(['code' => 500, 'msg' => '数据库事务错误'], JSON_UNESCAPED_UNICODE);
|
||
}
|
||
} else {
|
||
echo json_encode($res ?: ['code' => 500, 'msg' => 'API获取号码失败'], JSON_UNESCAPED_UNICODE);
|
||
}
|
||
break;
|
||
|
||
case 'check_sms':
|
||
$request_id = $_GET['request_id'] ?? '';
|
||
if (!$request_id) {
|
||
echo json_encode(['code' => 400, 'msg' => 'Request ID is required']);
|
||
break;
|
||
}
|
||
|
||
$res = $api->getSms($request_id);
|
||
if ($res && (int)($res['code'] ?? -1) === 0 && (string)($res['msg'] ?? '') === 'success') {
|
||
$stmt = $pdo->prepare("UPDATE sms_orders SET sms_content = ?, status = 'received' WHERE request_id = ?");
|
||
$stmt->execute([$res['sms_code'], $request_id]);
|
||
}
|
||
echo json_encode($res ?: ['code' => 500, 'msg' => 'API Error'], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
|
||
case 'release_number':
|
||
$request_id = $_GET['request_id'] ?? '';
|
||
|
||
$stmt = $pdo->prepare("SELECT created_at, status FROM sms_orders WHERE request_id = ? AND user_id = ?");
|
||
$stmt->execute([$request_id, $_SESSION['user_id']]);
|
||
$order = $stmt->fetch();
|
||
|
||
if (!$order) {
|
||
echo json_encode(['code' => 404, 'msg' => '未找到该订单']);
|
||
break;
|
||
}
|
||
|
||
if ($order['status'] !== 'pending') {
|
||
echo json_encode(['code' => 400, 'msg' => '订单状态不符合释放条件']);
|
||
break;
|
||
}
|
||
|
||
$createdAt = strtotime($order['created_at']);
|
||
if (time() - $createdAt < 120) {
|
||
echo json_encode(['code' => 400, 'msg' => '获取号码不足2分钟,暂时无法手动释放。']);
|
||
break;
|
||
}
|
||
|
||
$res = $api->setStatus($request_id, 'reject');
|
||
if ($res && (int)($res['code'] ?? -1) === 0) {
|
||
$stmt = $pdo->prepare("UPDATE sms_orders SET status = 'canceled' WHERE request_id = ?");
|
||
$stmt->execute([$request_id]);
|
||
}
|
||
echo json_encode($res ?: ['code' => 500, 'msg' => 'API释放失败'], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
|
||
case 'get_active_orders':
|
||
// Auto expire old orders
|
||
$stmt = $pdo->prepare("UPDATE sms_orders SET status = 'expired' WHERE status = 'pending' AND expire_at < NOW()");
|
||
$stmt->execute();
|
||
|
||
$stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE user_id = ? AND status = 'pending' ORDER BY created_at DESC");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
|
||
case 'create_recharge':
|
||
$amount = (float)($_POST['amount'] ?? 0);
|
||
if ($amount < 10) {
|
||
echo json_encode(['code' => 400, 'msg' => '最低充值金额为 10 USDT']);
|
||
break;
|
||
}
|
||
|
||
$base = floor($amount);
|
||
$random_decimal = rand(1, 99) / 100;
|
||
$final_amount = $base + $random_decimal;
|
||
|
||
$stmt = $pdo->prepare("INSERT INTO recharges (user_id, amount, txid, status) VALUES (?, ?, 'Auto-Detect', 'pending')");
|
||
$stmt->execute([$_SESSION['user_id'], $final_amount]);
|
||
echo json_encode(['code' => 0, 'recharge_id' => $pdo->lastInsertId(), 'amount' => $final_amount], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
|
||
case 'check_recharge_status':
|
||
$recharge_id = $_GET['recharge_id'] ?? '';
|
||
if (!$recharge_id) {
|
||
echo json_encode(['code' => 400, 'msg' => 'Recharge ID is required']);
|
||
break;
|
||
}
|
||
|
||
$stmt = $pdo->prepare("SELECT * FROM recharges WHERE id = ? AND user_id = ?");
|
||
$stmt->execute([$recharge_id, $_SESSION['user_id']]);
|
||
$recharge = $stmt->fetch();
|
||
|
||
if (!$recharge) {
|
||
echo json_encode(['code' => 404, 'msg' => '未找到充值订单']);
|
||
break;
|
||
}
|
||
|
||
if ($recharge['status'] === 'completed') {
|
||
echo json_encode(['code' => 0, 'status' => 'completed']);
|
||
exit;
|
||
}
|
||
|
||
// Try Auto-Detection
|
||
$settings = $pdo->query("SELECT setting_key, setting_value FROM settings")->fetchAll(PDO::FETCH_KEY_PAIR);
|
||
$trc20_address = $settings['usdt_trc20_address'] ?? '';
|
||
|
||
$txid = check_trc20_payment($trc20_address, $recharge['amount'], $recharge['created_at']);
|
||
if ($txid) {
|
||
$pdo->beginTransaction();
|
||
try {
|
||
$stmt = $pdo->prepare("UPDATE recharges SET status = 'completed', txid = ? WHERE id = ?");
|
||
$stmt->execute([$txid, $recharge_id]);
|
||
$stmt = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
|
||
$stmt->execute([$recharge['amount'], $recharge['user_id']]);
|
||
$pdo->commit();
|
||
echo json_encode(['code' => 0, 'status' => 'completed']);
|
||
} catch (Exception $e) {
|
||
$pdo->rollBack();
|
||
echo json_encode(['code' => 500, 'msg' => '自动入账失败'], JSON_UNESCAPED_UNICODE);
|
||
}
|
||
} else {
|
||
echo json_encode(['code' => 0, 'status' => 'pending']);
|
||
}
|
||
break;
|
||
|
||
case 'send_message':
|
||
$message = trim($_POST['message'] ?? '');
|
||
$target_user_id = $_POST['user_id'] ?? $_SESSION['user_id'];
|
||
|
||
if (!$message) {
|
||
echo json_encode(['code' => 400, 'msg' => '消息内容不能为空']);
|
||
break;
|
||
}
|
||
|
||
// Check sender role
|
||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
$role = $stmt->fetchColumn();
|
||
$sender = ($role === 'admin') ? 'admin' : 'user';
|
||
|
||
$stmt = $pdo->prepare("INSERT INTO support_messages (user_id, sender, message, is_read) VALUES (?, ?, ?, 0)");
|
||
$stmt->execute([$target_user_id, $sender, $message]);
|
||
echo json_encode(['code' => 0, 'msg' => '已发送'], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
|
||
case 'get_messages':
|
||
$target_user_id = $_GET['user_id'] ?? $_SESSION['user_id'];
|
||
|
||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
$currentUserRole = $stmt->fetchColumn();
|
||
|
||
$isAdmin = ($currentUserRole === 'admin');
|
||
if (!$isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) {
|
||
echo json_encode(['code' => 403, 'msg' => '无权查看他人消息']);
|
||
break;
|
||
}
|
||
|
||
// Mark as read
|
||
if ($isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) {
|
||
$stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'user'");
|
||
$stmt->execute([$target_user_id]);
|
||
} else if (!$isAdmin) {
|
||
$stmt = $pdo->prepare("UPDATE support_messages SET is_read = 1 WHERE user_id = ? AND sender = 'admin'");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
}
|
||
|
||
$stmt = $pdo->prepare("SELECT * FROM support_messages WHERE user_id = ? ORDER BY created_at ASC");
|
||
$stmt->execute([$target_user_id]);
|
||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
|
||
case 'get_chat_users':
|
||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
if ($stmt->fetchColumn() !== 'admin') {
|
||
echo json_encode(['code' => 403, 'msg' => 'Forbidden']);
|
||
break;
|
||
}
|
||
|
||
$stmt = $pdo->query("
|
||
SELECT u.id, u.username, m.message as last_message, m.created_at as last_time,
|
||
(SELECT COUNT(*) FROM support_messages WHERE user_id = u.id AND sender = 'user' AND is_read = 0) as unread_count
|
||
FROM users u
|
||
JOIN (
|
||
SELECT user_id, MAX(created_at) as max_time
|
||
FROM support_messages
|
||
GROUP BY user_id
|
||
) last_msg ON u.id = last_msg.user_id
|
||
JOIN support_messages m ON m.user_id = u.id AND m.created_at = last_msg.max_time
|
||
ORDER BY m.created_at DESC
|
||
");
|
||
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE);
|
||
break;
|
||
|
||
case 'check_new_messages':
|
||
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
|
||
$stmt->execute([$_SESSION['user_id']]);
|
||
if ($stmt->fetchColumn() !== 'admin') {
|
||
echo json_encode(['code' => 403, 'msg' => 'Forbidden']);
|
||
break;
|
||
}
|
||
|
||
$stmt = $pdo->query("SELECT COUNT(*) FROM support_messages WHERE sender = 'user' AND is_read = 0");
|
||
$count = $stmt->fetchColumn();
|
||
echo json_encode(['code' => 0, 'unread_total' => $count]);
|
||
break;
|
||
|
||
default:
|
||
echo json_encode(['code' => 404, 'msg' => '未知请求']);
|
||
break;
|
||
}
|
||
} catch (Exception $e) {
|
||
echo json_encode(['code' => 500, 'msg' => '系统处理异常: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE);
|
||
} |