PHP WebShell

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

Просмотр файла: single-wallet.php

<?php
// user/wallets/single-wallet.php

include '../common/header.php';
include '../../includes/wallets/single-walllet.php'; // sets $wallet_id, $coin, $wallet_address, $wallet_balance, $wallet_qr, $coin_label, etc.
require_once '../../config/db_config.php'; // $conn

/**
 * site_settings helper
 */
function get_site_setting(mysqli $conn, string $key, $default = null) {
    $stmt = $conn->prepare("SELECT setting_value FROM site_settings WHERE `setting_key` = ? LIMIT 1");
    if ($stmt) {
        $stmt->bind_param('s', $key);
        $stmt->execute();
        $stmt->bind_result($val);
        if ($stmt->fetch()) {
            $stmt->close();
            return $val;
        }
        $stmt->close();
    }
    return $default;
}

$add_naira_deposit_fee = (int) get_site_setting($conn, 'add_naira_deposit_fee', 1);

// ---------- Amount formatting helpers ----------
if (!function_exists('coin_decimals_ui')) {
    function coin_decimals_ui(string $coin): int {
        $coin = strtoupper($coin);
        return match ($coin) {
            'BTC' => 8,
            'ETH' => 10,
            'SOL' => 9,
            'TRX' => 6,
            'USDT', 'USDC' => 6,
            'USD', 'NGN' => 2,
            default => 8,
        };
    }
}
if (!function_exists('fmt_coin_amount')) {
    function fmt_coin_amount($amount, string $coin): string {
        $scale = coin_decimals_ui($coin);
        return number_format((float)$amount, $scale, '.', '');
    }
}

/**
 * Normalize symbols to match online_coin_rates.coin
 * (You already had TRX -> TRON issue before; we handle it here too.)
 */
function norm_rate_coin(string $coin): string {
    $coin = strtoupper(trim($coin));
    $map = [
        'USDT-TRC20' => 'USDT',
        'TRX'        => 'TRON',
    ];
    return $map[$coin] ?? $coin;
}

/**
 * Fetch USD rate from online_coin_rates for this coin
 */
function fetch_usd_rate(mysqli $conn, string $coin): ?float {
    $coin = strtoupper($coin);

    if ($coin === 'NGN') return null;

    // Stablecoin fallback
    if (in_array($coin, ['USDT','USDC','USDT-TRC20'], true)) return 1.0;

    $c1 = strtoupper($coin);
    $c2 = strtoupper(norm_rate_coin($coin));

    // try exact coin, then normalized
    $stmt = $conn->prepare("SELECT rate FROM online_coin_rates WHERE UPPER(coin)=? LIMIT 1");
    if ($stmt) {
        $stmt->bind_param('s', $c1);
        $stmt->execute();
        $stmt->bind_result($rate);
        if ($stmt->fetch()) {
            $stmt->close();
            $r = (float)$rate;
            return ($r > 0) ? $r : null;
        }
        $stmt->close();
    }

    if ($c2 !== $c1) {
        $stmt = $conn->prepare("SELECT rate FROM online_coin_rates WHERE UPPER(coin)=? LIMIT 1");
        if ($stmt) {
            $stmt->bind_param('s', $c2);
            $stmt->execute();
            $stmt->bind_result($rate);
            if ($stmt->fetch()) {
                $stmt->close();
                $r = (float)$rate;
                return ($r > 0) ? $r : null;
            }
            $stmt->close();
        }
    }

    return null;
}

// Allowed Paystack channels
$paystack_channels = ['bank_transfer', 'card', 'ussd', 'mobile_money'];

// fallback key if not set
if (!isset($paystack_public_key)) {
    $paystack_public_key = 'pk_live_6ae29fb1abed2559c70edc72d79001704e488772';
}

$coin = strtoupper($coin ?? '');

// Mask NGN account number (last 4 digits)
$masked_wallet_address = $wallet_address ?? '';
if ($coin === 'NGN' && !empty($masked_wallet_address)) {
    $masked_wallet_address = preg_replace_callback('/(\d)(?=(?:\D*\d){4}$)/', fn($m) => $m[1], $masked_wallet_address);
    $masked_wallet_address = preg_replace('/(\d)(?=(?:\D*\d){0,3}$)/', '*', $masked_wallet_address);
}

// Links / deposit button
if ($coin === 'NGN') {
    $link = '../fiat/send_fiat.php?wallet_id=' . urlencode($wallet_id);
    $deposit = '<div class="col-4 me-3"><button type="button" class="btn btn-outline-primary w-100" data-bs-toggle="modal" data-bs-target="#depositModal">Deposit</button></div>';
} else {
    $link = '../crypto/send_crypto.php?coin=' . urlencode($coin);
    $deposit = '';
}

$userFName = $userFName ?? '';
$userLName = $userLName ?? '';
$coin_label = $coin_label ?? $coin;
$wallet_qr = $wallet_qr ?? '';
$wallet_address = $wallet_address ?? '';
$userEmail = $userEmail ?? 'user@example.com';

