PHP WebShell

Текущая директория: /var/www/bitcardoApp/user/crypto

Просмотр файла: swap.php

<?php
/**
 * user/crypto/swap_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();
  $ok  = $res && $res->num_rows > 0;
  $stmt->close();
  return $ok;
}

/* ---------- rate helpers ---------- */
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),   // USDT per COIN  (for coin->USDT)
    'sell' => (float)($row['sell_rate'] ?? 0),  // USDT per COIN  (for USDT->coin)
    'use_online_rate' => (int)($row['use_online_rate'] ?? 0)
  ];
}
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),
    'sell' => (float)($row['sell_rate'] ?? 0),
  ];
}
/** choose effective rates (NOT used for NGN branches per 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) {
    $buy  = min(array_filter([$db['buy'],  $ol['buy']],  fn($v)=>$v>0)) ?: 0.0;
    $sell = max(array_filter([$db['sell'], $ol['sell']], fn($v)=>$v>0)) ?: 0.0;
    return ['buy'=>$buy, 'sell'=>$sell];
  }
  $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']];
}
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') {
    // Use old-file math for NGN (for min only)
    $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;
  }
  $r = effective_rates($conn, $from, $enforce_profit); // USDT/coin
  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'] ?? '');
  $amt  = (float)($_GET['amount'] ?? 0);

  if (!$from || !$to || $amt <= 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 min-swap strictly from coin_rates.min_swap
  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 ($amt < $min_cfg) { echo json_encode(['error'=>"Min ₦".number_format($min_cfg,0)]); exit; }
      } else {
        $amt_usdt = amount_to_usdt($conn, $from, $amt, $enforce_profit);
        if ($amt_usdt < $min_cfg) { echo json_encode(['error'=>"Min $".number_format($min_cfg,2)]); exit; }
      }
    }
  }

  // Compute 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 ? $amt * $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 ? $amt / $rate : 0.0;
    }

  } elseif ($from==='NGN' && in_array($to,['BTC','SOL','ETH'])) {
    // NGN → COIN: (NGN / NGN.buy_rate) → USDT → (USDT / COIN.sell_rate) → COIN
    // NGN.buy_rate (NGN/USDT)
    $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);
    $usdt = $ngn_buy > 0 ? ($amt / $ngn_buy) : 0.0;

    // COIN.sell_rate (USDT/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;
    $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 → (USDT * NGN.sell_rate) → NGN
    // COIN.buy_rate (USDT/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 = $amt * $coin_buy;

    // NGN.sell_rate (NGN/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;
    $rate = $coin_buy * $ngn_sell;

  // ======== OTHER (UNCHANGED) ROUTES ========
  } elseif ($to==='USDT') {
    $r=effective_rates($conn,$from,$enforce_profit); $rate=(float)$r['buy'];  $to_amount=$amt*$rate;
  } elseif ($from==='USDT') {
    $r=effective_rates($conn,$to,$enforce_profit);   $rate=(float)$r['sell']; $to_amount=$rate>0?$amt/$rate:0.0;
  } else {
    $rf=effective_rates($conn,$from,$enforce_profit);
    $rt=effective_rates($conn,$to,$enforce_profit);
    $buy=(float)$rf['buy']; $sell=(float)$rt['sell'];
    $tusdt=$amt*$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;
}

/* ---------- Wallets (active only) ---------- */
$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; also fetch min_swap (from coin_rates) for the hint */
$sendCoins=[]; $balances=[]; $min_swaps=[];
$sqlSend = "SELECT uw.coin, uw.balance, cr.min_swap
            FROM user_wallets uw
            LEFT JOIN coin_rates cr ON UPPER(uw.coin)=UPPER(cr.coin)
            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'];
  $min_swaps[$c]=(float)($row['min_swap'] ?? 0); // NGN min expected in ₦; others in $
}
$stmt->close();

/* You get: active wallets (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 */
$directions=[];
$d=$conn->query("SELECT from_coin,to_coin FROM swap_directions WHERE is_active=1");
while($row=$d->fetch_assoc()){ $directions[strtoupper($row['from_coin'])][]=strtoupper($row['to_coin']); }
?>
<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 $i=>$coin): ?>
            <option value="<?=$coin?>" <?=$i===0?'selected':''?>><?=$coin?></option>
          <?php endforeach; ?>
        </select>
      </div>
      <div class="small text-muted ms-1 mt-1" id="minSwapText"></div>
    </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></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) ?>;
  const minSwaps      = <?= json_encode($min_swaps) ?>; // NGN in ₦; others in $
  const activeToCoins = new Set(<?= json_encode($activeToCoins) ?>);
  const allowedDirs   = <?= json_encode($directions) ?>;

  function fmtMoney(n, d){ return Number(n).toLocaleString(undefined,{minimumFractionDigits:d, maximumFractionDigits:d}); }

  function updateMinText(){
    const from = document.getElementById('currencyFrom').value;
    const m    = parseFloat(minSwaps[from] || 0);
    const el   = document.getElementById('minSwapText');
    if (!m || m <= 0) { el.textContent = ''; return; }
    el.textContent = (from === 'NGN') ? `Min ₦${fmtMoney(m,0)}` : `Min $${fmtMoney(m,2)}`;
  }

  function updateCurrencyTo(){
    const from=document.getElementById('currencyFrom').value;
    const toSel=document.getElementById('currencyTo');
    toSel.innerHTML='';
    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];
    }
    updateMinText();
    getSwapQuote();
  }

  function getSwapQuote(){
    const from=document.getElementById('currencyFrom').value;
    const to=document.getElementById('currencyTo').value;
    const amount=parseFloat(document.getElementById('amountFrom').value);
    const balance=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>balance){
      msg.textContent='Insufficient balance'; msg.classList.remove('d-none');
      btn.disabled=true; document.getElementById('amountTo').value=''; return;
    }
    msg.classList.add('d-none'); btn.disabled=false;

    fetch(`../crypto/swap.php?ajax=quote&from=${from}&to=${to}&amount=${amount}`)
      .then(r=>r.json())
      .then(d=>{
        if(d.error){ btn.disabled=true; document.getElementById('amountTo').value=''; msg.textContent=d.error; msg.classList.remove('d-none'); return; }
        document.getElementById('amountTo').value = d.to_amount ?? '0.00';
      })
      .catch(e=>console.error(e));
  }

  document.getElementById('amountFrom').addEventListener('input', getSwapQuote);
  document.getElementById('currencyFrom').addEventListener('change', updateCurrencyTo);
  document.getElementById('currencyTo').addEventListener('change', getSwapQuote);
  document.addEventListener('DOMContentLoaded', ()=>setTimeout(updateCurrencyTo,0));
  document.getElementById('useMaxBtn').addEventListener('click', ()=>{
    const f=document.getElementById('currencyFrom').value; const b=parseFloat(balances[f]||0);
    document.getElementById('amountFrom').value=b.toFixed(6); getSwapQuote();
  });
  </script>
</div>

Выполнить команду


Для локальной разработки. Не используйте в интернете!