0 && substr($ipBin, 0, $fullBytes) !== substr($subBin, 0, $fullBytes)) { return false; } if ($remBits > 0) { $mask = chr((0xff << (8 - $remBits)) & 0xff); if ((ord($ipBin[$fullBytes]) & ord($mask)) !== (ord($subBin[$fullBytes]) & ord($mask))) { return false; } } return true; } /** * Converts an IP string to its packed binary form (for varbinary storage). * Returns null on invalid input. */ public static function toBinary($ip) { $bin = @inet_pton($ip); return $bin === false ? null : $bin; } /** * Blocks the request if the resolved client IP is banned. * Renders a stand-alone 403 page and stops execution. Never throws. * * @param object $database The global Database instance (must expose ipBanActive()). */ public static function enforce($database) { if (defined('BAN_IP_ENABLED') && !BAN_IP_ENABLED) { return; } $ip = self::getClientIp(); if ($ip === null) { return; } $bin = self::toBinary($ip); if ($bin === null || !is_object($database) || !method_exists($database, 'ipBanActive')) { return; } $ban = $database->ipBanActive($bin); if (!$ban) { return; } if (!headers_sent()) { header('HTTP/1.1 403 Forbidden'); header('Content-Type: text/html; charset=UTF-8'); } $reason = (isset($ban['reason']) && $ban['reason'] !== '') ? htmlspecialchars($ban['reason'], ENT_QUOTES, 'UTF-8') : ''; $until = !empty($ban['end']) ? date('Y-m-d H:i', (int) $ban['end']) : '∞'; echo '' . '' . 'Access blocked' . '' . '

Access blocked

' . '

Your IP address has been banned from this server.

' . ($reason !== '' ? '

Reason: ' . $reason . '

' : '') . '

Ban expires: ' . $until . '

' . ''; exit; } }