PHP WebShell

Текущая директория: /var/www/bitcardoApp/backyard/models/security

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

<?php
// backyard/models/security/throttle.php
// Helper functions to inspect and clear throttle / rate-limit tables safely.

if (!function_exists('h')) {
    function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
}

function th_allowed_tables(): array {
    // hard-allow only these tables
    return ['auth_throttle','rate_limits','request_limits'];
}

function th_table_exists(mysqli $conn, string $table): bool {
    $table_safe = mysqli_real_escape_string($conn, $table);
    $sql = "SHOW TABLES LIKE '{$table_safe}'";
    if ($res = mysqli_query($conn, $sql)) {
        $ok = mysqli_num_rows($res) > 0;
        mysqli_free_result($res);
        return $ok;
    }
    return false;
}

/**
 * List rows with very defensive SQL. We try to show common columns if present.
 * @return array{columns: string[], rows: array<int,array>, total:int}
 */
function th_list(mysqli $conn, string $table, array $filters = [], int $page = 1, int $per_page = 50): array {
    $out = ['columns'=>[], 'rows'=>[], 'total'=>0];
    $allowed = th_allowed_tables();
    if (!in_array($table, $allowed, true) || !th_table_exists($conn, $table)) {
        return $out;
    }

    $page = max(1, (int)$page);
    $per_page = max(1, min(200, (int)$per_page));
    $offset = ($page - 1) * $per_page;

    // Discover columns
    $cols = [];
    if ($res = mysqli_query($conn, "DESCRIBE `{$table}`")) {
        while ($r = mysqli_fetch_assoc($res)) { $cols[] = $r['Field']; }
        mysqli_free_result($res);
    }
    $out['columns'] = $cols;

    // Build WHERE from a few common filters if those columns exist
    $w = [];
    $bind = [];
    $like = function($v){ return '%'.str_replace(['%','_'],['\%','\_'],$v).'%'; };

    if (!empty($filters['q'])) {
        $q = $filters['q'];
        // try match ip, token, key, user_id columns if they exist
        $targetCols = array_intersect(['ip','token','key','api_key','identifier','user_id'], $cols);
        if ($targetCols) {
            $parts = [];
            foreach ($targetCols as $c) {
                $parts[] = "`$c` LIKE '".mysqli_real_escape_string($conn, $like($q))."'";
            }
            $w[] = '('.implode(' OR ', $parts).')';
        }
    }
    if (!empty($filters['only_locked'])) {
        // look for status/locked/blocked columns
        foreach (['locked','blocked','is_blocked','status'] as $c) {
            if (in_array($c, $cols, true)) {
                if ($c === 'status') {
                    $w[] = "`status` IN ('locked','blocked','throttled')";
                } else {
                    $w[] = "`{$c}` IN (1,'1',true,'true')";
                }
                break;
            }
        }
    }

    $where = $w ? ('WHERE '.implode(' AND ', $w)) : '';

    // Total
    $sqlTotal = "SELECT COUNT(*) AS c FROM `{$table}` {$where}";
    if ($res = mysqli_query($conn, $sqlTotal)) {
        $r = mysqli_fetch_assoc($res);
        $out['total'] = (int)($r['c'] ?? 0);
        mysqli_free_result($res);
    }

    // Order by a best-effort timestamp/created column, else id, else nothing
    $orderBy = '';
    foreach (['updated_at','created_at','last_seen','timestamp','ts','id'] as $c) {
        if (in_array($c, $cols, true)) {
            $orderBy = "ORDER BY `{$c}` DESC";
            break;
        }
    }

    $sql = "SELECT * FROM `{$table}` {$where} {$orderBy} LIMIT {$per_page} OFFSET {$offset}";
    if ($res = mysqli_query($conn, $sql)) {
        while ($r = mysqli_fetch_assoc($res)) { $out['rows'][] = $r; }
        mysqli_free_result($res);
    }

    return $out;
}

/**
 * Attempt to delete a single row by primary key if possible.
 * We try common PK names: id, fee_id, rate_id, etc; fallback: match by provided composite key.
 */
function th_delete(mysqli $conn, string $table, array $idPayload): array {
    $allowed = th_allowed_tables();
    if (!in_array($table, $allowed, true) || !th_table_exists($conn, $table)) {
        return ['ok'=>false, 'error'=>'Invalid table'];
    }

    // Identify a primary/unique column
    $pk = null;
    $cols = [];
    if ($res = mysqli_query($conn, "DESCRIBE `{$table}`")) {
        while ($r = mysqli_fetch_assoc($res)) { $cols[] = $r['Field']; }
        mysqli_free_result($res);
    }
    foreach (['id','lock_id','limit_id','rid'] as $c) {
        if (in_array($c, $cols, true) && isset($idPayload[$c])) { $pk = $c; break; }
    }
    if ($pk) {
        $val = mysqli_real_escape_string($conn, (string)$idPayload[$pk]);
        $sql = "DELETE FROM `{$table}` WHERE `{$pk}` = '{$val}' LIMIT 1";
        return ['ok'=> (bool)mysqli_query($conn, $sql), 'error'=> mysqli_error($conn)];
    }

    // Fallback: try to match by ip / token / key
    foreach (['ip','token','key','api_key','identifier'] as $c) {
        if (in_array($c, $cols, true) && isset($idPayload[$c])) {
            $val = mysqli_real_escape_string($conn, (string)$idPayload[$c]);
            $sql = "DELETE FROM `{$table}` WHERE `{$c}` = '{$val}' LIMIT 1";
            return ['ok'=> (bool)mysqli_query($conn, $sql), 'error'=> mysqli_error($conn)];
        }
    }

    return ['ok'=>false, 'error'=>'No matching identifier'];
}

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


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