fix(v1.5.0): Correcciones críticas en configuración avanzada de IPs

- Corregida inicialización de editorData que impedía cargar rangos personalizados
- Corregidos errores de escape JS que rompían botones de la interfaz
- Corregida clasificación frontend que ignoraba rangos específicos por segmento
- Agregado indicador visual de modo y logs de depuración
- Eliminada columna redundante en tabla de resultados

Resuelve problemas donde los rangos admin personalizados eran ignorados.
This commit is contained in:
DANYDHSV 2025-11-27 14:40:58 -06:00
parent 1b821410c1
commit 6a0e15447c
9 changed files with 4097 additions and 124 deletions

View File

@ -18,17 +18,32 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/).
- **Botón de Configuración Avanzada** (⚙️): Acceso rápido al editor desde la interfaz principal.
- **Modal de Autenticación**: Protección por contraseña para acceso al editor.
- **Fallback Inteligente**: Segmentos no configurados en JSON usan automáticamente rangos globales.
- **Indicador Visual de Modo**: Badge que muestra si está activo "Rangos Personalizados" o "Rangos Globales".
- **Logs de Depuración**: Mensajes detallados en consola para diagnosticar clasificación de IPs.
### 🔧 Mejorado
- **AdminRangeHelper.php**: Nueva clase helper para procesar configuración JSON por segmento.
- **IpSearchService.php**: Lógica mejorada con soporte para rangos personalizados y fallback.
- Configuración inyectada en constructor para consistencia
- Rangos dinámicos en lugar de hardcodeados
- Logs de depuración opcionales con `debugMode`
- **Validación de Cambios**: Advertencia al salir del editor con cambios sin guardar.
- **Tabla de Resultados**: Eliminada columna redundante "Tipo de IP" en escritorio, badge ahora aparece junto a la IP.
- **Inicialización de Datos**: `editorData` se carga correctamente al inicio para asegurar que los rangos personalizados se apliquen inmediatamente.
### 🐛 Corregido
- **Error de Escape de Strings**: Reemplazado `addslashes()` por `json_encode()` para variables PHP en JavaScript, evitando errores de sintaxis.
- **Guardado de Configuración**: Implementada escritura directa a `config.json` debido a limitaciones del SDK de UCRM.
- **Clasificación de IPs en Frontend**: Función `getIpType()` ahora respeta rangos personalizados por segmento, no solo globales.
- **Carga de Configuración Personalizada**: Corregido bug crítico donde `editorData` se inicializaba vacío y nunca se cargaba hasta abrir el editor, causando que los rangos personalizados fueran ignorados.
- **Comparación de Segmentos**: Mejorada robustez con conversión explícita a string y trim para evitar fallos por espacios o tipos de datos.
### 🎨 Interfaz
- Editor visual completo con formularios dinámicos
- Tabla de segmentos configurados
- Agregar/eliminar rangos en tiempo real
- Diseño responsive con soporte para temas claro/oscuro
- Valor por defecto de 254 para rangos finales (optimización UX)
## [1.4.0] - 2025-11-27

View File