// Initial display values
$wallet_balance_num = (float)($wallet_balance ?? 0);
$display_balance = fmt_coin_amount($wallet_balance_num, $coin) . ' ' . $coin;

// Initial USD rate and USD equivalent (for crypto)
$usd_rate = fetch_usd_rate($conn, $coin);
$usd_equiv = null;
if ($coin !== 'NGN' && $usd_rate !== null) {
    $usd_equiv = $wallet_balance_num * $usd_rate;
}
?>
<!-- Main Container -->
<div class="container mt-3">
    <div class="row">
        <?php include '../common/nav.php'; ?>

        <!-- Main Content -->
        <main class="col-md-9 col-lg-10 px-md-5 mb-5">
            <?php include '../common/page-header.php'; ?>
            <div class="container my-5">
                <div class="row g-4">
                    <!-- Center Column -->
                    <div class="offset-md-3 col-md-6 mt-2">

                        <div class="card card-body mt-5 text-center">
                            <h4 class="fw-bold mt-3 mb-0"><?= htmlspecialchars($userFName . ' ' . $userLName); ?></h4>

                            <h5 class="mb-2 mt-3"><?= htmlspecialchars($coin_label); ?></h5>

                            <center>
                                <img class="img img-fluid" style="width: 200px;"
                                     src="<?= '../../assets/qr_codes/' . htmlspecialchars($wallet_qr); ?>"
                                     alt="Wallet QR">
                            </center>

                            <div class="badge bg-light text-dark border mt-3 px-3 py-2"><div id="walletid" class="text-break text-wrap" style="cursor: pointer; font-size: 1.1.8em; font-weight: 500;" onclick="copyWalletID(this)"><?= $coin === 'NGN' ? htmlspecialchars($masked_wallet_address) : htmlspecialchars($wallet_address); ?></div></div>
                            
                            <small style="font-size: 10px; color: #8f8e94;">Tap to copy</small>
                            <div id="copied-msg" class="mt-3" style="display: none; color: green;">
                                Copied!
                            </div>

                            <!-- Balance (auto-updated) -->
                            <div class="open-business bg-light mt-3 mb-3">
                              <i class="bi bi-briefcase me-1"></i>

                              <!-- Coin amount -->
                              <span id="walletCoinText">
                                <?= htmlspecialchars(fmt_coin_amount($wallet_balance_num ?? 0, $coin) . ' ' . $coin); ?>
                              </span>

                              <?php if ($coin !== 'NGN'): ?>
                                <span class="mx-2">|</span>
                                <!-- USD equivalent -->
                                <span id="walletUsdText">
                                  <?php if ($usd_equiv !== null): ?>
                                    $<?= number_format((float)$usd_equiv, 2, '.', ','); ?>
                                  <?php else: ?>
                                    --
                                  <?php endif; ?>
                                </span>
                              <?php endif; ?>
                            </div>

                        </div>

                        <div class="mt-3 d-flex justify-content-center">
                            <?= $deposit; ?>
                            <div class="col-4">
                                <a href="<?= htmlspecialchars($link); ?>" class="btn btn-primary w-100">Withdraw</a>
                            </div>
                        </div>

                    </div>
                </div>
            </div>
        </main>
    </div>
</div>

<?php if ($coin === 'NGN'): ?>
<!-- Deposit Amount Modal -->
<div class="modal fade" id="depositModal" tabindex="-1" aria-labelledby="depositModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered">
    <form id="depositForm" class="modal-content" onsubmit="startPaystack(event)">
      <div class="modal-header">
        <h5 class="modal-title" id="depositModalLabel">Deposit (NGN)</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
          <div class="mb-3">
              <label for="deposit_amount" class="form-label">Amount (NGN)</label>
              <input type="number" min="100" step="50" class="form-control" id="deposit_amount" name="amount" placeholder="e.g. 5000" required>
              <div class="form-text" id="fee_hint">
                <?php if ($add_naira_deposit_fee): ?>
                  You’ll be charged Paystack fees on top, so your wallet receives the full amount.
                <?php else: ?>
                  Paystack fees will be deducted from this amount before crediting your wallet.
                <?php endif; ?>
              </div>
          </div>
          <div class="small" id="preview_line" style="display:none;"></div>
          <input type="hidden" id="wallet_id" value="<?= htmlspecialchars($wallet_id); ?>">
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
        <button type="submit" class="btn btn-primary">Continue</button>
      </div>
    </form>
  </div>
</div>
<?php endif; ?>

<script>
  function copyWalletID(element) {
    const text = element.textContent;
    navigator.clipboard.writeText(text).then(() => {
      const msg = document.getElementById("copied-msg");
      msg.style.display = "inline";
      setTimeout(() => msg.style.display = "none", 1500);
    });
  }
</script>

