32) { return false; } $clientIpLong = ip2long($clientIp); $subnetLong = ip2long($subnet); $maskLong = (-1 << (32 - $mask)); return ($clientIpLong & $maskLong) === ($subnetLong & $maskLong); } /** * IP范围匹配 * * @param string $clientIp * @param string $range * @return bool */ private static function matchRange(string $clientIp, string $range): bool { list($startIp, $endIp) = explode('-', $range, 2); $startIp = trim($startIp); $endIp = trim($endIp); if (!filter_var($startIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) || !filter_var($endIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) || !filter_var($clientIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return false; } $clientIpLong = ip2long($clientIp); $startIpLong = ip2long($startIp); $endIpLong = ip2long($endIp); return $clientIpLong >= $startIpLong && $clientIpLong <= $endIpLong; } /** * 通配符匹配 * * @param string $clientIp * @param string $pattern * @return bool */ private static function matchWildcard(string $clientIp, string $pattern): bool { $pattern = str_replace('.', '\.', $pattern); $pattern = str_replace('*', '[0-9]+', $pattern); $pattern = '/^' . $pattern . '$/'; return preg_match($pattern, $clientIp) === 1; } /** * 验证IP白名单格式 * * @param string $whiteListIp * @return array [bool $isValid, string $message, array $parsedList] */ public static function validateWhiteListFormat(string $whiteListIp): array { if (empty($whiteListIp)) { return [true, '白名单为空,表示不限制IP访问', []]; } $items = self::parseWhiteListIp($whiteListIp); $validItems = []; $errors = []; foreach ($items as $item) { $validation = self::validateSingleIpFormat($item); if ($validation['valid']) { $validItems[] = [ 'input' => $item, 'type' => $validation['type'], 'description' => $validation['description'] ]; } else { $errors[] = "'{$item}': " . $validation['message']; } } $isValid = empty($errors); $message = $isValid ? 'IP白名单格式正确' : 'IP白名单格式错误: ' . implode(', ', $errors); return [$isValid, $message, $validItems]; } /** * 验证单个IP配置格式 * * @param string $ipConfig * @return array */ private static function validateSingleIpFormat(string $ipConfig): array { // 精确IP if (filter_var($ipConfig, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return [ 'valid' => true, 'type' => 'exact', 'description' => "精确IP: {$ipConfig}" ]; } // CIDR格式 if (strpos($ipConfig, '/') !== false) { list($subnet, $mask) = explode('/', $ipConfig); if (filter_var($subnet, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && is_numeric($mask) && $mask >= 0 && $mask <= 32) { return [ 'valid' => true, 'type' => 'cidr', 'description' => "CIDR网段: {$ipConfig}" ]; } } // IP范围 if (strpos($ipConfig, '-') !== false) { list($startIp, $endIp) = explode('-', $ipConfig, 2); $startIp = trim($startIp); $endIp = trim($endIp); if (filter_var($startIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && filter_var($endIp, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return [ 'valid' => true, 'type' => 'range', 'description' => "IP范围: {$startIp} 到 {$endIp}" ]; } } // 通配符 if (strpos($ipConfig, '*') !== false) { $parts = explode('.', $ipConfig); if (count($parts) === 4) { $valid = true; foreach ($parts as $part) { if ($part !== '*' && (!is_numeric($part) || $part < 0 || $part > 255)) { $valid = false; break; } } if ($valid) { return [ 'valid' => true, 'type' => 'wildcard', 'description' => "通配符IP: {$ipConfig}" ]; } } } return [ 'valid' => false, 'message' => '不支持的IP格式' ]; } }