siip-available-ips/src/AdminRangeHelper.php
DANYDHSV 1b821410c1 git commit -m "feat: sistema de configuración avanzada de IPs administrativas por segmento (v1.5.0)
- Agregar editor visual de configuración avanzada con protección por contraseña
- Implementar rangos de IPs administrativas personalizados por segmento
- Crear AdminRangeHelper.php para procesamiento de JSON por segmento
- Agregar botón ⚙️ de acceso rápido al editor
- Implementar modal de autenticación con validación de contraseña
- Agregar fallback inteligente a rangos globales para segmentos no configurados

Configuración avanzada:
- 3 campos nuevos en manifest.json (checkbox, JSON textarea, password)
- Editor visual completo con formularios dinámicos
- Agregar/eliminar segmentos y rangos en tiempo real
- Tabla de segmentos configurados con acciones
- Validación de cambios sin guardar
- Mensaje de éxito al guardar configuración

Backend:
- AdminRangeHelper.php: getSegmentLimits(), isAdminIpCustom(), validateConfigJson()
- IpSearchService.php: soporte para rangos personalizados con fallback
- Handler POST para guardar configuración JSON

Frontend:
- ~250 líneas de JavaScript para gestión del editor
- CSS responsive con soporte para temas claro/oscuro
- Interfaz amigable para usuarios no técnicos

Lógica de fallback:
- Checkbox desactivado → rangos globales para todos
- Checkbox activado + segmento en JSON → rangos del JSON
- Checkbox activado + segmento NO en JSON → fallback a rangos globales

Archivos creados:
- src/AdminRangeHelper.php

Archivos modificados:
- manifest.json: 3 campos nuevos, versión 1.5.0
- src/IpSearchService.php: lógica de fallback
- public.php: editor completo, modal, JavaScript
- CHANGELOG.md: entrada v1.5.0
- README.md: documentación de nuevos campos"
2025-11-27 13:00:40 -06:00

131 lines
4.5 KiB
PHP

<?php
namespace SiipAvailableIps;
/**
* Helper class para manejar rangos de IPs administrativas personalizados por segmento
*/
class AdminRangeHelper
{
/**
* Obtiene los límites de IPs administrativas para un segmento específico
*
* @param string|int $segmentNumber Número del segmento (ej: 18 para 172.16.18.x)
* @param string $jsonData JSON con configuración de rangos
* @return array|null Array con límites o null si el segmento no existe
*/
public static function getSegmentLimits($segmentNumber, $jsonData)
{
if (empty($jsonData)) {
return null;
}
$data = json_decode($jsonData, true);
if (!isset($data['segmentos']) || !is_array($data['segmentos'])) {
return null;
}
foreach ($data['segmentos'] as $segmento) {
if ($segmento['segmento'] == $segmentNumber) {
// Última IP del bloque inicial
$ultimoInicial = 0;
if (isset($segmento['administrativas_iniciales']) && is_array($segmento['administrativas_iniciales'])) {
foreach ($segmento['administrativas_iniciales'] as $rango) {
if (isset($rango['hasta']) && $rango['hasta'] > $ultimoInicial) {
$ultimoInicial = $rango['hasta'];
}
}
}
// Primera IP del bloque final
$primerFinal = 999;
if (isset($segmento['administrativas_finales']) && is_array($segmento['administrativas_finales'])) {
foreach ($segmento['administrativas_finales'] as $rango) {
if (isset($rango['inicio']) && $rango['inicio'] < $primerFinal) {
$primerFinal = $rango['inicio'];
}
}
}
return [
'ultimo_inicial_reservado' => $ultimoInicial,
'primer_final_reservado' => $primerFinal,
'rangos_iniciales' => $segmento['administrativas_iniciales'] ?? [],
'rangos_finales' => $segmento['administrativas_finales'] ?? []
];
}
}
return null;
}
/**
* Verifica si una IP es administrativa según configuración JSON personalizada
*
* @param string $ip Dirección IP completa (ej: 172.16.18.45)
* @param string $jsonData JSON con configuración de rangos
* @return bool True si es IP administrativa
*/
public static function isAdminIpCustom($ip, $jsonData)
{
$parts = explode('.', $ip);
if (count($parts) !== 4) {
return false;
}
$segment = $parts[2];
$lastOctet = (int)$parts[3];
$limits = self::getSegmentLimits($segment, $jsonData);
if (!$limits) {
return false;
}
// Verificar rangos iniciales
if (isset($limits['rangos_iniciales']) && is_array($limits['rangos_iniciales'])) {
foreach ($limits['rangos_iniciales'] as $rango) {
if ($lastOctet >= $rango['inicio'] && $lastOctet <= $rango['hasta']) {
return true;
}
}
}
// Verificar rangos finales
if (isset($limits['rangos_finales']) && is_array($limits['rangos_finales'])) {
foreach ($limits['rangos_finales'] as $rango) {
if ($lastOctet >= $rango['inicio'] && $lastOctet <= $rango['hasta']) {
return true;
}
}
}
return false;
}
/**
* Valida el formato del JSON de configuración
*
* @param string $jsonData JSON a validar
* @return array Array con 'valid' (bool) y 'error' (string|null)
*/
public static function validateConfigJson($jsonData)
{
if (empty($jsonData)) {
return ['valid' => false, 'error' => 'JSON vacío'];
}
$data = json_decode($jsonData, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return ['valid' => false, 'error' => 'JSON inválido: ' . json_last_error_msg()];
}
if (!isset($data['segmentos']) || !is_array($data['segmentos'])) {
return ['valid' => false, 'error' => 'Falta el array "segmentos"'];
}
return ['valid' => true, 'error' => null];
}
}