@ -98,10 +98,12 @@ Después de instalar el plugin, configura los siguientes parámetros:
| **Inicio rango admin final** | Primera IP del rango administrativo final (default: 254) | Define el inicio del rango final de IPs administrativas |
| **Fin rango admin final** | Última IP del rango administrativo final (default: 254) | Define el fin del rango final de IPs administrativas |
| **Usar rangos personalizados por segmento** | Habilita configuración avanzada por segmento | Permite definir rangos específicos para cada segmento de red |
| **Configuración JSON de rangos** | JSON con rangos por segmento | Configuración detallada de rangos administrativos personalizados |
| **Contraseña de administrador** | Contraseña para editor avanzado | Protege el acceso al editor de configuración avanzada |
| **Debug Mode** | Modo de depuración | Habilita logs más detallados |
| **Enable debug logs** | Logs verbosos | Información adicional en logs |
| **Configuración JSON de rangos** | JSON con rangos por segmento | Configuración detallada de rangos administrativos personalizados (se gestiona desde el editor visual) |
| **Contraseña de administrador** | Contraseña para editor avanzado | Protege el acceso al editor de configuración avanzada (⚙️) |
| **Debug Mode** | Modo de depuración | Habilita logs detallados en consola del navegador para diagnóstico |
| **Enable debug logs** | Logs verbosos | Información adicional en logs del servidor |
> **💡 Tip**: Para configurar rangos personalizados por segmento, marca el checkbox "Usar rangos personalizados por segmento" y haz clic en el botón ⚙️ (Configuración Avanzada) en la interfaz principal. Necesitarás la contraseña de administrador configurada.
### Cómo obtener los tokens:
@ -178,6 +180,31 @@ Durante la verificación por ping, aparece un botón **"🛑 Cancelar Verificaci
3. Las IPs ya verificadas permanecen en la tabla.
4. El botón desaparece al finalizar o cancelar.
### ⚙️ Configuración Avanzada de Rangos por Segmento
A partir de la versión 1.5.0, puedes definir rangos de IPs administrativas específicos para cada segmento de red.
**Acceso:**
1. Marca el checkbox **"Usar rangos personalizados por segmento"** en la configuración del plugin
2. Configura una **"Contraseña de administrador"** en la configuración del plugin
3. Haz clic en el botón **⚙️** (Configuración Avanzada) en la esquina superior derecha de la interfaz principal
4. Ingresa la contraseña configurada
**Características del Editor:**
- **Interfaz visual**: No necesitas editar JSON manualmente
- **Múltiples rangos**: Define varios rangos iniciales y finales por segmento
- **Validación automática**: El sistema valida que los rangos sean correctos
- **Indicador de modo**: Badge visual que muestra si los rangos personalizados están activos
**Ejemplo de Configuración:**
- **Segmento 13**: IPs administrativas del 2 al 60 y del 253 al 255
- **Segmento 15**: IPs administrativas del 2 al 30 y del 253 al 255
- **Segmento 18**: IPs administrativas del 1 al 50 y del 253 al 255
- **Otros segmentos**: Usan los rangos globales configurados
**Fallback Inteligente:**
Los segmentos no configurados en el editor avanzado usarán automáticamente los rangos globales definidos en la configuración básica del plugin.
---
## 🔌 API REST

View File

@ -1 +1 @@
{"ipserver":"sistema.siip.mx","apitoken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","unmsApiToken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","debugMode":true,"logging_level":true,"enablePingVerification":true,"adminRangeStart":"2","adminRangeEnd":"50","adminRangeFinalStart":"254","adminRangeFinalEnd":"255"}
{"ipserver":"sistema.siip.mx","apitoken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","unmsApiToken":"393eb3d0-9b46-4a47-b9b4-473e4e24a89c","debugMode":true,"logging_level":true,"enablePingVerification":true,"adminRangeStart":"2","adminRangeEnd":"50","adminRangeFinalStart":"254","adminRangeFinalEnd":"255","useCustomAdminRanges":true,"customAdminRangesJson":"{\"segmentos\":[{\"segmento\":\"13\",\"administrativas_iniciales\":[{\"inicio\":2,\"hasta\":50}],\"administrativas_finales\":[{\"inicio\":253,\"hasta\":254}]}]}","adminPassword":"Siip.2963"}

File diff suppressed because it is too large Load Diff

View File

