PHP WebShell
Текущая директория: /var/www/bitcardoApp/backyard/user/users
Просмотр файла: view.php
<?php
// backyard/user/users/view.php
include '../common/header.php';
if (!isset($conn)) { include_once '../../config/db_config.php'; }
require_once '../../models/users/index.php';
date_default_timezone_set('Africa/Lagos');
$user_id = isset($_GET['user_id']) ? (int)$_GET['user_id'] : 0;
if ($user_id <= 0) {
echo '<div class="nk-content nk-content-fluid"><div class="container-xl wide-lg"><div class="nk-content-body"><div class="alert alert-warning">Invalid user.</div></div></div></div>';
include '../common/footer.php'; exit;
}
$u = users_get_basic($conn, $user_id);
if (!$u) {
echo '<div class="nk-content nk-content-fluid"><div class="container-xl wide-lg"><div class="nk-content-body"><div class="alert alert-warning">User not found.</div></div></div></div>';
include '../common/footer.php'; exit;
}
$wl = users_get_wallets($conn, $user_id);
$tr = users_get_recent_trades($conn, $user_id, 20);
$tx = users_get_recent_tx($conn, $user_id, 20);
$ss = users_get_sessions($conn, $user_id, 20);
$dv = users_get_devices($conn, $user_id);
$sec = users_get_security($conn, $user_id);
// Total transactions count (for Overview card)
$tx_total = 0;
if ($res = mysqli_query($conn, "SELECT COUNT(*) AS c FROM transactions WHERE user_id = {$user_id}")) {
$row = mysqli_fetch_assoc($res);
$tx_total = (int)($row['c'] ?? 0);
mysqli_free_result($res);
}
$fullname = trim(($u['first_name'] ?? '').' '.($u['last_name'] ?? ''));
$statusClass = badge_class($u['user_status'] ?? '');
if (!function_exists('h')) { function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } }
if (!function_exists('mny')){ function mny($n,$d=2){ return number_format((float)$n,$d); } }
?>
<style>
.gc-card { border:1px solid #e5e7eb; border-radius:.5rem; padding:.75rem; }
.gc-kv { display:flex; justify-content:space-between; gap:.75rem; }
.gc-kv .k { color:#6c757d; font-size:.85rem; }
.gc-kv .v { font-weight:600; }
</style>
<div class="nk-content nk-content-fluid">
<div class="container-xl wide-lg">
<div class="nk-content-body">
<div class="nk-block-head">
<div class="nk-block-between-md g-3 align-items-center">
<div class="nk-block-head-content">
<div class="nk-block-head-sub"><span>User Profile</span></div>
<h3 class="nk-block-title fw-normal mb-1">
<?= h($fullname ?: '—'); ?>
<span class="badge <?= $statusClass; ?> align-middle"><?= h($u['user_status'] ?: '—'); ?></span>
</h3>
<div class="nk-block-des">
<p class="text-soft mb-1">
<?= h($u['email'] ?: '—'); ?> · <?= h($u['phone'] ?: '—'); ?> · ID: <?= (int)$u['user_id']; ?>
</p>
</div>
</div>
<div class="nk-block-head-content">
<ul class="nk-block-tools gx-2">
<li>
<button class="btn <?= (strtolower($u['user_status'])==='active'?'btn-danger':'btn-success'); ?>"
onclick="openStatusConfirm(<?= (int)$u['user_id']; ?>,'<?= h($u['user_status']); ?>','<?= h($fullname ?: 'this user'); ?>')">
<?= (strtolower($u['user_status'])==='active'?'Suspend User':'Activate User'); ?>
</button>
</li>
<li><a href="users.php" class="btn btn-outline-secondary">Back to Users</a></li>
</ul>
</div>
</div>
</div>
<!-- Tabs -->
<ul class="nav nav-tabs mt-2" role="tablist">
<li class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tab-overview" type="button">Overview</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-wallets" type="button">Wallets</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-trades" type="button">Gift Cards</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-trans" type="button">Transactions</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#tab-security" type="button">Security</button></li>
</ul>
<div class="tab-content mt-3">
<!-- Overview -->
<div class="tab-pane fade show active" id="tab-overview">
<div class="d-md-none">
<div class="gc-card mb-2">
<div class="gc-kv"><div class="k">Total No. of Transactions</div><div class="v"><?= (int)$tx_total; ?></div></div>
<div class="gc-kv"><div class="k">Created</div><div class="v"><?= h($u['created_at'] ?? '—'); ?></div></div>
<div class="gc-kv"><div class="k">Updated</div><div class="v"><?= h($u['updated_at'] ?? '—'); ?></div></div>
<div class="gc-kv"><div class="k">Wallets</div><div class="v"><?= count($wl); ?></div></div>
</div>
</div>
<div class="row g-2 d-none d-md-flex">
<div class="col-md-3"><div class="card card-bordered"><div class="card-inner p-2"><div class="small text-soft">Total No. of Transactions</div><div class="fw-bold"><?= (int)$tx_total; ?></div></div></div></div>
<div class="col-md-3"><div class="card card-bordered"><div class="card-inner p-2"><div class="small text-soft">Created</div><div class="fw-bold"><?= h($u['created_at'] ?? '—'); ?></div></div></div></div>
<div class="col-md-3"><div class="card card-bordered"><div class="card-inner p-2"><div class="small text-soft">Updated</div><div class="fw-bold"><?= h($u['updated_at'] ?? '—'); ?></div></div></div></div>
<div class="col-md-3"><div class="card card-bordered"><div class="card-inner p-2"><div class="small text-soft">Wallets</div><div class="fw-bold"><?= count($wl); ?></div></div></div></div>
</div>
</div>
<!-- Wallets (with toggle) -->
<div class="tab-pane fade" id="tab-wallets">
<?php if (empty($wl)): ?>
<div class="alert alert-light border mb-0">No wallets.</div>
<?php else: ?>
<!-- Desktop table -->
<div class="table-responsive d-none d-md-block">
<table class="table table-sm align-middle">
<thead class="small text-soft">
<tr>
<th>Label</th>
<th>Coin</th>
<th>Type</th>
<th>Balance</th>
<th>Status</th>
<th>Updated</th>
<th class="text-end">Freeze</th>
</tr>
</thead>
<tbody>
<?php foreach ($wl as $w): ?>
<?php
$isFrozen = strcasecmp((string)$w['wallet_status'], 'Frozen') === 0;
$toggleChecked = $isFrozen ? 'checked' : '';
$labelText = $isFrozen ? 'Frozen' : 'Active';
?>
<tr>
<td><?= h($w['label'] ?: '—'); ?></td>
<td><?= h($w['coin'] ?: '—'); ?></td>
<td><?= h($w['type'] ?: '—'); ?></td>
<td><?= mny($w['balance'] ?? 0, 4); ?></td>
<td>
<span class="badge <?= $isFrozen ? 'bg-secondary' : 'bg-success'; ?> wallet-status-badge">
<?= h($labelText); ?>
</span>
</td>
<td class="small"><?= h($w['updated_at'] ?: '—'); ?></td>
<td class="text-end">
<div class="form-check form-switch m-0 d-inline-block">
<input class="form-check-input wallet-freeze-toggle"
type="checkbox"
role="switch"
<?= $toggleChecked; ?>
data-wallet-id="<?= (int)$w['wallet_id']; ?>"
data-label="<?= h(($w['label'] ?: $w['coin'] ?: 'Wallet')); ?>">
<label class="form-check-label small ms-1"><?= $isFrozen ? 'On' : 'Off'; ?></label>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- Mobile cards -->
<div class="d-md-none">
<?php foreach ($wl as $w): ?>
<?php
$isFrozen = strcasecmp((string)$w['wallet_status'], 'Frozen') === 0;
$toggleChecked = $isFrozen ? 'checked' : '';
$labelText = $isFrozen ? 'Frozen' : 'Active';
?>
<div class="gc-card mb-2">
<div class="d-flex justify-content-between align-items-center mb-1">
<div class="fw-bold"><?= h($w['label'] ?: '—'); ?></div>
<span class="badge <?= $isFrozen ? 'bg-secondary' : 'bg-success'; ?> wallet-status-badge">
<?= h($labelText); ?>
</span>
</div>
<div class="gc-kv mt-1"><div class="k">Coin</div><div class="v"><?= h($w['coin'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Type</div><div class="v"><?= h($w['type'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Balance</div><div class="v"><?= mny($w['balance'] ?? 0, 4); ?></div></div>
<div class="gc-kv"><div class="k">Updated</div><div class="v small"><?= h($w['updated_at'] ?: '—'); ?></div></div>
<div class="d-flex justify-content-between align-items-center mt-2">
<div class="small text-soft">Freeze</div>
<div class="form-check form-switch m-0">
<input class="form-check-input wallet-freeze-toggle"
type="checkbox"
role="switch"
<?= $toggleChecked; ?>
data-wallet-id="<?= (int)$w['wallet_id']; ?>"
data-label="<?= h(($w['label'] ?: $w['coin'] ?: 'Wallet')); ?>">
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<!-- Gift Cards -->
<div class="tab-pane fade" id="tab-trades">
<?php if (empty($tr)): ?>
<div class="alert alert-light border mb-0">No recent gift card trades.</div>
<?php else: ?>
<div class="d-md-none">
<?php foreach ($tr as $r):
$created = $r['trade_created'] ? date('M j, Y g:i A', strtotime($r['trade_created'])) : '—';
$val = mny($r['card_value'] ?? 0, 2).' '.h($r['card_curr'] ?? '');
$payout = mny($r['est_payout_ngn'] ?? 0, 2);
?>
<div class="gc-card mb-2">
<div class="gc-kv"><div class="k">Batch</div><div class="v"><a href="../orders/process_order.php?batch=<?= urlencode($r['batch_ref']); ?>"><?= h($r['batch_ref']); ?></a></div></div>
<div class="gc-kv"><div class="k">Card Ref</div><div class="v"><?= $r['card_ref'] ? '<a href="../orders/process_order.php?ref='.urlencode($r['card_ref']).'">'.h($r['card_ref']).'</a>' : '—'; ?></div></div>
<div class="gc-kv"><div class="k">Brand</div><div class="v"><?= h($r['card_brand'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Denom</div><div class="v"><?= h($r['demon'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Value</div><div class="v"><?= $val; ?></div></div>
<div class="gc-kv"><div class="k">Est. Payout (₦)</div><div class="v"><?= $payout; ?></div></div>
<div class="gc-kv"><div class="k">Status</div><div class="v"><?= h($r['trade_status'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Created</div><div class="v small"><?= h($created); ?></div></div>
<div class="mt-2"><a class="btn btn-sm btn-outline-primary w-100" href="../orders/process_order.php?ref=<?= urlencode($r['card_ref']); ?>">Open</a></div>
</div>
<?php endforeach; ?>
</div>
<div class="table-responsive d-none d-md-block">
<table class="table table-sm">
<thead class="small text-soft">
<tr><th>Batch</th><th>Card Ref</th><th>Brand</th><th>Denom</th><th>Value</th><th>Est. Payout (₦)</th><th>Status</th><th>Created</th><th></th></tr>
</thead>
<tbody>
<?php foreach ($tr as $r):
$created = $r['trade_created'] ? date('M j, Y g:i A', strtotime($r['trade_created'])) : '—';
$val = mny($r['card_value'] ?? 0, 2).' '.h($r['card_curr'] ?? '');
$payout = mny($r['est_payout_ngn'] ?? 0, 2);
?>
<tr>
<td><a href="../orders/process_order.php?batch=<?= urlencode($r['batch_ref']); ?>"><?= h($r['batch_ref']); ?></a></td>
<td><?= $r['card_ref'] ? '<a href="../orders/process_order.php?ref='.urlencode($r['card_ref']).'">'.h($r['card_ref']).'</a>' : '—'; ?></td>
<td><?= h($r['card_brand'] ?: '—'); ?></td>
<td><?= h($r['demon'] ?: '—'); ?></td>
<td><?= $val; ?></td>
<td><?= $payout; ?></td>
<td><?= h($r['trade_status'] ?: '—'); ?></td>
<td class="small"><?= h($created); ?></td>
<td class="text-end"><a class="btn btn-xs btn-outline-primary" href="../orders/process_order.php?ref=<?= urlencode($r['card_ref']); ?>">Open</a></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<!-- Transactions -->
<div class="tab-pane fade" id="tab-trans">
<?php if (empty($tx)): ?>
<div class="alert alert-light border mb-0">No recent transactions.</div>
<?php else: ?>
<div class="d-md-none">
<?php foreach ($tx as $t): ?>
<div class="gc-card mb-2">
<div class="gc-kv"><div class="k">#</div><div class="v"><?= (int)$t['trans_id']; ?></div></div>
<div class="gc-kv"><div class="k">Coin</div><div class="v"><?= h($t['coin'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Amount</div><div class="v"><?= mny($t['amount'] ?? 0, 8); ?></div></div>
<div class="gc-kv"><div class="k">Type</div><div class="v"><?= h($t['type'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Status</div><div class="v"><?= h($t['status'] ?: '—'); ?></div></div>
<div class="gc-kv"><div class="k">Reference</div><div class="v small"><?= h($t['reference'] ?: ''); ?></div></div>
<div class="gc-kv"><div class="k">Created</div><div class="v small"><?= h($t['created_at'] ?: '—'); ?></div></div>
</div>
<?php endforeach; ?>
</div>
<div class="table-responsive d-none d-md-block">
<table class="table table-sm">
<thead class="small text-soft"><tr><th>#</th><th>Coin</th><th>Amount</th><th>Type</th><th>Status</th><th>Reference</th><th>Created</th></tr></thead>
<tbody>
<?php foreach ($tx as $t): ?>
<tr>
<td><?= (int)$t['trans_id']; ?></td>
<td><?= h($t['coin'] ?: '—'); ?></td>
<td><?= mny($t['amount'] ?? 0, 8); ?></td>
<td><?= h($t['type'] ?: '—'); ?></td>
<td><?= h($t['status'] ?: '—'); ?></td>
<td class="small"><?= h($t['reference'] ?: ''); ?></td>
<td class="small"><?= h($t['created_at'] ?: '—'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
<!-- Security -->
<div class="tab-pane fade" id="tab-security">
<div class="row g-2">
<div class="col-12 col-md-6">
<div class="card card-bordered h-100">
<div class="card-inner p-2">
<h6 class="mb-2">Two-Factor (TOTP)</h6>
<?php if (!empty($sec['totp'])): ?>
<div class="small text-soft">Enabled: <strong><?= (int)$sec['totp']['enabled'] ? 'Yes' : 'No'; ?></strong></div>
<div class="small">Verified: <strong><?= h($sec['totp']['verified_at'] ?: '—'); ?></strong></div>
<div class="small text-soft">Created: <?= h($sec['totp']['created_at'] ?: '—'); ?></div>
<?php else: ?>
<div class="small">No TOTP record.</div>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-12 col-md-6">
<div class="card card-bordered h-100">
<div class="card-inner p-2">
<h6 class="mb-2">Recent OTPs</h6>
<?php if (empty($sec['otps'])): ?>
<div class="small">No recent OTP activity.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm">
<thead class="small text-soft"><tr><th>Channel</th><th>Created</th><th>Expires</th><th>Used</th><th>Attempts</th></tr></thead>
<tbody>
<?php foreach ($sec['otps'] as $o): ?>
<tr>
<td><?= h($o['channel']); ?></td>
<td class="small"><?= h($o['created_at']); ?></td>
<td class="small"><?= h($o['expires_at']); ?></td>
<td class="small"><?= h($o['consumed_at'] ?: '—'); ?></td>
<td class="small"><?= (int)$o['attempts']; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-12">
<div class="card card-bordered">
<div class="card-inner p-2">
<h6 class="mb-2">Sessions</h6>
<?php if (empty($ss)): ?>
<div class="small">No sessions.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm">
<thead class="small text-soft"><tr><th>IP</th><th>Agent</th><th>Device</th><th>Created</th><th>Last Seen</th><th>Expires</th><th>Revoked</th></tr></thead>
<tbody>
<?php foreach ($ss as $s): ?>
<tr>
<td class="small"><?= h($s['ip_address']); ?></td>
<td class="small text-break"><?= h($s['user_agent']); ?></td>
<td class="small"><?= h($s['device_label'] ?: '—'); ?></td>
<td class="small"><?= h($s['created_at'] ?: '—'); ?></td>
<td class="small"><?= h($s['last_seen_at'] ?: '—'); ?></td>
<td class="small"><?= h($s['expires_at'] ?: '—'); ?></td>
<td class="small"><?= h($s['revoked_at'] ?: '—'); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
<div class="col-12">
<div class="card card-bordered">
<div class="card-inner p-2">
<h6 class="mb-2">Devices</h6>
<?php if (empty($dv)): ?>
<div class="small">No devices.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-sm">
<thead class="small text-soft"><tr><th>Label</th><th>Device ID</th><th>Trusted</th><th>First Seen</th><th>Last Seen</th><th>IP (first/last)</th></tr></thead>
<tbody>
<?php foreach ($dv as $d): ?>
<tr>
<td class="small"><?= h($d['device_label'] ?: '—'); ?></td>
<td class="small"><?= h($d['device_id']); ?></td>
<td class="small"><?= (int)$d['trusted'] ? 'Yes' : 'No'; ?><?= $d['trusted_until'] ? ' (until '.h($d['trusted_until']).')' : ''; ?></td>
<td class="small"><?= h($d['first_seen_at'] ?: '—'); ?></td>
<td class="small"><?= h($d['last_seen_at'] ?: '—'); ?></td>
<td class="small"><?= h(($d['first_ip'] ?: '—').' / '.($d['last_ip'] ?: '—')); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div><!-- /Security -->
</div><!-- /.tab-content -->
</div>
</div>
</div>
<!-- Confirm Activate/Suspend Modal -->
<div class="modal fade" id="confirmUserStatusModal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header"><h6 class="modal-title">Confirm Action</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
<div class="modal-body" id="confirmUserStatusBody">Are you sure?</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger" id="confirmUserStatusBtn">Yes, Proceed</button>
</div>
</div>
</div>
</div>
<script>
let __pendingUserId = null, __pendingUserStatus = '', __pendingUserName = '';
function openStatusConfirm(uid, currentStatus, fullname){
__pendingUserId = uid;
__pendingUserStatus = currentStatus;
__pendingUserName = fullname || 'this user';
const action = (String(currentStatus).toLowerCase()==='active') ? 'suspend' : 'activate';
document.getElementById('confirmUserStatusBody').innerText =
`Are you sure you want to ${action} ${__pendingUserName}?`;
new bootstrap.Modal(document.getElementById('confirmUserStatusModal')).show();
}
document.getElementById('confirmUserStatusBtn').addEventListener('click', function(){
const form = new URLSearchParams();
form.append('user_id', __pendingUserId);
form.append('status', __pendingUserStatus);
fetch('../../models/users/update_user.php', {
method: 'POST', headers: {'Content-Type':'application/x-www-form-urlencoded'}, body: form.toString()
}).then(r => r.json()).then(j => { if (j.success){ location.reload(); } else { alert(j.message||'Action failed.'); } })
.catch(()=>alert('Network error'));
});
</script>
<!-- Wallet Freeze Toggle JS -->
<script>
(function(){
const busy = new Set();
async function postToggle(walletId, freeze){
const form = new URLSearchParams();
form.append('action', 'toggle_freeze');
form.append('wallet_id', walletId);
form.append('freeze', freeze);
const resp = await fetch('../../models/users/toggle_wallet.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: form.toString()
});
const text = await resp.text(); // be tolerant to non-JSON
let data;
try { data = JSON.parse(text); }
catch(e){
throw new Error('Bad JSON from server: ' + text.substring(0, 200));
}
if (!resp.ok || !data || data.success !== true) {
const msg = (data && data.message) ? data.message : ('HTTP ' + resp.status);
throw new Error(msg + (data && data._diag ? ' | ' + data._diag : ''));
}
return data;
}
document.addEventListener('change', async function(e){
const el = e.target.closest('.wallet-freeze-toggle');
if (!el) return;
const walletId = el.getAttribute('data-wallet-id');
if (!walletId || busy.has(walletId)) return;
const freeze = el.checked ? '1' : '0'; // checked = Freeze ON
busy.add(walletId);
el.disabled = true;
try {
await postToggle(walletId, freeze);
// Reload to keep badges/status consistent
location.reload();
} catch (err) {
// revert UI if failed
el.checked = !el.checked;
alert('Request failed: ' + (err && err.message ? err.message : err));
} finally {
busy.delete(walletId);
el.disabled = false;
}
});
})();
</script>
<script>
(function () {
// On load: if there is a hash (#tab-wallets etc), show that tab
document.addEventListener('DOMContentLoaded', function () {
var hash = window.location.hash;
if (hash && document.querySelector('[data-bs-target="' + hash + '"]')) {
var triggerEl = document.querySelector('[data-bs-target="' + hash + '"]');
bootstrap.Tab.getOrCreateInstance(triggerEl).show();
}
// Keep URL hash in sync when the user switches tabs
document.querySelectorAll('[data-bs-toggle="tab"]').forEach(function (el) {
el.addEventListener('shown.bs.tab', function (e) {
var target = e.target.getAttribute('data-bs-target');
if (target) history.replaceState(null, '', target);
});
});
});
})();
</script>
<?php include '../common/footer.php'; ?>
Выполнить команду
Для локальной разработки. Не используйте в интернете!