", "<", "&", "%", "|", "^", "~", "(", ")"); return str_replace($replacements, "", $input); } } class Admin { public $adminID = -1; public $adminGroupID = -1; public $adminSteamID = ""; public $adminUser = ""; public function IsLoginValid($steamID, $secret_key, $bInitialVerification) { if (empty($steamID) || empty($secret_key) || $secret_key !== $GLOBALS['SECRET_KEY']) { return false; } $sql = "SELECT aid FROM sb_admins WHERE authid = ?"; $stmt = $GLOBALS['SBPP']->prepare($sql); $stmt->bind_param("s", $steamID); $stmt->execute(); $queryResult = $stmt->get_result(); $stmt->close(); // Fetch the result from the query $row = $queryResult->fetch_assoc(); if ($row === null) { return false; } $sbppaid = $row['aid']; // Compare the cookie 'aid' with the result from the query if (!$bInitialVerification && !isset($_COOKIE['aid'])) { return false; } if (!$bInitialVerification && $sbppaid != $_COOKIE['aid']) { return false; } $sql = "SELECT * FROM `sb_admins` WHERE `authid`=?"; $stmt = $GLOBALS['SBPP']->prepare($sql); $stmt->bind_param("s", $steamID); $stmt->execute(); $queryResult = $stmt->get_result(); $stmt->close(); if ($queryResult->num_rows <= 0) { return false; } $acceptableGroups = array_merge(GID_STAFF, GID_ADMIN); $resultsAAA = $queryResult->fetch_all(MYSQLI_ASSOC); foreach ($resultsAAA as $result) { $gid = $result['gid']; if (!in_array($gid, $acceptableGroups) || $gid == -1) { return false; } } return true; } public function UpdateAdminInfo($steamID) { if (!isset($_COOKIE['secret_key'])) { return false; } $secret_key = $_COOKIE['secret_key']; if (!$this->IsLoginValid($steamID, $secret_key, false)) { return false; } $sql = "SELECT `aid`, `gid`, `authid`, `user` FROM `sb_admins` WHERE `authid`=?"; $stmt = $GLOBALS['SBPP']->prepare($sql); $stmt->bind_param("s", $steamID); $stmt->execute(); $queryResult = $stmt->get_result(); if ($queryResult->num_rows <= 0) { $stmt->close(); return false; } $result = $queryResult->fetch_assoc(); $stmt->close(); $this->adminID = $result['aid']; $this->adminGroupID = $result['gid']; $this->adminSteamID = $result['authid']; $this->adminUser = $result['user']; return true; } public function GetAdminNameFromSteamID($steamID) { $steamID = (string) ($steamID ?? ''); if (!str_contains($steamID, "STEAM")) { return "CONSOLE"; } $sql = "SELECT * FROM `sb_admins` WHERE `authid`=?"; $stmt = $GLOBALS['SBPP']->prepare($sql); $stmt->bind_param("s", $steamID); $stmt->execute(); $queryResult = $stmt->get_result(); $stmt->close(); $results = $queryResult->fetch_all(MYSQLI_ASSOC); foreach ($results as $result) { return $result['user']; } return "Admin Deleted"; } public function DoesHaveFullAccess() { if (!isset($_COOKIE['steamID'])) { return false; } if (in_array($this->adminGroupID, GID_STAFF)) { return true; } return false; } } class Kban { public function UnbanByID($id, $reasonA) { if (empty($reasonA)) { $reasonA = "No Reason"; } $reason = Utility::sanitizeInput($reasonA); if (!isset($_COOKIE['steamID'])) { return false; // Should never happen but better be safe } $admin = new Admin(); if (!$admin->UpdateAdminInfo($_COOKIE['steamID'])) { return false; } $adminName = $admin->adminUser; $adminSteamID = $admin->adminSteamID; $kban = new Kban(); $resultsB = $kban->getKbanInfoFromID($id); if ($resultsB === null) { return false; } $length = $resultsB['length']; $time_removed = time(); $sql = "UPDATE `KbRestrict_CurrentBans` SET `is_expired`=1, `is_removed`=1, `web_unban_required`=1, `admin_name_removed`=?, `admin_steamid_removed`=?, `reason_removed`=?, `time_stamp_removed`=? WHERE `id`=?"; $stmt = $GLOBALS['DB']->prepare($sql); $stmt->bind_param("ssssi", $adminName, $adminSteamID, $reason, $time_removed, $id); $stmt->execute(); $stmt->close(); $results = $this->getKbanInfoFromID($id); if ($results === null) { return false; } $playerName = $results['client_name']; $playerSteamID = $results['client_steamid']; $message = "Kban Removed (was $length minutes. Reason: $reason)"; $time_stamp_start = time(); GetRowInfo($id); $sql = "INSERT INTO `KbRestrict_weblogs` (`client_name`, `client_steamid`, `admin_name`, `admin_steamid`, `message`, `time_stamp`) "; $sql .= "VALUES (?, ?, ?, ?, ?, ?)"; $stmt = $GLOBALS['DB']->prepare($sql); $stmt->bind_param("sssssi", $playerName, $playerSteamID, $adminName, $adminSteamID, $message, $time_stamp_start); $stmt->execute(); $stmt->close(); //echo ""; echo ""; return true; } public function RemoveKbanFromDB($id) { $admin = new Admin(); $adminSteamID = isset($_COOKIE['steamID']) ? $_COOKIE['steamID'] : ""; $admin->UpdateAdminInfo($adminSteamID); if (!IsAdminLoggedIn() || !$admin->DoesHaveFullAccess()) { return false; } $resultsC = $this->getKbanInfoFromID($id); if ($resultsC === null) { return false; } $playerName = $resultsC['client_name']; $playerSteamID = $resultsC['client_steamid']; $length = $resultsC['length']; $reason = $resultsC['reason']; $isExpired = ($resultsC['is_expired'] == 1); $isRemoved = ($resultsC['is_removed'] == 1); $status = "Active"; if ($isExpired && !$isRemoved) { $status = "Expired"; } if ($isRemoved) { $status = "Removed"; } $message = "KBan Deleted (was $length minutes. Issued for: $reason. Kban was $status)"; $admin->UpdateAdminInfo($_COOKIE['steamID']); $adminName = $admin->adminUser; $adminSteamID = $admin->adminSteamID; $time_stamp = time(); // No longer a hard DELETE — flag the row for the plugin to reconcile (pull the // ban off disk if it's still active there) and delete once it's done. $stmt = $GLOBALS['DB']->prepare("UPDATE `KbRestrict_CurrentBans` SET `web_ban_delete`=1 WHERE `id` = ?"); $stmt->bind_param('i', $id); $stmt->execute(); $stmt->close(); $stmt = $GLOBALS['DB']->prepare("INSERT INTO `KbRestrict_weblogs` (`client_name`, `client_steamid`, `admin_name`, `admin_steamid`, `message`, `time_stamp`) VALUES (?, ?, ?, ?, ?, ?)"); $stmt->bind_param('sssssi', $playerName, $playerSteamID, $adminName, $adminSteamID, $message, $time_stamp); $stmt->execute(); $stmt->close(); echo ""; //echo ""; return true; } public function formatLength($seconds) { /* if less than one minute */ if ($seconds < 60) { return "$seconds Seconds"; } /* if one minute or more */ if ($seconds >= 60 && $seconds < 3600) { $minutes = ($seconds / 60); $minutesPhrase = ($minutes > 1) ? "Minutes" : "Minute"; return "$minutes $minutesPhrase"; } /* If hour or more*/ if ($seconds >= 3600 && $seconds < 86400) { $hours = intval(($seconds / 3600)); $minutes = intval((($seconds / 60) % 60)); $hoursPhrase = ($hours > 1) ? "Hours" : "Hour"; $minutesPhrase = ($minutes > 1) ? "Minutes" : "Minute"; if ($minutes <= 0) { return "$hours $hoursPhrase"; } return "$hours $hoursPhrase, $minutes $minutesPhrase"; } /* If day or more */ if ($seconds >= 86400 && $seconds < 604800) { $days = intval(($seconds / 86400)); $hours = intval((($seconds / 3600) % 24)); $daysPhrase = ($days > 1) ? "Days" : "Day"; $hoursPhrase = ($hours > 1) ? "Hours" : "Hour"; if ($hours <= 0) { return "$days $daysPhrase"; } return "$days $daysPhrase, $hours $hoursPhrase"; } /* if week or more */ if ($seconds >= 604800 && $seconds < 2592000) { $weeks = intval(($seconds / 604800)); $days = intval((($seconds / 86400) % 7)); $weeksPhrase = ($weeks > 1) ? "Weeks" : "Week"; $daysPhrase = ($days > 1) ? "Days" : "Day"; if ($days <= 0) { return "$weeks $weeksPhrase"; } return "$weeks $weeksPhrase, $days $daysPhrase"; } /* if month or more */ if ($seconds >= 2592000) { $months = intval(($seconds / 2592000)); $days = intval((($seconds / 86400) % 30)); $monthsPhrase = ($months > 1) ? "Months" : "Month"; $daysPhrase = ($days > 1) ? "Days" : "Day"; if ($days <= 0) { return "$months $monthsPhrase"; } return "$months $monthsPhrase, $days $daysPhrase"; } } public function formatPlaytime($minutes) { $minutes = intval($minutes); $hours = intval($minutes / 60); $mins = $minutes % 60; $hoursPhrase = ($hours == 1) ? "Hour" : "Hours"; $minsPhrase = ($mins == 1) ? "Minute" : "Minutes"; if ($hours <= 0) { return "$mins $minsPhrase"; } if ($mins <= 0) { return "$hours $hoursPhrase"; } return "$hours $hoursPhrase, $mins $minsPhrase"; } // Looks up a player's total accumulated playtime (in minutes) from the // separate playtime-stats database, so a web-created kban can be baselined // against the same clock the sourcemod plugin uses. Returns 0 if the player // has no playtime record (e.g. has never connected to the server). public function GetPlaytimeMinutes($steamID) { $stmt = $GLOBALS['DB_PLAYTIME']->prepare( "SELECT SUM(ze_time) AS ze_time_total FROM player_time WHERE steam_id = ? GROUP BY steam_id ORDER BY ze_time_total DESC" ); $stmt->bind_param("s", $steamID); $stmt->execute(); $result = $stmt->get_result(); $row = $result->fetch_assoc(); $stmt->close(); return $row ? intval($row['ze_time_total']) : 0; } public function getKbanInfoFromID($id) { $stmt = $GLOBALS['DB']->prepare("SELECT * FROM `KbRestrict_CurrentBans` WHERE `id` = ? AND `web_ban_delete` = 0"); $stmt->bind_param("i", $id); $stmt->execute(); $query = $stmt->get_result(); $result = $query->fetch_assoc(); $stmt->close(); return $result ?: null; } public function GetKbansNumber($steamID, $IP = "") { $search = (empty($steamID)) ? $IP : $steamID; $searchMethod = (empty($steamID)) ? "client_ip" : "client_steamid"; $stmt = $GLOBALS['DB']->prepare("SELECT COUNT(*) AS total FROM `KbRestrict_CurrentBans` WHERE `$searchMethod` = ? AND `web_ban_delete` = 0"); $stmt->bind_param("s", $search); $stmt->execute(); $queryA = $stmt->get_result(); $row = $queryA->fetch_assoc(); $stmt->close(); $rows = intval($row['total'] ?? 0); return $rows; } public function GetRealKbansNumber($steamID, $IP = "") { $search = (empty($steamID)) ? $IP : $steamID; $searchMethod = (empty($steamID)) ? "client_ip" : "client_steamid"; $stmt = $GLOBALS['DB']->prepare("SELECT COUNT(*) AS total FROM `KbRestrict_CurrentBans` WHERE `$searchMethod` = ? AND `is_removed` = 0 AND `web_ban_delete` = 0"); $stmt->bind_param("s", $search); $stmt->execute(); $queryA = $stmt->get_result(); $row = $queryA->fetch_assoc(); $stmt->close(); $rows = intval($row['total'] ?? 0); return $rows; } public function addNewKban($playerNameA, $playerSteamID, $length, $reasonA) { $admin = new Admin(); $admin->UpdateAdminInfo($_COOKIE['steamID']); $adminName = $admin->adminUser; $adminSteamID = $admin->adminSteamID; $playerName = Utility::sanitizeInput($playerNameA); $reason = Utility::sanitizeInput($reasonA); $lengthInMinutes = ($length / 60); $time_stamp_start = time(); $time_stamp_start_sql = date('Y-m-d H:i:s', $time_stamp_start); if ($length <= -1) { $lengthInMinutes = 30; } else if ($length == 0) { $lengthInMinutes = 0; } if ($this->IsSteamIDAlreadyBanned($playerSteamID)) { die(); } if ($lengthInMinutes == 0) { // Permanent - no playtime baseline needed $time_played_start = -1; $time_played_end = -1; } else { $time_played_start = $this->GetPlaytimeMinutes($playerSteamID); $time_played_end = ($time_played_start + $lengthInMinutes); } // Use prepared statements for the insertion into `KbRestrict_CurrentBans` $sql = "INSERT INTO `KbRestrict_CurrentBans` (`client_name`, `client_steamid`, `client_ip`, `admin_name`, `admin_steamid`, `reason`, `map`, `length`, `time_stamp_start`, `time_played_start`, `time_played_end`, `is_expired`, `is_removed`, `admin_name_removed`, `admin_steamid_removed`, `time_stamp_removed`, `reason_removed`, `web_addban_required`) VALUES (?, ?, 'Unknown', ?, ?, ?, 'Web Ban', ?, ?, ?, ?, 0, 0, 'null', 'null', '0', 'null', 1)"; $stmt = $GLOBALS['DB']->prepare($sql); $stmt->bind_param("sssssisii", $playerName, $playerSteamID, $adminName, $adminSteamID, $reason, $lengthInMinutes, $time_stamp_start_sql, $time_played_start, $time_played_end); $stmt->execute(); $stmt->close(); $message = "Kban Added ("; if ($lengthInMinutes >= 1) { $message .= "$lengthInMinutes Minutes"; } else if ($lengthInMinutes == 0) { $message .= "Permanent"; } else { $message .= "Session"; } $message .= ")"; // Use prepared statements for the insertion into `KbRestrict_weblogs` $sql = "INSERT INTO `KbRestrict_weblogs` (`client_name`, `client_steamid`, `admin_name`, `admin_steamid`, `message`, `time_stamp`) VALUES (?, ?, ?, ?, ?, ?)"; $stmt = $GLOBALS['DB']->prepare($sql); $stmt->bind_param("sssssi", $playerName, $playerSteamID, $adminName, $adminSteamID, $message, $time_stamp_start); $stmt->execute(); $stmt->close(); echo ""; //echo ""; } public function EditKban($id, $playerNameA, $playerSteamID, $length, $reasonA) { $admin = new Admin(); $admin->UpdateAdminInfo($_COOKIE['steamID']); $adminName = $admin->adminUser; $adminSteamID = $admin->adminSteamID; $playerName = Utility::sanitizeInput($playerNameA); $reason = Utility::sanitizeInput($reasonA); $lengthInMinutes = ($length / 60); $info = $this->getKbanInfoFromID($id); if ($info === null) { return false; } if ($length <= -1) { $lengthInMinutes = -1; } else if ($length == 0) { $lengthInMinutes = 0; } $time_played_start = intval($info['time_played_start']); if ($lengthInMinutes <= 0) { // Permanent (or zero-length) - no expiry threshold $time_played_end = -1; } else if ($time_played_start == -1) { // Not yet baselined by the plugin - leave as -1, the plugin computes a // real end value once it establishes the player's actual playtime baseline. $time_played_end = -1; } else { $time_played_end = ($time_played_start + $lengthInMinutes); } // time_played_start is left untouched — it's the plugin's own baseline and // must not be reset by an edit. Only the expiry threshold (time_played_end) // is recalculated from it, along with is_expired being cleared so the ban // becomes active again under its new duration. $sql = "UPDATE `KbRestrict_CurrentBans` SET `client_name`=?, `client_steamid`=?, `reason`=?, `length`=?, `time_played_end`=?, `is_expired`=0, `web_edit_required`=1 WHERE `id`=?"; $stmt = $GLOBALS['DB']->prepare($sql); $stmt->bind_param("sssiii", $playerName, $playerSteamID, $reason, $lengthInMinutes, $time_played_end, $id); $stmt->execute(); $stmt->close(); $message = "Kban Edited ("; if ($playerName != $info['client_name']) { $message .= " New Name: $playerName"; } if ($playerSteamID != $info['client_steamid']) { $message .= " New SteamID: $playerSteamID"; } if ($reason != $info['reason']) { $message .= " New Reason: $reason"; } if ($lengthInMinutes != $info['length']) { if ($lengthInMinutes >= 1) { $message .= " New Length: $lengthInMinutes Minutes"; } else if ($lengthInMinutes == 0) { $message .= " New Length: Permanent"; } else { $message .= " New Length: Session"; } } $message .= " )"; $playerNameOld = $info['client_name']; $playerSteamIDOld = $info['client_steamid']; $time = time(); // Use prepared statements for the INSERT query $sql = "INSERT INTO `KbRestrict_weblogs` (`client_name`, `client_steamid`, `admin_name`, `admin_steamid`, `message`, `time_stamp`) VALUES (?, ?, ?, ?, ?, ?)"; $stmt = $GLOBALS['DB']->prepare($sql); $stmt->bind_param("sssssi", $playerNameOld, $playerSteamIDOld, $adminName, $adminSteamID, $message, $time); $stmt->execute(); $stmt->close(); echo ""; //echo ""; } public function IsSteamIDAlreadyBanned($steamID) { $stmt = $GLOBALS['DB']->prepare("SELECT * FROM `KbRestrict_CurrentBans` WHERE `client_steamid` = ? AND `web_ban_delete` = 0"); $stmt->bind_param("s", $steamID); $stmt->execute(); $query = $stmt->get_result(); $results = $query->fetch_all(MYSQLI_ASSOC); $stmt->close(); foreach ($results as $result) { $isActive = ($result['is_expired'] == 0 && $result['is_removed'] == 0); if ($isActive) { return true; // Early return when a matching active ban is found } } return false; } } function IsAdminLoggedIn() { if(!isset($_COOKIE['steamID']) || !isset($_COOKIE['secret_key'])) { return false; } $steamID = $_COOKIE['steamID']; $secret_key = $_COOKIE['secret_key']; $admin = new Admin(); if ($admin->IsLoginValid($steamID, $secret_key, false)) { return true; } return false; } function EnsureCsrfToken() { if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); } if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } return $_SESSION['csrf_token']; } function ValidateCsrfToken($token) { if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); } $token = (string) ($token ?? ''); if (empty($_SESSION['csrf_token']) || empty($token)) { return false; } return hash_equals($_SESSION['csrf_token'], $token); } function formatMethod(int $method) { $methods = ["client_steamid", "client_name", "client_ip", "admin_name", "admin_steamid", "map", "length"]; return $methods[$method-1] ?? $methods[0]; } function GetRowInfo($id, $result2 = null) { $admin = new Admin(); $kban = new Kban(); if ($id != 0) { $result2 = $kban->getKbanInfoFromID($id); } else if ($result2 !== null) { $id = $result2['id']; } if ($result2 === null) { return; } $clientName = $result2['client_name']; $clientSteamID = $result2['client_steamid']; $clientIP = $result2['client_ip']; $adminSteamID = $result2['admin_steamid']; $reason = $result2['reason']; $map = $result2['map']; $time_stamp_start = strtotime($result2['time_stamp_start']); $length_minutes = intval($result2['length']); $time_played_start = intval($result2['time_played_start']); $isExpired = ($result2['is_expired'] == 1); $isRemoved = ($result2['is_removed'] == 1); $adminNameRemoved = $result2['admin_name_removed']; $time_stamp_removed = $result2['time_stamp_removed']; $reason_removed = $result2['reason_removed']; $adminName = $admin->GetAdminNameFromSteamID($adminSteamID); $isPermanent = ($length_minutes == 0); if ($isPermanent) { $length = "Permanent"; $startedOn = "N/A"; $expiresOn = "Never"; } else { $length = $kban->formatPlaytime($length_minutes); $startedOn = $kban->formatPlaytime($time_played_start) . " played"; $expiresOn = $kban->formatPlaytime($time_played_start + $length_minutes) . " played"; } $status = "Kban Active"; if ($isExpired && !$isRemoved) { $status = "Kban Expired"; } if ($isRemoved) { $status = "Kban Removed"; } echo "
"; $date = new DateTime("now", new DateTimeZone(DATE_TIME_ZONE)); $date->setTimestamp($time_stamp_start); $startDate = $date->format(DATE_TIME_FORMAT); echo "