@ -35,9 +35,70 @@
"key": "unmsApiToken",
"label": "Token de la API UNMS",
"description": "Token de autenticación necesario para el uso de la API del sistema UISP UNMS, se utiliza para gestionar información de antenas u otros dispositivos de red. Contiene 34 caracteres y se genera desde el módulo de Ajustes del UISP Network en la opción de 'Usuarios' y en apartado de 'API tokens'.",
"required": 0,
"required": 1,
"type": "text"
},
{
"key": "enablePingVerification",
"label": "Habilitar verificación por Ping",
"description": "Permite verificar la disponibilidad real de las IPs mediante ping. Cuando está habilitado, el usuario puede elegir si desea verificar las IPs con ping antes de mostrarlas como disponibles. Esto ayuda a detectar dispositivos no registrados en UISP.",
"required": 0,
"type": "checkbox"
},
{
"key": "adminRangeStart",
"label": "Inicio primer rango admin",
"description": "Primera IP del rango administrativo inicial (ej: 1). Las IPs en este rango se marcarán como administrativas.",
"required": 1,
"type": "number",
"default": 1
},
{
"key": "adminRangeEnd",
"label": "Fin primer rango admin",
"description": "Última IP del rango administrativo inicial (ej: 30). Las IPs desde 'Inicio primer rango' hasta este valor se marcarán como administrativas.",
"required": 1,
"type": "number",
"default": 30
},
{
"key": "adminRangeFinalStart",
"label": "Inicio rango admin final",
"description": "Primera IP del rango administrativo final (ej: 254). Útil para reservar las últimas IPs del segmento.",
"required": 1,
"type": "number",
"default": 2541
},
{
"key": "adminRangeFinalEnd",
"label": "Fin rango admin final",
"description": "Última IP del rango administrativo final (ej: 254). Las IPs desde 'Inicio rango final' hasta este valor se marcarán como administrativas.",
"required": 1,
"type": "number",
"default": 254
},
{
"key": "useCustomAdminRanges",
"label": "Usar rangos de IPs administrativas personalizados por segmento",
"description": "Habilita configuración personalizada por segmento en lugar de rangos globales. Permite definir rangos específicos para cada segmento de red.",
"required": 0,
"type": "checkbox"
},
{
"key": "customAdminRangesJson",
"label": "Configuración JSON de rangos administrativos",
"description": "JSON con rangos administrativos por segmento (Utilizar interfaz de configuración avanzada para editar). Formato: {\"segmentos\": [{\"segmento\": \"18\", \"administrativas_iniciales\": [{\"inicio\": 1, \"hasta\": 50}], \"administrativas_finales\": [{\"inicio\": 253, \"hasta\": 255}]}]}",
"required": 1,
"type": "textarea",
"default": "{\"segmentos\":[]}"
},
{
"key": "adminPassword",
"label": "Contraseña de administrador para configuración avanzada",
"description": "Contraseña requerida para acceder al editor visual de configuración avanzada de rangos administrativos.",
"required": 1,
"type": "password"
},
{
"key": "debugMode",
"label": "Debug Mode?",
@ -51,67 +112,6 @@
"description": "Make the plugin more verbose - Hace el plugin mas verboso.",
"type": "checkbox",
"required": 0
},
{
"key": "enablePingVerification",
"label": "Habilitar verificación por Ping",
"description": "Permite verificar la disponibilidad real de las IPs mediante ping. Cuando está habilitado, el usuario puede elegir si desea verificar las IPs con ping antes de mostrarlas como disponibles. Esto ayuda a detectar dispositivos no registrados en UISP.",
"required": 0,
"type": "checkbox"
},
{
"key": "adminRangeStart",
"label": "Inicio primer rango admin",
"description": "Primera IP del rango administrativo inicial (ej: 1). Las IPs en este rango se marcarán como administrativas.",
"required": 0,
"type": "number",
"default": 1
},
{
"key": "adminRangeEnd",
"label": "Fin primer rango admin",
"description": "Última IP del rango administrativo inicial (ej: 30). Las IPs desde 'Inicio primer rango' hasta este valor se marcarán como administrativas.",
"required": 0,
"type": "number",
"default": 30
},
{
"key": "adminRangeFinalStart",
"label": "Inicio rango admin final",
"description": "Primera IP del rango administrativo final (ej: 254). Útil para reservar las últimas IPs del segmento.",
"required": 0,
"type": "number",
"default": 254
},
{
"key": "adminRangeFinalEnd",
"label": "Fin rango admin final",
"description": "Última IP del rango administrativo final (ej: 254). Las IPs desde 'Inicio rango final' hasta este valor se marcarán como administrativas.",
"required": 0,
"type": "number",
"default": 254
},
{
"key": "useCustomAdminRanges",
"label": "Usar rangos de IPs administrativas personalizados por segmento",
"description": "Habilita configuración personalizada por segmento en lugar de rangos globales. Permite definir rangos específicos para cada segmento de red.",
"required": 0,
"type": "checkbox"
},
{
"key": "customAdminRangesJson",
"label": "Configuración JSON de rangos administrativos",
"description": "JSON con rangos administrativos por segmento. Formato: {\"segmentos\": [{\"segmento\": \"18\", \"administrativas_iniciales\": [{\"inicio\": 1, \"hasta\": 50}], \"administrativas_finales\": [{\"inicio\": 253, \"hasta\": 255}]}]}",
"required": 1,
"type": "textarea",
"default": "{\"segmentos\":[]}"
},
{
"key": "adminPassword",
"label": "Contraseña de administrador para configuración avanzada",
"description": "Contraseña requerida para acceder al editor visual de configuración avanzada de rangos administrativos.",
"required": 1,
"type": "password"
}
],
"menu": [

View File

@ -53,11 +53,23 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_advanced_config'
die('Error: ' . $validation['error']);
}
// Guardar en config.json
$configManager = PluginConfigManager::create();
$config = $configManager->loadConfig();
// Guardar en config.json directamente (el SDK no tiene método save)
$configFile = __DIR__ . '/data/config.json';
if (!file_exists($configFile)) {
// Si no existe, intentar crearlo con estructura básica
$config = [];
} else {
$config = json_decode(file_get_contents($configFile), true);
if (!is_array($config)) {
$config = [];
}
}
$config['customAdminRangesJson'] = $jsonData;
$configManager->saveConfig($config);
if (file_put_contents($configFile, json_encode($config, JSON_PRETTY_PRINT)) === false) {
throw new Exception("No se pudo escribir en el archivo de configuración: $configFile");
}
// Redirigir con mensaje de éxito
header('Location: ?success=1');
@ -608,6 +620,12 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
color: #2095fbff;
}
.ip-cell-mobile {
display: flex;
align-items: center;
gap: 12px;
}
.btn-copy {
padding: 8px 16px;
background: rgba(102, 126, 234, 0.2);
@ -720,19 +738,17 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
font-size: 0.8rem;
}
/* Ocultar columnas # y Tipo de IP en móvil */
/* Ocultar columnas # en móvil */
th:first-child,
td:first-child,
th:nth-child(3),
td:nth-child(3) {
td:first-child {
display: none;
}
/* Contenedor de IP con badge debajo */
.ip-cell-mobile {
display: flex;
flex-direction: column;
gap: 6px;
align-items: flex-start;
}
.ip-address {
@ -1135,7 +1151,7 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
<div class="range-input-group">
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
<span>hasta</span>
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" />
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" value="254" />
<button class="btn-small" onclick="addFinalRange()">+ Agregar Rango</button>
</div>
</div>
@ -1265,7 +1281,6 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
<tr>
<th>#</th>
<th>Dirección IP</th>
<th>Tipo de IP</th>
<th>Estado</th>
<th>Acción</th>
</tr>
@ -1290,8 +1305,30 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
finalStart: <?php echo isset($config['adminRangeFinalStart']) ? (int)$config['adminRangeFinalStart'] : 254; ?>,
finalEnd: <?php echo isset($config['adminRangeFinalEnd']) ? (int)$config['adminRangeFinalEnd'] : 254; ?>
};
console.log('PHP Config Debug:', <?php echo json_encode($config); ?>);
const useCustomRanges = <?php echo !empty($config['useCustomAdminRanges']) ? 'true' : 'false'; ?>;
const searchForm = document.getElementById('searchForm');
// Mostrar indicador de modo
const header = document.querySelector('.header');
const modeBadge = document.createElement('div');
modeBadge.className = useCustomRanges ? 'mode-badge custom' : 'mode-badge global';
modeBadge.innerHTML = useCustomRanges ? '✨ Modo: Rangos Personalizados' : '🌐 Modo: Rangos Globales';
modeBadge.style.cssText = `
display: inline-block;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.8rem;
margin-top: 10px;
background: ${useCustomRanges ? 'rgba(102, 126, 234, 0.2)' : 'rgba(255, 255, 255, 0.1)'};
color: ${useCustomRanges ? '#667eea' : '#a0aec0'};
border: 1px solid ${useCustomRanges ? 'rgba(102, 126, 234, 0.3)' : 'rgba(255, 255, 255, 0.2)'};
`;
header.appendChild(modeBadge);
const searchBtn = document.getElementById('searchBtn');
const loading = document.getElementById('loading');
const results = document.getElementById('results');
@ -1306,43 +1343,56 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
// ========== ADVANCED CONFIGURATION EDITOR ==========
// Variables del editor
let editorData = { segmentos: [] };
// Inicializar editorData con los rangos personalizados
let editorData;
const customRangesJson = <?php echo json_encode($config['customAdminRangesJson'] ?? '{"segmentos":[]}'); ?>;
try {
editorData = JSON.parse(customRangesJson);
if (!editorData.segmentos) {
editorData = { segmentos: [] };
}
console.log('editorData cargado al inicio:', editorData);
} catch (e) {
console.error('Error loading initial editorData:', e);
editorData = { segmentos: [] };
}
let hasUnsavedChanges = false;
const adminPassword = '<?php echo addslashes($config['adminPassword'] ?? ''); ?>';
const customRangesJson = '<?php echo addslashes($config['customAdminRangesJson'] ?? '{"segmentos":[]}'); ?>';
const adminPassword = <?php echo json_encode($config['adminPassword'] ?? ''); ?>;
// Event listener para botón de configuración avanzada
document.getElementById('advancedConfigBtn').addEventListener('click', openAdvancedConfig);
function openAdvancedConfig() {
document.getElementById('passwordModal').style.display = 'flex';
document.getElementById('adminPasswordInput').value = '';
document.getElementById('adminPasswordInput').focus();
}
function closePasswordModal() {
document.getElementById('passwordModal').style.display = 'none';
}
function validatePassword() {
const inputPassword = document.getElementById('adminPasswordInput').value;
if (inputPassword === adminPassword) {
closePasswordModal();
showEditor();
} else {
alert('❌ Contraseña incorrecta');
document.getElementById('passwordModal').style.display = 'flex';
document.getElementById('adminPasswordInput').value = '';
document.getElementById('adminPasswordInput').focus();
}
}
// Permitir Enter en el campo de contraseña
document.getElementById('adminPasswordInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
validatePassword();
function closePasswordModal() {
document.getElementById('passwordModal').style.display = 'none';
}
});
function validatePassword() {
const inputPassword = document.getElementById('adminPasswordInput').value;
if (inputPassword === adminPassword) {
closePasswordModal();
showEditor();
} else {
alert('❌ Contraseña incorrecta');
document.getElementById('adminPasswordInput').value = '';
document.getElementById('adminPasswordInput').focus();
}
}
// Permitir Enter en el campo de contraseña
document.getElementById('adminPasswordInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
validatePassword();
}
});
function showEditor() {
document.querySelector('.container').style.display = 'none';
@ -1431,7 +1481,7 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
newRange.innerHTML = `
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
<span>hasta</span>
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" />
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" value="255" />
<button class="btn-small" onclick="this.parentElement.remove()" style="background: rgba(245, 87, 108, 0.2); color: #ff6b6b;">
Quitar
</button>
@ -1503,7 +1553,7 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
<div class="range-input-group">
<input type="number" class="range-start" placeholder="Desde" min="1" max="254" />
<span>hasta</span>
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" />
<input type="number" class="range-end" placeholder="Hasta" min="1" max="254" value="255" />
<button class="btn-small" onclick="addFinalRange()">+ Agregar Rango</button>
</div>
`;
@ -1745,11 +1795,6 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
</span>
</div>
</td>
<td>
<span class="ip-type-badge ip-type-${ipTypeLabel === 'Administración' ? 'admin' : 'client'}">
${ipTypeLabel}
</span>
</td>
<td id="status-${ip.replace(/\./g, '-')}">
<span class="status-badge status-${statusClass}">${statusText}</span>
</td>
@ -1779,15 +1824,79 @@ $pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePing
// Función para clasificar el tipo de IP
function getIpType(ip) {
const lastOctet = parseInt(ip.split('.')[3]);
const parts = ip.split('.');
if (parts.length !== 4) return 'Cliente';
// Verificar si está en alguno de los rangos administrativos configurados
const segment = parts[2];
const lastOctet = parseInt(parts[3]);
// 1. Verificar rangos personalizados si existen
// Asegurarse de que editorData esté cargado
if (typeof editorData === 'undefined' || !editorData.segmentos) {
try {
if (typeof customRangesJson !== 'undefined') {
console.log('customRangesJson type:', typeof customRangesJson);
console.log('customRangesJson value:', customRangesJson);
editorData = JSON.parse(customRangesJson);
console.log('Parsed editorData:', editorData);
console.log('editorData.segmentos:', editorData.segmentos);
} else {
console.warn('customRangesJson is undefined');
editorData = { segmentos: [] };
}
} catch(e) {
console.error('Error parsing JSON in getIpType:', e);
console.error('Failed to parse:', customRangesJson);
editorData = { segmentos: [] };
}
}
// Buscar segmento actual en configuración personalizada
// Convertir ambos a string y limpiar espacios para asegurar coincidencia
const searchSeg = segment.toString().trim();
const customSegment = editorData.segmentos.find(s => s.segmento.toString().trim() === searchSeg);
if (useCustomRanges && customSegment) {
// Verificar rangos iniciales personalizados
if (customSegment.administrativas_iniciales) {
for (const rango of customSegment.administrativas_iniciales) {
if (lastOctet >= rango.inicio && lastOctet <= rango.hasta) {
console.log(`IP ${ip} es Admin (Custom Init: ${rango.inicio}-${rango.hasta})`);
return 'Administración';
}
}
}
// Verificar rangos finales personalizados
if (customSegment.administrativas_finales) {
for (const rango of customSegment.administrativas_finales) {
if (lastOctet >= rango.inicio && lastOctet <= rango.hasta) {
console.log(`IP ${ip} es Admin (Custom Final: ${rango.inicio}-${rango.hasta})`);
return 'Administración';
}
}
}
// Si hay configuración personalizada para este segmento y no cayó en los rangos admin, es Cliente
console.log(`IP ${ip} es Cliente (Custom Segment Found but not in ranges)`);
return 'Cliente';
} else if (useCustomRanges) {
console.log(`IP ${ip}: Segmento '${searchSeg}' no encontrado en custom ranges.`);
if (editorData.segmentos) {
console.log('Segmentos disponibles:', editorData.segmentos.map(s => `'${s.segmento}'`));
} else {
console.log('editorData.segmentos es undefined o null');
}
}
// 2. Fallback a configuración global si no hay segmento personalizado
// Verificar si está en alguno de los rangos administrativos configurados globalmente
if ((lastOctet >= adminConfig.rangeStart && lastOctet <= adminConfig.rangeEnd) ||
(lastOctet >= adminConfig.finalStart && lastOctet <= adminConfig.finalEnd)) {
return 'Administración';
}
return 'Válida para cliente';
return 'Cliente';
}
async function runProgressiveVerification(clientIps, limit) {

View File

@ -97,7 +97,7 @@ function handleIpRequest($data, $log) {
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true";
$apiToken = $config['unmsApiToken'];
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log);
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log, $config);
$resultado = $ipService->buscarIpsDisponibles($segment, $verifyPing, $pingLimit);
// Formatear respuesta para API

View File

@ -7,12 +7,14 @@ class IpSearchService
private $apiUrl;
private $apiToken;
private $logger;
private $config;
public function __construct($apiUrl, $apiToken, $logger = null)
public function __construct($apiUrl, $apiToken, $logger = null, $config = [])
{
$this->apiUrl = $apiUrl;
$this->apiToken = $apiToken;
$this->logger = $logger;
$this->config = $config;
}
/**
@ -34,10 +36,19 @@ class IpSearchService
// Si el segmento está configurado en JSON, usar esos rangos
if ($limits !== null) {
return AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
$isCustom = AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
// Log para depuración (temporal)
if (isset($config['debugMode']) && $config['debugMode']) {
error_log("Check Custom IP $ip (Seg $segment): " . ($isCustom ? 'ADMIN' : 'CLIENT'));
}
return $isCustom;
}
// Si el segmento NO está en JSON, usar rangos globales como fallback
}
} else {
if (isset($config['debugMode']) && $config['debugMode']) {
error_log("Custom ranges disabled or empty JSON. Config: " . print_r($config, true));
}
}
// Usar configuración estándar (rangos globales)
@ -174,11 +185,8 @@ class IpSearchService
$clientIps = [];
foreach ($ipsDisponibles as $ip) {
$parts = explode('.', $ip);
$lastOctet = intval(end($parts));
// IPs administrativas: 1-30 y 254
if (($lastOctet >= 1 && $lastOctet <= 30) || $lastOctet === 254) {
// Usar función dinámica para verificar si es administrativa
if (self::isAdminIp($ip, $this->config)) {
$adminIps[] = $ip;
} else {
$clientIps[] = $ip;

55
test_debug.php Normal file
View File

@ -0,0 +1,55 @@
<?php
require_once __DIR__ . '/src/AdminRangeHelper.php';
use SiipAvailableIps\AdminRangeHelper;
// Datos simulados del config.json
$config = [
'useCustomAdminRanges' => true,
'customAdminRangesJson' => '{"segmentos":[{"segmento":"18","administrativas_iniciales":[{"inicio":1,"hasta":50}],"administrativas_finales":[{"inicio":253,"hasta":255}]},{"segmento":"15","administrativas_iniciales":[{"inicio":2,"hasta":30}],"administrativas_finales":[{"inicio":253,"hasta":255}]},{"segmento":"13","administrativas_iniciales":[{"inicio":2,"hasta":60}],"administrativas_finales":[{"inicio":253,"hasta":255}]}]}'
];
$ip = "172.16.13.52";
echo "Probando IP: $ip\n";
echo "Config JSON: " . $config['customAdminRangesJson'] . "\n";
$parts = explode('.', $ip);
$segment = $parts[2];
echo "Segmento extraído: $segment\n";
$limits = AdminRangeHelper::getSegmentLimits($segment, $config['customAdminRangesJson']);
if ($limits) {
echo "Límites encontrados para segmento $segment:\n";
print_r($limits);
} else {
echo "NO se encontraron límites para segmento $segment\n";
}
$isAdmin = AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
echo "Es Admin IP (Custom)? " . ($isAdmin ? "SI" : "NO") . "\n";
// Prueba de la lógica completa de IpSearchService (simulada)
function isAdminIp($ip, $config) {
if (!empty($config['useCustomAdminRanges']) && !empty($config['customAdminRangesJson'])) {
$parts = explode('.', $ip);
if (count($parts) === 4) {
$segment = $parts[2];
$limits = AdminRangeHelper::getSegmentLimits($segment, $config['customAdminRangesJson']);
if ($limits !== null) {
echo "[DEBUG] Usando rangos custom para segmento $segment\n";
return AdminRangeHelper::isAdminIpCustom($ip, $config['customAdminRangesJson']);
} else {
echo "[DEBUG] Fallback a rangos globales para segmento $segment\n";
}
}
}
return false; // Simplificado
}
$result = isAdminIp($ip, $config);
echo "Resultado final isAdminIp: " . ($result ? "TRUE" : "FALSE") . "\n";