PHP WebShell
Текущая директория: /var/www/bitcardoApp/backyard/user/security
Просмотр файла: throttle.php
<?php
// backyard/user/security/throttle.php
include '../common/header.php';
if (!isset($conn)) { include_once '../../config/db_config.php'; }
require_once '../../models/security/throttle.php';
date_default_timezone_set('Africa/Lagos');
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
$table = $_GET['table'] ?? 'auth_throttle';
$allowed = th_allowed_tables();
if (!in_array($table, $allowed, true)) { $table = 'auth_throttle'; }
$filters = [
'q' => $_GET['q'] ?? '',
'only_locked' => isset($_GET['only_locked']) ? 1 : 0,
'page' => (int)($_GET['page'] ?? 1),
'per_page' => (int)($_GET['per_page'] ?? 50),
];
$data = th_list($conn, $table, $filters, $filters['page'], $filters['per_page']);
function qurl(array $add=[]){
$qs = array_merge($_GET, $add);
return '?'.http_build_query($qs);
}
?>
<style>
.table td, .table th { vertical-align: middle; }
.code-sm { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; font-size: .825rem; }
@media (max-width: 767.98px){
.stack-sm>*{ margin-bottom:.5rem; }
.table-responsive{ overflow-x:auto; }
}
</style>
<div class="nk-content nk-content-fluid mt-5">
<div class="container-xl wide-lg">
<div class="nk-content-body">
<div class="nk-block-head">
<div class="nk-block-between-md g-3">
<div class="nk-block-head-content">
<h4 class="nk-block-title fw-normal">Rate-limit & Throttle Monitor</h4>
<p class="text-soft mb-0">Inspect and clear locks across throttle tables.</p>
</div>
<div class="nk-block-head-content">
<a href="../dashboard/index.php" class="btn btn-outline-secondary btn-sm">Back</a>
</div>
</div>
</div>
<div class="nk-block">
<div class="card card-bordered">
<div class="card-inner">
<form class="row g-2 mb-3" method="get">
<div class="col-12 col-md-3">
<label class="form-label small">Table</label>
<select class="form-select" name="table" onchange="this.form.submit()">
<?php foreach ($allowed as $t): ?>
<option value="<?= h($t); ?>" <?= $t===$table?'selected':''; ?>><?= h($t); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-8 col-md-5">
<label class="form-label small">Search (ip/token/key/user)</label>
<input type="text" class="form-control" name="q" value="<?= h($filters['q']); ?>" placeholder="e.g. 127.0.0.1 or user id">
</div>
<div class="col-4 col-md-2 d-flex align-items-end">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="only_locked" id="only_locked" <?= $filters['only_locked']?'checked':''; ?>>
<label class="form-check-label small" for="only_locked">Only locked</label>
</div>
</div>
<div class="col-12 col-md-2 d-flex align-items-end justify-content-end">
<button class="btn btn-primary w-100 w-md-auto">Apply</button>
</div>
</form>
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0"><?= h($table); ?></h6>
<div class="small text-soft">Total: <?= number_format($data['total']); ?></div>
</div>
<div class="table-responsive">
<table class="table table-striped table-sm align-middle">
<thead class="small text-soft">
<tr>
<?php foreach ($data['columns'] as $c): ?>
<th><?= h($c); ?></th>
<?php endforeach; ?>
<th class="text-end">Action</th>
</tr>
</thead>
<tbody>
<?php if (empty($data['rows'])): ?>
<tr><td colspan="<?= count($data['columns'])+1; ?>" class="text-center text-muted py-4">No data.</td></tr>
<?php else: foreach ($data['rows'] as $row): ?>
<tr>
<?php foreach ($data['columns'] as $c):
$v = $row[$c] ?? '';
$disp = is_scalar($v) ? (string)$v : json_encode($v);
?>
<td class="code-sm"><?= h($disp); ?></td>
<?php endforeach; ?>
<td class="text-end">
<button class="btn btn-xs btn-outline-danger" onclick='thDelete(<?= json_encode(['table'=>$table,'id'=>$row], JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_AMP|JSON_HEX_QUOT); ?>)'>Clear</button>
</td>
</tr>
<?php endforeach; endif; ?>
</tbody>
</table>
</div>
<?php if ($data['total'] > $filters['per_page']):
$p = max(1,(int)$filters['page']);
$pages = max(1, (int)ceil($data['total'] / max(1,(int)$filters['per_page'])));
$prev = max(1, $p-1); $next = min($pages, $p+1);
?>
<div class="d-flex justify-content-between align-items-center mt-2">
<div class="small text-soft">Page <?= $p; ?> of <?= $pages; ?></div>
<ul class="pagination pagination-sm mb-0">
<li class="page-item <?= $p<=1?'disabled':''; ?>"><a class="page-link" href="<?= qurl(['page'=>1]); ?>">« First</a></li>
<li class="page-item <?= $p<=1?'disabled':''; ?>"><a class="page-link" href="<?= qurl(['page'=>$prev]); ?>">‹ Prev</a></li>
<li class="page-item disabled"><span class="page-link"><?= $p; ?></span></li>
<li class="page-item <?= $p>=$pages?'disabled':''; ?>"><a class="page-link" href="<?= qurl(['page'=>$next]); ?>">Next ›</a></li>
<li class="page-item <?= $p>=$pages?'disabled':''; ?>"><a class="page-link" href="<?= qurl(['page'=>$pages]); ?>">Last »</a></li>
</ul>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
async function thDelete(payload){
if(!confirm('Clear this lock/row?')) return;
try{
const resp = await fetch('../../models/security/throttle_actions.php', {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({ action:'delete', table: payload.table, id: payload.id })
});
const txt = await resp.text();
let data; try { data = JSON.parse(txt); } catch(e){ throw new Error('Bad JSON: '+txt.substring(0,160)); }
if(!data.ok){ alert('Failed: '+(data.error||'Unknown')); return;}
location.reload();
}catch(err){
alert(err.message || 'Network error');
}
}
</script>
<?php include '../common/footer.php'; ?>
Выполнить команду
Для локальной разработки. Не используйте в интернете!