PHP WebShell
Текущая директория: /var/www/bitcardoApp/user/crypto
Просмотр файла: swap_crypto.php
<?php
/**
* user/crypto/swap_crypto_new.php
*
*/
require_once "../../config/db_config.php";
if (!isset($_SESSION)) { session_start(); }
if (!isset($_SESSION['user_id'])) { header("Location: ../../auth/login.php"); exit(); }
$user_id = $_SESSION['user_id'];
/* ----------------- helpers ----------------- */
function get_setting(mysqli $conn, string $key, $default = null) {
$sql = "SELECT setting_value FROM site_settings WHERE setting_key=? LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $key);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $row['setting_value'] ?? $default;
}
function table_has_column(mysqli $conn, string $table, string $column): bool {
$sql = "SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = ?
AND COLUMN_NAME = ?
LIMIT 1";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $table, $column);
$stmt->execute();
$res = $stmt->get_result();
$exists = $res && $res->num_rows > 0;
$stmt->close();
return $exists;
}
/** coin_rates: USDT per COIN (crypto); NGN row may be absent */
function get_db_rates(mysqli $conn, string $coin): array {
$sql = "SELECT buy_rate, sell_rate, COALESCE(use_online_rate,0) AS use_online_rate
FROM coin_rates WHERE UPPER(coin)=?";
$stmt = $conn->prepare($sql);
$c = strtoupper($coin);
$stmt->bind_param("s", $c);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$stmt->close();
return [
'buy' => (float)($row['buy_rate'] ?? 0.0), // USDT/COIN (platform buys coin)
'sell' => (float)($row['sell_rate'] ?? 0.0), // USDT/COIN (platform sells coin)
'use_online_rate' => (int)($row['use_online_rate'] ?? 0)
];
}
/** online_coin_rates:
* - Crypto: rate = USDT per COIN → buy/sell around that
* - NGN : rate = NGN per USDT → buy/sell around that
*/
function get_online_rates(mysqli $conn, string $coin): array {
$sql = "SELECT buy_rate, sell_rate FROM online_coin_rates WHERE UPPER(coin)=?";
$stmt = $conn->prepare($sql);
$c = strtoupper($coin);
$stmt->bind_param("s", $c);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$stmt->close();
return [
'buy' => (float)($row['buy_rate'] ?? 0.0),
'sell' => (float)($row['sell_rate'] ?? 0.0)
];
}
/**
* Decide effective rates for a coin:
* - If enforce_swap_profit=1:
* BUY (coin→USDT) : min(db.buy, online.buy)
* SELL (USDT→coin) : max(db.sell, online.sell)
* - Else:
* If coin_rates.use_online_rate=1 and online present → online; else → db.
*
* NOTE: We DO NOT use this for NGN routes in this file per your instruction.
*/
function effective_rates(mysqli $conn, string $coin, bool $enforce_profit): array {
$coin = strtoupper($coin);
$db = get_db_rates($conn, $coin);
$ol = get_online_rates($conn, $coin);
if ($enforce_profit) {
$candidates_buy = [];
$candidates_sell = [];
if ($db['buy'] > 0) $candidates_buy[] = $db['buy'];
if ($ol['buy'] > 0) $candidates_buy[] = $ol['buy'];
if ($db['sell'] > 0) $candidates_sell[] = $db['sell'];
if ($ol['sell'] > 0) $candidates_sell[] = $ol['sell'];
return [
'buy' => $candidates_buy ? min($candidates_buy) : 0.0,
'sell' => $candidates_sell ? max($candidates_sell) : 0.0,
];
}
$useOnline = ($db['use_online_rate'] === 1) && ($ol['buy'] > 0 || $ol['sell'] > 0);
return $useOnline ? ['buy'=>$ol['buy'], 'sell'=>$ol['sell']]
: ['buy'=>$db['buy'], 'sell'=>$db['sell']];
}
/** Convert an amount FROM coin to USDT for min-swap comparison (NGN special) */
function amount_to_usdt(mysqli $conn, string $from, float $amount, bool $enforce_profit): float {
$from = strtoupper($from);
if ($from === 'USDT') return $amount;
if ($from === 'NGN') {
// For min-swap only (kept), but quote logic below uses old-file math directly
$stmt = $conn->prepare("SELECT buy_rate FROM coin_rates WHERE UPPER(coin)='NGN'");
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$stmt->close();
$buy = (float)($row['buy_rate'] ?? 0.0); // NGN/USDT
return $buy > 0 ? ($amount / $buy) : 0.0;
}
// Crypto: USDT per COIN (use BUY side)
$r = effective_rates($conn, $from, $enforce_profit);
return $amount * (float)$r['buy'];
}
/* ----------------- AJAX QUOTE ----------------- */
if (isset($_GET['ajax']) && $_GET['ajax'] === 'quote') {
header('Content-Type: application/json');
$from = strtoupper($_GET['from'] ?? '');
$to = strtoupper($_GET['to'] ?? '');
$amount = (float)($_GET['amount'] ?? 0);
if (!$from || !$to || $amount <= 0) {
echo json_encode(['error' => 'Invalid input']); exit;
}
$enforce_profit = get_setting($conn, 'enforce_swap_profit', '1') === '1';
$enforce_min = get_setting($conn, 'enforce_min_swap', '1') === '1';
// Enforce minimum from coin_rates.min_swap only
if ($enforce_min) {
$stmt = $conn->prepare("SELECT COALESCE(min_swap,0) AS m FROM coin_rates WHERE UPPER(coin)=?");
$stmt->bind_param("s", $from);
$stmt->execute();
$r = $stmt->get_result()->fetch_assoc();
$stmt->close();
$min_cfg = (float)($r['m'] ?? 0);
if ($min_cfg > 0) {
if ($from === 'NGN') {
if ($amount < $min_cfg) { echo json_encode(['error' => "Min ₦" . number_format($min_cfg, 0)]); exit; }
} else {
$amount_usdt = amount_to_usdt($conn, $from, $amount, $enforce_profit);
if ($amount_usdt < $min_cfg) { echo json_encode(['error' => "Min $" . number_format($min_cfg, 2)]); exit; }
}
}
}
// Build quote
$rate = 0.0;
$to_amount = 0.0;
// ======== NGN ROUTES (USING OLD-FILE LOGIC) ========
if (($from === 'USDT' && $to === 'NGN') || ($from === 'NGN' && $to === 'USDT')) {
// Direct NGN ↔ USDT
if ($from === 'USDT') {
// USDT → NGN : multiply by NGN.sell_rate
$stmt = $conn->prepare("SELECT sell_rate FROM coin_rates WHERE UPPER(coin) = 'NGN'");
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$stmt->close();
$rate = (float)($row['sell_rate'] ?? 0);
$to_amount = $rate > 0 ? $amount * $rate : 0.0;
} else {
// NGN → USDT : divide by NGN.buy_rate
$stmt = $conn->prepare("SELECT buy_rate FROM coin_rates WHERE UPPER(coin) = 'NGN'");
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$stmt->close();
$rate = (float)($row['buy_rate'] ?? 0);
$to_amount = $rate > 0 ? $amount / $rate : 0.0;
}
} elseif ($from === 'NGN' && in_array($to, ['BTC','SOL','ETH'])) {
// NGN → COIN : (NGN / NGN.buy_rate) -> USDT, then (USDT / COIN.sell_rate) -> COIN
// 1) NGN.buy_rate
$stmt = $conn->prepare("SELECT buy_rate FROM coin_rates WHERE UPPER(coin) = 'NGN'");
$stmt->execute();
$ngnRow = $stmt->get_result()->fetch_assoc();
$stmt->close();
$ngn_buy = (float)($ngnRow['buy_rate'] ?? 0.0); // NGN per 1 USDT
$usdt = $ngn_buy > 0 ? ($amount / $ngn_buy) : 0.0;
// 2) COIN.sell_rate (USDT per 1 COIN)
$stmt = $conn->prepare("SELECT sell_rate FROM coin_rates WHERE UPPER(coin) = ?");
$stmt->bind_param("s", $to);
$stmt->execute();
$coinRow = $stmt->get_result()->fetch_assoc();
$stmt->close();
$coin_sell = (float)($coinRow['sell_rate'] ?? 0.0);
$to_amount = ($coin_sell > 0) ? ($usdt / $coin_sell) : 0.0;
// Composite rate (optional): COIN per 1 NGN
$rate = ($ngn_buy > 0 && $coin_sell > 0) ? (1.0 / $ngn_buy) / $coin_sell : 0.0;
} elseif (in_array($from, ['BTC','SOL','ETH']) && $to === 'NGN') {
// COIN → NGN : (COIN * COIN.buy_rate) -> USDT, then (USDT * NGN.sell_rate) -> NGN
// 1) COIN.buy_rate (USDT per 1 COIN)
$stmt = $conn->prepare("SELECT buy_rate FROM coin_rates WHERE UPPER(coin) = ?");
$stmt->bind_param("s", $from);
$stmt->execute();
$coinRow = $stmt->get_result()->fetch_assoc();
$stmt->close();
$coin_buy = (float)($coinRow['buy_rate'] ?? 0.0);
$usdt = $amount * $coin_buy;
// 2) NGN.sell_rate (NGN per 1 USDT)
$stmt = $conn->prepare("SELECT sell_rate FROM coin_rates WHERE UPPER(coin) = 'NGN'");
$stmt->execute();
$ngnRow = $stmt->get_result()->fetch_assoc();
$stmt->close();
$ngn_sell = (float)($ngnRow['sell_rate'] ?? 0.0);
$to_amount = $usdt * $ngn_sell;
// Composite rate (optional): NGN per 1 COIN
$rate = $coin_buy * $ngn_sell;
// ======== OTHER (UNCHANGED) ROUTES ========
} elseif ($to === 'USDT') {
// Coin → USDT: multiply by BUY (USDT/coin)
$r = effective_rates($conn, $from, $enforce_profit);
$rate = (float)$r['buy'];
$to_amount = $amount * $rate;
} elseif ($from === 'USDT') {
// USDT → Coin: divide by SELL (USDT/coin)
$r = effective_rates($conn, $to, $enforce_profit);
$rate = (float)$r['sell'];
$to_amount = $rate > 0 ? $amount / $rate : 0.0;
} else {
// Crypto → Crypto: (amount * FROM.buy USDT) / TO.sell
$rf = effective_rates($conn, $from, $enforce_profit);
$rt = effective_rates($conn, $to, $enforce_profit);
$buy = (float)$rf['buy']; // USDT / FROM
$sell = (float)$rt['sell']; // USDT / TO
$tusdt = $amount * $buy;
$to_amount = $sell > 0 ? $tusdt / $sell : 0.0;
$rate = ($buy > 0 && $sell > 0) ? ($buy / $sell) : 0.0;
}
echo json_encode([
'rate' => $rate,
'to_amount' => round($to_amount, 8)
]);
exit;
}
/* ----------------- Build wallet picklists ----------------- */
/** Active filter (wallet_status can be 'Active' or 'active') */
$hasWalletStatus = table_has_column($conn, 'user_wallets', 'wallet_status');
$activeClause = $hasWalletStatus
? " AND (LOWER(uw.wallet_status) = 'active' OR uw.wallet_status IS NULL) "
: "";
/** "You send" → active + balance > 0 */
$sendCoins = [];
$balances = [];
$sqlSend = "SELECT uw.coin, uw.balance
FROM user_wallets uw
WHERE uw.user_id = ? $activeClause AND uw.balance > 0";
$stmt = $conn->prepare($sqlSend);
$stmt->bind_param("i", $user_id);
$stmt->execute();
$rs = $stmt->get_result();
while ($row = $rs->fetch_assoc()) {
$c = strtoupper($row['coin']);
$sendCoins[] = $c;
$balances[$c] = (float)$row['balance'];
}
$stmt->close();
/** "You get" → active (balance can be 0) */
$activeToCoins = [];
$sqlTo = "SELECT DISTINCT UPPER(uw.coin) AS coin
FROM user_wallets uw
WHERE uw.user_id = ? $activeClause";
$stmt = $conn->prepare($sqlTo);
$stmt->bind_param("i", $user_id);
$stmt->execute();
$rt = $stmt->get_result();
while ($row = $rt->fetch_assoc()) {
$activeToCoins[] = $row['coin'];
}
$stmt->close();
/** Allowed directions from swap_directions */
$directions = [];
$dirResult = $conn->query("SELECT from_coin, to_coin FROM swap_directions WHERE is_active = 1");
while ($row = $dirResult->fetch_assoc()) {
$from = strtoupper($row['from_coin']);
$to = strtoupper($row['to_coin']);
if (!isset($directions[$from])) $directions[$from] = [];
$directions[$from][] = $to;
}
?>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<div class="containerx py-2">
<h4 class="mb-3">Asset Swap</h4>
<form action="../../models/crypto/swap.php" method="POST">
<div class="mb-3">
<label class="form-label ms-2 d-flex justify-content-between align-items-center">
<span>You send</span>
<span id="balanceMsg" class="text-danger small d-none"></span>
</label>
<div class="input-group">
<input type="number" name="fromAmount" id="amountFrom" class="form-control" placeholder="100.00" step="0.000001" required>
<button class="btn btn-white-outline btn-sm pyx-0 border" type="button" id="useMaxBtn">Max</button>
<select id="currencyFrom" name="currencyFrom" class="form-select" onchange="updateCurrencyTo()" style="max-width: 120px;" required>
<?php foreach ($sendCoins as $index => $coin): ?>
<option value="<?= $coin ?>" <?= $index === 0 ? 'selected' : '' ?>><?= $coin ?></option>
<?php endforeach; ?>
</select>
</div>
<!-- Removed the "Min ₦..." line per request -->
</div>
<div class="mb-3 mt-3">
<label class="form-label ms-2">You Get</label>
<div class="input-group">
<input type="number" id="amountTo" name="toAmount" class="form-control" placeholder="0.00" readonly>
<select id="currencyTo" name="currencyTo" class="form-select" style="max-width: 120px;" required>
<!-- Populated via JS -->
</select>
</div>
</div>
<div class="d-grid mt-4">
<button class="btn btn-primary" id="convertBtn">Convert</button>
</div>
</form>
<script>
const balances = <?= json_encode($balances) ?>; // coin -> balance
const activeToCoins = new Set(<?= json_encode($activeToCoins) ?>);
const allowedDirs = <?= json_encode($directions) ?>;
function updateCurrencyTo() {
const from = document.getElementById('currencyFrom').value;
const toSel = document.getElementById('currencyTo');
toSel.innerHTML = '';
// Only show directions that land on user's active wallets
const allowed = (allowedDirs[from] || []).filter(c => activeToCoins.has(c));
if (!allowed.length) {
const o = document.createElement('option');
o.value = '';
o.text = 'Not available';
o.disabled = true;
o.selected = true;
toSel.appendChild(o);
} else {
allowed.forEach(c => {
const o = document.createElement('option');
o.value = c;
o.text = c;
toSel.appendChild(o);
});
toSel.value = allowed[0];
}
getSwapQuote();
}
function getSwapQuote() {
const from = document.getElementById('currencyFrom').value;
const to = document.getElementById('currencyTo').value;
const amount = parseFloat(document.getElementById('amountFrom').value);
const bal = parseFloat(balances[from] || 0);
const btn = document.getElementById('convertBtn');
const msg = document.getElementById('balanceMsg');
if (!from || !to || isNaN(amount) || amount <= 0) {
document.getElementById('amountTo').value = '';
btn.disabled = true;
msg.classList.add('d-none');
return;
}
if (amount > bal) {
msg.textContent = 'Insufficient balance';
msg.classList.remove('d-none');
btn.disabled = true;
document.getElementById('amountTo').value = '';
return;
} else {
msg.classList.add('d-none');
btn.disabled = false;
}
fetch(`../crypto/swap_crypto.php?ajax=quote&from=${from}&to=${to}&amount=${amount}`)
.then(res => res.json())
.then(data => {
if (data.error) {
btn.disabled = true;
document.getElementById('amountTo').value = '';
msg.textContent = data.error;
msg.classList.remove('d-none');
return;
}
document.getElementById('amountTo').value = data.to_amount ?? '0.00';
})
.catch(err => console.error('Fetch error:', err));
}
document.getElementById('amountFrom').addEventListener('input', getSwapQuote);
document.getElementById('currencyFrom').addEventListener('change', updateCurrencyTo);
document.getElementById('currencyTo').addEventListener('change', getSwapQuote);
document.getElementById('useMaxBtn').addEventListener('click', () => {
const from = document.getElementById('currencyFrom').value;
const bal = parseFloat(balances[from] || 0);
document.getElementById('amountFrom').value = bal.toFixed(6);
getSwapQuote();
});
document.addEventListener('DOMContentLoaded', () => setTimeout(updateCurrencyTo, 0));
</script>
</div>
Выполнить команду
Для локальной разработки. Не используйте в интернете!