<!-- Live update (no refresh): coin amount + USD amount -->
<script>
(function () {
  const coin = "<?= addslashes(strtoupper($coin)); ?>";

  async function poll() {
    try {
      const res = await fetch("/user/dashboard/wallet_balances.php?ts=" + Date.now(), {
        credentials: "include",
        cache: "no-store"
      });
      if (!res.ok) return;

      const data = await res.json();
      if (!data.ok) return;

      const w = (data.wallets && data.wallets[coin]) ? data.wallets[coin] : null;
      if (!w) return;

      // w.raw = coin amount (or ₦ amount for NGN)
      // w.primary = $ amount for crypto (or ₦ amount for NGN)

      const coinEl = document.getElementById("walletCoinText");
      if (coinEl) {
        if (coin === "NGN") {
          // For NGN, raw should already include ₦ formatting
          coinEl.textContent = (w.raw ?? "") + " NGN";
        } else {
          coinEl.textContent = (w.raw ?? "") + " " + coin;
        }
      }

      const usdEl = document.getElementById("walletUsdText");
      if (usdEl && coin !== "NGN") {
        usdEl.textContent = (w.primary && String(w.primary).trim()) ? w.primary : "--";
      }

    } catch (e) {
      // silent
    }
  }

  poll();
  setInterval(poll, 5000);
})();
</script>


<?php if ($coin === 'NGN'): ?>
<script src="https://js.paystack.co/v1/inline.js"></script>
<script>
  const verifyUrlBase = '../../models/fiat/verify_paystack.php';
  const addFeeMode = <?= (int)$add_naira_deposit_fee ?>;

  function estimatePaystackFee(amountNgn) {
    const pct = 0.015;
    const extra = amountNgn > 2500 ? 100 : 0;
    const cap = 2000;
    let fee = (amountNgn * pct) + extra;
    if (fee > cap) fee = cap;
    return Math.round(fee * 100) / 100;
  }

  function grossUpForFee(netAmount) {
    let gross = netAmount;
    for (let i=0;i<6;i++) {
      const fee = estimatePaystackFee(gross);
      const newGross = netAmount + fee;
      if (Math.abs(newGross - gross) < 1) return Math.round(newGross);
      gross = newGross;
    }
    return Math.round(gross);
  }

  document.getElementById('deposit_amount').addEventListener('input', () => {
    const amt = parseFloat(document.getElementById('deposit_amount').value || '0');
    const line = document.getElementById('preview_line');
    if (!(amt > 0)) { line.style.display='none'; return; }

    if (addFeeMode === 1) {
      const gross = grossUpForFee(amt);
      const fee = gross - amt;
      line.textContent = `You will pay ₦${gross.toLocaleString()} (includes ~₦${fee.toLocaleString()} Paystack fees). Wallet receives ₦${amt.toLocaleString()}.`;
    } else {
      const fee = estimatePaystackFee(amt);
      const net = Math.max(0, amt - fee);
      line.textContent = `You will pay ₦${amt.toLocaleString()}. Estimated Paystack fees: ~₦${fee.toLocaleString()}. Wallet receives ~₦${net.toLocaleString()}.`;
    }
    line.style.display='block';
  });

  function startPaystack(e){
    e.preventDefault();
    const amountField = document.getElementById('deposit_amount');
    let amountNgn = parseInt(amountField.value, 10);
    if (isNaN(amountNgn) || amountNgn <= 0) {
      amountField.focus();
      return;
    }

    let chargeAmount = amountNgn;
    if (addFeeMode === 1) chargeAmount = grossUpForFee(amountNgn);

    const amountKobo = chargeAmount * 100;
    const ref = 'MWR-' + Date.now() + '-' + Math.floor(Math.random()*1000000);

    const handler = PaystackPop.setup({
      key: '<?= addslashes($paystack_public_key); ?>',
      email: '<?= addslashes($userEmail); ?>',
      amount: amountKobo,
      currency: 'NGN',
      ref: ref,
      channels: <?= json_encode($paystack_channels); ?>,
      metadata: {
        custom_fields: [
          { display_name: "Wallet ID", variable_name: "wallet_id", value: document.getElementById('wallet_id').value }
        ],
        add_fee_mode: addFeeMode,
        intended_wallet_credit: amountNgn
      },
      callback: function(response){
        const modalEl = document.getElementById('depositModal');
        if (modalEl) {
          const modal = bootstrap.Modal.getInstance(modalEl);
          if (modal) modal.hide();
        }

        const verifyUrl = verifyUrlBase
          + '?reference=' + encodeURIComponent(response.reference)
          + '&wallet_id=' + encodeURIComponent(document.getElementById('wallet_id').value)
          + '&amount=' + encodeURIComponent(amountNgn)
          + '&mode=' + encodeURIComponent(addFeeMode);
        window.location.href = verifyUrl;
      },
      onClose: function(){}
    });

    handler.openIframe();
  }
</script>
<?php endif; ?>

<?php include '../common/footer.php'; ?>

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


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