Característica: verificación de ping progresiva y asincrónica con procesamiento por lotes y agregar opciones de UI para límites de ping y ocultar IP's de administrador.
This commit is contained in:
parent
8549bab24b
commit
48024291c4
27
CHANGELOG.md
27
CHANGELOG.md
@ -7,6 +7,33 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/).
|
||||
|
||||
---
|
||||
|
||||
## [1.3.0] - 2025-11-26
|
||||
|
||||
### ✨ Añadido
|
||||
- **Carga Progresiva**: Los resultados de la búsqueda aparecen inmediatamente y la verificación por ping se realiza en segundo plano, actualizando el estado en tiempo real.
|
||||
- **Feedback Visual Mejorado**: Nuevos iconos de estado (⏳ Verificando, ✅ Disponible, ⚠️ En uso) en la tabla de resultados.
|
||||
- **Filtro de IPs Administrativas**: Nuevo checkbox para ocultar/mostrar IPs de administración (1-30, 254) al instante.
|
||||
|
||||
### 🔄 Mejorado
|
||||
- **Rendimiento**: La interfaz ya no se bloquea durante la verificación por ping.
|
||||
- **Experiencia de Usuario**: Se puede ver el progreso de la verificación IP por IP.
|
||||
|
||||
---
|
||||
|
||||
## [1.2.1] - 2025-11-26
|
||||
|
||||
### ✨ Añadido
|
||||
- **Límite de IPs para verificación**: Nuevo selector para limitar la cantidad de IPs a verificar con ping (5, 10, 20 o Todas)
|
||||
- Evita timeouts en segmentos grandes
|
||||
- Prioriza IPs de cliente (las administrativas se muestran sin verificar cuando hay límite)
|
||||
- **Defaults mejorados**: Checkbox de verificación activado por defecto (si está habilitado en config)
|
||||
|
||||
### 🔄 Mejorado
|
||||
- **Optimización de verificación**: Al usar un límite, las IPs administrativas se excluyen del ping para acelerar el proceso
|
||||
- **Interfaz de usuario**: Feedback visual más claro sobre el límite aplicado
|
||||
|
||||
---
|
||||
|
||||
## [1.2.0] - 2025-11-26
|
||||
|
||||
### ✨ Añadido
|
||||
|
||||
41
README.md
41
README.md
@ -1,6 +1,6 @@
|
||||
# SIIP - Buscador de IP's Disponibles UISP
|
||||
|
||||
[](manifest.json)
|
||||
[](manifest.json)
|
||||
[](https://uisp.com/)
|
||||
[](https://uisp.com/)
|
||||
|
||||
@ -142,17 +142,19 @@ La interfaz incluye:
|
||||
|
||||
### Verificación por Ping (Opcional)
|
||||
|
||||
Si está habilitada en la configuración, aparecerá un checkbox "🔍 Verificar con ping" en el formulario.
|
||||
Si está habilitada en la configuración, aparecerá un checkbox "🔍 Verificar con ping" (marcado por defecto) y un selector de límite.
|
||||
|
||||
**¿Qué hace?**
|
||||
- Verifica que las IPs reportadas como disponibles realmente no respondan a ping
|
||||
- Detecta dispositivos no registrados en UISP (computadoras, impresoras, cámaras, etc.)
|
||||
- Filtra automáticamente IPs que responden (posibles conflictos)
|
||||
**Opciones de Límite:**
|
||||
- **Todas (Lento)**: Verifica todas las IPs del segmento.
|
||||
- **5, 10, 20 IPs (Rápido)**: Verifica solo las primeras N IPs disponibles para clientes.
|
||||
|
||||
**¿Cuándo usarlo?**
|
||||
- ✅ Antes de asignar IPs a clientes nuevos (máxima seguridad)
|
||||
- ✅ En redes con dispositivos no gestionados
|
||||
- ❌ Para búsquedas rápidas donde no importa la verificación
|
||||
**Feedback Visual:**
|
||||
- ⏳ **Pendiente/Verificando**: La IP está siendo analizada.
|
||||
- ✅ **Disponible**: La IP está libre en UISP y no responde a ping.
|
||||
- ⚠️ **En uso (Ping)**: La IP está libre en UISP pero responde a ping (posible conflicto).
|
||||
|
||||
### Filtrado de IPs
|
||||
- **Ocultar Admin IPs**: Checkbox para ocultar/mostrar instantáneamente las IPs reservadas para administración (x.x.x.1-30 y x.x.x.254).
|
||||
|
||||
---
|
||||
|
||||
@ -213,13 +215,15 @@ Busca todas las IPs disponibles en un segmento de red específico.
|
||||
- `type` (string, requerido): Tipo de evento, debe ser `"event.ip_request"`
|
||||
- `segment` (string, requerido): Tercer octeto del segmento (0-255)
|
||||
- `verify_ping` (boolean, opcional): Si es `true`, verifica IPs con ping antes de reportarlas
|
||||
- `ping_limit` (int, opcional): Cantidad máxima de IPs a verificar (0 = todas, default: 0)
|
||||
|
||||
**Ejemplo con verificación por ping**:
|
||||
**Ejemplo con límite**:
|
||||
```json
|
||||
{
|
||||
"type": "event.ip_request",
|
||||
"segment": "5",
|
||||
"verify_ping": true
|
||||
"verify_ping": true,
|
||||
"ping_limit": 5
|
||||
}
|
||||
```
|
||||
|
||||
@ -235,12 +239,13 @@ Busca todas las IPs disponibles en un segmento de red específico.
|
||||
},
|
||||
"ping_verified": true,
|
||||
"ping_stats": {
|
||||
"total_checked": 223,
|
||||
"responding": 1,
|
||||
"not_responding": 222,
|
||||
"execution_time": "2.3s"
|
||||
"total_checked": 5,
|
||||
"responding": 0,
|
||||
"not_responding": 5,
|
||||
"execution_time": "0.8s",
|
||||
"limit_applied": 5
|
||||
},
|
||||
"ping_responding": ["172.16.5.50"]
|
||||
"ping_responding": []
|
||||
}
|
||||
```
|
||||
|
||||
@ -580,5 +585,5 @@ Este plugin es propiedad de **SIIP Internet**. Todos los derechos reservados.
|
||||
|
||||
---
|
||||
|
||||
**Versión**: 1.2.0
|
||||
**Versión**: 1.3.0
|
||||
**Última actualización**: 26 de noviembre de 2025
|
||||
|
||||
191
data/plugin.log
191
data/plugin.log
@ -379,3 +379,194 @@ IPs obtenidas exitosamente: 3105 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.100.x - Disponibles: 123, En uso: 131
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":123,"ipsEnUso":131}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: GET
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type:
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
Acceso a la interfaz pública de búsqueda de IPs
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"13"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary43e6452152194b7d2f9ee1cc1f4dcc5f
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
>>> Entrando al handler de búsqueda AJAX
|
||||
Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true}
|
||||
Buscando IPs en segmento: 13 (sin verificación por ping)
|
||||
URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Respuesta HTTP: 200
|
||||
Longitud de respuesta: 48906 bytes
|
||||
IPs obtenidas exitosamente: 3105 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 153, En uso: 101
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":153,"ipsEnUso":101}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: GET
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type:
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
Acceso a la interfaz pública de búsqueda de IPs
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"13","verify_ping":"true"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundarycaf9a5a4ec0cc39fcde382e2ad3254b5
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
>>> Entrando al handler de búsqueda AJAX
|
||||
Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true}
|
||||
Buscando IPs en segmento: 13 (con verificación por ping)
|
||||
URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Respuesta HTTP: 200
|
||||
Longitud de respuesta: 48906 bytes
|
||||
IPs obtenidas exitosamente: 3105 direcciones
|
||||
Verificación por ping habilitada, iniciando verificación...
|
||||
Iniciando verificación por ping de 153 IPs (lotes de 30)
|
||||
Procesando lote 1/6 (30 IPs)
|
||||
Lote completado: 1/30 IPs responden (29.20s)
|
||||
Procesando lote 2/6 (30 IPs)
|
||||
Lote completado: 1/30 IPs responden (29.35s)
|
||||
Procesando lote 3/6 (30 IPs)
|
||||
Lote completado: 0/30 IPs responden (30.20s)
|
||||
Procesando lote 4/6 (30 IPs)
|
||||
Lote completado: 1/30 IPs responden (29.23s)
|
||||
Procesando lote 5/6 (30 IPs)
|
||||
Lote completado: 0/30 IPs responden (30.19s)
|
||||
Procesando lote 6/6 (3 IPs)
|
||||
Lote completado: 0/3 IPs responden (3.11s)
|
||||
ADVERTENCIA: 3 IPs responden a ping pero no están en UISP: 172.16.13.45, 172.16.13.52, 172.16.13.188
|
||||
Verificación por ping completada: 153 IPs verificadas, 3 responden, 150 no responden (151.28s)
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 150, En uso: 101 (verificado con ping)
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":150,"ipsEnUso":101}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: GET
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type:
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
Acceso a la interfaz pública de búsqueda de IPs
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"13"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundarycb3b0d69f1f38554c073fe54b312e6d4
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
>>> Entrando al handler de búsqueda AJAX
|
||||
Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true}
|
||||
Buscando IPs en segmento: 13 (sin verificación por ping)
|
||||
URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Respuesta HTTP: 200
|
||||
Longitud de respuesta: 48906 bytes
|
||||
IPs obtenidas exitosamente: 3105 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 153, En uso: 101
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":153,"ipsEnUso":101}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"13","verify_ping":"true"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundaryb216276793b3e68fe84b13e1d74f9f09
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
>>> Entrando al handler de búsqueda AJAX
|
||||
Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true}
|
||||
Buscando IPs en segmento: 13 (con verificación por ping)
|
||||
URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Respuesta HTTP: 200
|
||||
Longitud de respuesta: 48906 bytes
|
||||
IPs obtenidas exitosamente: 3105 direcciones
|
||||
Verificación por ping habilitada, iniciando verificación...
|
||||
Iniciando verificación por ping de 153 IPs (lotes de 30)
|
||||
Procesando lote 1/6 (30 IPs)
|
||||
Lote completado: 1/30 IPs responden (29.21s)
|
||||
Procesando lote 2/6 (30 IPs)
|
||||
Lote completado: 1/30 IPs responden (29.23s)
|
||||
Procesando lote 3/6 (30 IPs)
|
||||
Lote completado: 0/30 IPs responden (30.20s)
|
||||
Procesando lote 4/6 (30 IPs)
|
||||
Lote completado: 1/30 IPs responden (29.20s)
|
||||
Procesando lote 5/6 (30 IPs)
|
||||
Lote completado: 0/30 IPs responden (30.20s)
|
||||
Procesando lote 6/6 (3 IPs)
|
||||
Lote completado: 0/3 IPs responden (3.11s)
|
||||
ADVERTENCIA: 3 IPs responden a ping pero no están en UISP: 172.16.13.45, 172.16.13.52, 172.16.13.188
|
||||
Verificación por ping completada: 153 IPs verificadas, 3 responden, 150 no responden (151.15s)
|
||||
Búsqueda de IPs en segmento 172.16.13.x - Disponibles: 150, En uso: 101 (verificado con ping)
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":150,"ipsEnUso":101}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: GET
|
||||
POST data: []
|
||||
GET data: []
|
||||
Content-Type:
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
Acceso a la interfaz pública de búsqueda de IPs
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"100","verify_ping":"true","ping_limit":"20"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary2463648a22fbfc0977c6f46af73a71c2
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
>>> Entrando al handler de búsqueda AJAX
|
||||
Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true}
|
||||
Buscando IPs en segmento: 100 (con verificación por ping, límite: 20 IPs)
|
||||
URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Respuesta HTTP: 200
|
||||
Longitud de respuesta: 48906 bytes
|
||||
IPs obtenidas exitosamente: 3105 direcciones
|
||||
Verificación por ping habilitada, iniciando verificación...
|
||||
Aplicando límite de ping: 20 IPs de cliente (Total disponibles: 105)
|
||||
Iniciando verificación por ping de 20 IPs (lotes de 30)
|
||||
Procesando lote 1/1 (20 IPs)
|
||||
Lote completado: 0/20 IPs responden (20.18s)
|
||||
Verificación por ping completada: 20 IPs verificadas, 0 responden, 20 no responden (20.18s)
|
||||
Búsqueda de IPs en segmento 172.16.100.x - Disponibles: 123, En uso: 131 (verificado con ping)
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":123,"ipsEnUso":131}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"100"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary5753dc1b36d69572108222d59aa55e38
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
>>> Entrando al handler de búsqueda AJAX
|
||||
Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true}
|
||||
Buscando IPs en segmento: 100 (sin verificación por ping)
|
||||
URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Respuesta HTTP: 200
|
||||
Longitud de respuesta: 48906 bytes
|
||||
IPs obtenidas exitosamente: 3105 direcciones
|
||||
Búsqueda de IPs en segmento 172.16.100.x - Disponibles: 123, En uso: 131
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":123,"ipsEnUso":131}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
=== NUEVA PETICIÓN ===
|
||||
Método: POST
|
||||
POST data: {"action":"search","segment":"100","verify_ping":"true","ping_limit":"5"}
|
||||
GET data: []
|
||||
Content-Type: multipart/form-data; boundary=----geckoformboundary3aee2ff80e73e922f743d236ac2c22c9
|
||||
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:145.0) Gecko/20100101 Firefox/145.0
|
||||
>>> Entrando al handler de búsqueda AJAX
|
||||
Configuración cargada: {"ipserver":"sistema.siip.mx","hasUnmsToken":true,"hasApiToken":true}
|
||||
Buscando IPs en segmento: 100 (con verificación por ping, límite: 5 IPs)
|
||||
URL de API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Iniciando conexión a API: https://sistema.siip.mx/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true
|
||||
Respuesta HTTP: 200
|
||||
Longitud de respuesta: 48906 bytes
|
||||
IPs obtenidas exitosamente: 3105 direcciones
|
||||
Verificación por ping habilitada, iniciando verificación...
|
||||
Aplicando límite de ping: 5 IPs de cliente (Total disponibles: 105)
|
||||
Iniciando verificación por ping de 5 IPs (lotes de 30)
|
||||
Procesando lote 1/1 (5 IPs)
|
||||
Lote completado: 0/5 IPs responden (5.14s)
|
||||
Verificación por ping completada: 5 IPs verificadas, 0 responden, 5 no responden (5.15s)
|
||||
Búsqueda de IPs en segmento 172.16.100.x - Disponibles: 123, En uso: 131 (verificado con ping)
|
||||
Resultado de búsqueda: {"success":true,"ipsDisponibles":123,"ipsEnUso":131}
|
||||
<<< Finalizando handler de búsqueda AJAX
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
"displayName": "SIIP - Buscador de IP's Disponibles UISP",
|
||||
"description": "Este plugin permite buscar IP's disponibles en UISP (UNMS) y asignarlas a los clientes en UCRM. Evitando así la asignación de IP's duplicadas y mejorando la gestión de direcciones IP en la red.",
|
||||
"url": "https://siip.mx",
|
||||
"version": "1.2.0",
|
||||
"version": "1.3.0",
|
||||
"ucrmVersionCompliancy": {
|
||||
"min": "1.0.0",
|
||||
"max": null
|
||||
|
||||
219
public.php
219
public.php
@ -4,6 +4,9 @@
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0); // No mostrar errores en HTML
|
||||
|
||||
// Aumentar tiempo de ejecución para verificación por ping (puede tardar varios minutos)
|
||||
set_time_limit(300); // 5 minutos
|
||||
|
||||
// Handler global de errores
|
||||
set_error_handler(function($errno, $errstr, $errfile, $errline) {
|
||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||
@ -114,13 +117,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
||||
}
|
||||
|
||||
$segmento = $_POST['segment'] ?? '';
|
||||
$verifyPing = isset($_POST['verify_ping']) && $_POST['verify_ping'] === 'true';
|
||||
// NOTA: Ignoramos verify_ping aquí porque ahora se hace progresivamente desde el frontend
|
||||
// Pero lo logueamos para saber la intención del usuario
|
||||
$verifyPingIntention = isset($_POST['verify_ping']) && $_POST['verify_ping'] === 'true';
|
||||
|
||||
if ($verifyPing) {
|
||||
$log->appendLog("Buscando IPs en segmento: $segmento (con verificación por ping)");
|
||||
} else {
|
||||
$log->appendLog("Buscando IPs en segmento: $segmento (sin verificación por ping)");
|
||||
}
|
||||
$log->appendLog("Buscando IPs en segmento: $segmento (Búsqueda inicial rápida)");
|
||||
|
||||
// URL de la API de UISP - Usar HTTPS
|
||||
|
||||
// URL de la API de UISP - Usar HTTPS
|
||||
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=false&management=true&includeObsolete=true";
|
||||
@ -128,9 +131,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
||||
|
||||
$log->appendLog("URL de API: $apiUrl");
|
||||
|
||||
// Crear instancia del servicio y buscar IPs
|
||||
// Crear instancia del servicio y buscar IPs (SIN ping, el ping se hace después)
|
||||
$ipService = new IpSearchService($apiUrl, $apiToken, $log);
|
||||
$resultado = $ipService->buscarIpsDisponibles($segmento, $verifyPing);
|
||||
$resultado = $ipService->buscarIpsDisponibles($segmento, false);
|
||||
|
||||
$log->appendLog('Resultado de búsqueda: ' . json_encode([
|
||||
'success' => $resultado['success'],
|
||||
@ -163,6 +166,51 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
||||
|
||||
$log->appendLog('<<< Finalizando handler de búsqueda AJAX');
|
||||
exit;
|
||||
} else if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'verify_batch') {
|
||||
$log->appendLog('>>> Entrando al handler de verificación por lotes (verify_batch)');
|
||||
|
||||
try {
|
||||
$ips = $_POST['ips'] ?? [];
|
||||
if (!is_array($ips)) {
|
||||
$ips = json_decode($ips, true);
|
||||
}
|
||||
|
||||
if (empty($ips)) {
|
||||
echo json_encode(['success' => true, 'results' => []]);
|
||||
exit;
|
||||
}
|
||||
|
||||
$log->appendLog('Verificando lote de ' . count($ips) . ' IPs');
|
||||
|
||||
// Crear instancia de PingService
|
||||
$pingService = new PingService($log, 1, count($ips));
|
||||
|
||||
if (!$pingService->isAvailable()) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Comando ping no disponible'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Hacer ping
|
||||
$pingResults = $pingService->pingMultipleIps($ips);
|
||||
$processed = $pingService->processPingResults($pingResults);
|
||||
|
||||
// Retornar resultados
|
||||
// responding = IPs que responden (ocupadas/conflicto)
|
||||
// not_responding = IPs que no responden (disponibles)
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'responding' => $processed['responding'],
|
||||
'not_responding' => $processed['not_responding']
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
$log->appendLog('ERROR en verify_batch: ' . $e->getMessage());
|
||||
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||
}
|
||||
exit;
|
||||
} else if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$log->appendLog('Petición POST recibida pero sin action=search o action no válida');
|
||||
$log->appendLog('Action recibida: ' . ($_POST['action'] ?? 'NO DEFINIDA'));
|
||||
@ -174,7 +222,7 @@ $log->appendLog('Acceso a la interfaz pública de búsqueda de IPs');
|
||||
// Cargar configuración para verificar si ping está habilitado
|
||||
$configManager = PluginConfigManager::create();
|
||||
$config = $configManager->loadConfig();
|
||||
$pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVerification'] === '1';
|
||||
$pingEnabled = !empty($config['enablePingVerification']) && ($config['enablePingVerification'] === true || $config['enablePingVerification'] === '1');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
@ -602,6 +650,43 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 6px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.status-verifying {
|
||||
background: rgba(102, 126, 234, 0.2);
|
||||
color: #667eea;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
.status-available {
|
||||
background: rgba(79, 209, 197, 0.2);
|
||||
color: #4fd1c5;
|
||||
border: 1px solid rgba(79, 209, 197, 0.4);
|
||||
}
|
||||
|
||||
.status-conflict {
|
||||
background: rgba(245, 87, 108, 0.2);
|
||||
color: #ff6b6b;
|
||||
border: 1px solid rgba(245, 87, 108, 0.4);
|
||||
}
|
||||
|
||||
tr.hidden-row {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -632,10 +717,25 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
<?php if ($pingEnabled): ?>
|
||||
<div class="input-group" style="flex: 0 0 auto; min-width: auto;">
|
||||
<label style="display: flex; align-items: center; gap: 10px; cursor: pointer; margin-bottom: 0; padding-top: 28px;">
|
||||
<input type="checkbox" id="verifyPing" name="verify_ping" style="width: auto; padding: 0; margin: 0;">
|
||||
<input type="checkbox" id="verifyPing" name="verify_ping" style="width: auto; padding: 0; margin: 0;" checked>
|
||||
<span style="color: var(--text-secondary); font-size: 0.9rem;">🔍 Verificar con ping</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="input-group" style="flex: 0 0 auto; min-width: auto;">
|
||||
<label style="display: flex; align-items: center; gap: 10px; cursor: pointer; margin-bottom: 0; padding-top: 28px;">
|
||||
<input type="checkbox" id="hideAdmin" name="hide_admin" style="width: auto; padding: 0; margin: 0;">
|
||||
<span style="color: var(--text-secondary); font-size: 0.9rem;">👁️ Ocultar Admin IPs</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="input-group" id="pingLimitContainer" style="flex: 0 0 auto; min-width: 150px;">
|
||||
<label for="pingLimit">Límite de IPs</label>
|
||||
<select id="pingLimit" name="ping_limit" style="width: 100%; padding: 16px; background: rgba(255, 255, 255, 0.05); border: 2px solid var(--card-border); border-radius: 12px; color: var(--text-primary); font-size: 1rem;">
|
||||
<option value="0">Todas (Lento)</option>
|
||||
<option value="5">5 IPs (Rápido)</option>
|
||||
<option value="10">10 IPs</option>
|
||||
<option value="20">20 IPs</option>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<button type="submit" class="btn btn-primary" id="searchBtn">
|
||||
<span>🔍</span>
|
||||
@ -645,7 +745,10 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
|
||||
<div class="loading" id="loading">
|
||||
<div class="spinner"></div>
|
||||
<p>Consultando IPs disponibles...</p>
|
||||
<p id="loadingMessage">Consultando IPs disponibles...</p>
|
||||
<p id="loadingPingWarning" style="display: none; color: var(--text-secondary); font-size: 0.9rem; margin-top: 10px;">
|
||||
⏱️ Verificación por ping habilitada. Esto puede tardar varios minutos...
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="errorContainer"></div>
|
||||
@ -673,6 +776,7 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
<th>#</th>
|
||||
<th>Dirección IP</th>
|
||||
<th>Tipo de IP</th>
|
||||
<th>Estado</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -699,6 +803,17 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
const usedCount = document.getElementById('usedCount');
|
||||
const segmentDisplay = document.getElementById('segmentDisplay');
|
||||
|
||||
// Toggle visibility of ping limit select
|
||||
<?php if ($pingEnabled): ?>
|
||||
const verifyPingCheckbox = document.getElementById('verifyPing');
|
||||
const pingLimitContainer = document.getElementById('pingLimitContainer');
|
||||
if (verifyPingCheckbox && pingLimitContainer) {
|
||||
verifyPingCheckbox.addEventListener('change', function() {
|
||||
pingLimitContainer.style.display = this.checked ? 'block' : 'none';
|
||||
});
|
||||
}
|
||||
<?php endif; ?>
|
||||
|
||||
searchForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@ -712,6 +827,14 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
}
|
||||
|
||||
// Mostrar loading
|
||||
<?php if ($pingEnabled): ?>
|
||||
const verifyPingCheckbox = document.getElementById('verifyPing');
|
||||
const loadingPingWarning = document.getElementById('loadingPingWarning');
|
||||
if (verifyPingCheckbox && verifyPingCheckbox.checked) {
|
||||
loadingPingWarning.style.display = 'block';
|
||||
}
|
||||
<?php endif; ?>
|
||||
|
||||
loading.classList.add('active');
|
||||
results.classList.remove('active');
|
||||
errorContainer.innerHTML = '';
|
||||
@ -723,13 +846,17 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
formData.append('segment', segment);
|
||||
|
||||
// Agregar verificación por ping si está habilitada y marcada
|
||||
<?php if ($pingEnabled): ?>
|
||||
const verifyPingCheckbox = document.getElementById('verifyPing');
|
||||
if (verifyPingCheckbox && verifyPingCheckbox.checked) {
|
||||
formData.append('verify_ping', 'true');
|
||||
console.log('Verificación por ping habilitada');
|
||||
}
|
||||
<?php endif; ?>
|
||||
<?php if ($pingEnabled): ?>
|
||||
const verifyPingCheckbox = document.getElementById('verifyPing');
|
||||
const pingLimitSelect = document.getElementById('pingLimit');
|
||||
const shouldVerifyPing = verifyPingCheckbox && verifyPingCheckbox.checked;
|
||||
const pingLimit = pingLimitSelect ? parseInt(pingLimitSelect.value) : 0;
|
||||
|
||||
// NOTA: Ya no enviamos verify_ping=true al backend para la búsqueda inicial
|
||||
// La verificación se hará progresivamente después de recibir la lista
|
||||
// Solo lo enviamos como 'false' para que el backend sepa que no debe verificar
|
||||
formData.append('verify_ping', 'false');
|
||||
<?php endif; ?>
|
||||
|
||||
console.log('Enviando petición AJAX...');
|
||||
console.log('Segmento:', segment);
|
||||
@ -755,15 +882,28 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
console.log('Datos recibidos:', data);
|
||||
|
||||
loading.classList.remove('active');
|
||||
<?php if ($pingEnabled): ?>
|
||||
loadingPingWarning.style.display = 'none';
|
||||
<?php endif; ?>
|
||||
searchBtn.disabled = false;
|
||||
|
||||
if (data.success) {
|
||||
displayResults(data);
|
||||
|
||||
// Iniciar verificación progresiva si corresponde
|
||||
<?php if ($pingEnabled): ?>
|
||||
if (shouldVerifyPing) {
|
||||
runProgressiveVerification(data.data, pingLimit);
|
||||
}
|
||||
<?php endif; ?>
|
||||
} else {
|
||||
showError(data.message || 'Error al buscar IPs disponibles');
|
||||
}
|
||||
} catch (error) {
|
||||
loading.classList.remove('active');
|
||||
<?php if ($pingEnabled): ?>
|
||||
loadingPingWarning.style.display = 'none'; // Ocultar advertencia
|
||||
<?php endif; ?>
|
||||
searchBtn.disabled = false;
|
||||
console.error('Error completo:', error);
|
||||
console.error('Tipo de error:', error.name);
|
||||
@ -789,17 +929,27 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
}
|
||||
|
||||
// Llenar tabla
|
||||
data.data.forEach((ip, index) => {
|
||||
const ipType = getIpType(ip);
|
||||
data.data.forEach((ipData, index) => {
|
||||
const ip = ipData.ip;
|
||||
const ipTypeLabel = getIpType(ip);
|
||||
const hideAdminCheckbox = document.getElementById('hideAdmin');
|
||||
const isHidden = hideAdminCheckbox && hideAdminCheckbox.checked && ipTypeLabel === 'Administración';
|
||||
const row = document.createElement('tr');
|
||||
row.id = `row-${ip.replace(/\./g, '-')}`;
|
||||
if (isHidden) row.classList.add('hidden-row');
|
||||
if (ipTypeLabel === 'Administración') row.classList.add('admin-row');
|
||||
|
||||
row.innerHTML = `
|
||||
<td>${index + 1}</td>
|
||||
<td><span class="ip-address">${ip}</span></td>
|
||||
<td>
|
||||
<span class="ip-type-badge ip-type-${ipType.type}">
|
||||
${ipType.label}
|
||||
<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-pending">Pendiente</span>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn-copy" onclick="copyToClipboard('${ip}', this)">
|
||||
📋 Copiar
|
||||
@ -816,22 +966,27 @@ $pingEnabled = isset($config['enablePingVerification']) && $config['enablePingVe
|
||||
showError(data.message, 'success');
|
||||
}
|
||||
|
||||
// Listener para el filtro de Admin IPs
|
||||
const hideAdminCheckbox = document.getElementById('hideAdmin');
|
||||
if (hideAdminCheckbox) {
|
||||
hideAdminCheckbox.addEventListener('change', function() {
|
||||
const adminRows = document.querySelectorAll('.admin-row');
|
||||
adminRows.forEach(row => {
|
||||
if (this.checked) {
|
||||
row.classList.add('hidden-row');
|
||||
} else {
|
||||
row.classList.remove('hidden-row');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Función para clasificar el tipo de IP
|
||||
function getIpType(ip) {
|
||||
const parts = ip.split('.');
|
||||
const lastOctet = parseInt(parts[3]);
|
||||
|
||||
// IPs administrativas: 1-30 y 254
|
||||
if ((lastOctet >= 1 && lastOctet <= 30) || lastOctet === 254) {
|
||||
return {
|
||||
type: 'admin',
|
||||
label: 'Administración',
|
||||
recommended: false
|
||||
};
|
||||
}
|
||||
|
||||
// IPs aptas para clientes: 31-253
|
||||
return {
|
||||
type: 'client',
|
||||
label: 'Apta para cliente',
|
||||
recommended: true
|
||||
|
||||
@ -71,9 +71,11 @@ function handleIpRequest($data, $log) {
|
||||
|
||||
$segment = $data['segment'];
|
||||
$verifyPing = isset($data['verify_ping']) && $data['verify_ping'] === true;
|
||||
$pingLimit = isset($data['ping_limit']) ? intval($data['ping_limit']) : 0;
|
||||
|
||||
if ($verifyPing) {
|
||||
$log->appendLog("API: Verificación por ping habilitada para segmento $segment");
|
||||
$limitMsg = $pingLimit > 0 ? "límite: $pingLimit IPs" : "sin límite";
|
||||
$log->appendLog("API: Verificación por ping habilitada para segmento $segment ($limitMsg)");
|
||||
} else {
|
||||
$log->appendLog("API: Buscando IPs en segmento $segment (sin verificación por ping)");
|
||||
}
|
||||
@ -96,7 +98,7 @@ function handleIpRequest($data, $log) {
|
||||
$apiToken = $config['unmsApiToken'];
|
||||
|
||||
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log);
|
||||
$resultado = $ipService->buscarIpsDisponibles($segment, $verifyPing);
|
||||
$resultado = $ipService->buscarIpsDisponibles($segment, $verifyPing, $pingLimit);
|
||||
|
||||
// Formatear respuesta para API
|
||||
if ($resultado['success']) {
|
||||
|
||||
@ -73,7 +73,15 @@ class IpSearchService
|
||||
* @param bool $verifyPing Si es true, verifica las IPs con ping antes de reportarlas como disponibles
|
||||
* @return array Array con 'success', 'data' (IPs disponibles), 'used' (IPs en uso), 'message', 'ping_verified', 'ping_stats'
|
||||
*/
|
||||
public function buscarIpsDisponibles($segmento, $verifyPing = false)
|
||||
/**
|
||||
* Busca IPs disponibles en un segmento
|
||||
*
|
||||
* @param string $segmento Tercer octeto de la IP (ej: 5 para 172.16.5.x)
|
||||
* @param bool $verifyPing Si es true, verifica disponibilidad con ping
|
||||
* @param int $pingLimit Límite de IPs a verificar (0 = todas)
|
||||
* @return array Resultado de la búsqueda
|
||||
*/
|
||||
public function buscarIpsDisponibles($segmento, $verifyPing = false, $pingLimit = 0)
|
||||
{
|
||||
try {
|
||||
// Validar el segmento
|
||||
@ -139,9 +147,45 @@ class IpSearchService
|
||||
$this->logger->appendLog('ADVERTENCIA: Comando ping no disponible, se omitirá verificación');
|
||||
}
|
||||
} else {
|
||||
// Hacer ping a las IPs "disponibles"
|
||||
// Preparar IPs para ping
|
||||
$ipsToPing = $ipsDisponibles;
|
||||
|
||||
// Si hay límite, filtrar IPs administrativas y limitar IPs de cliente
|
||||
if ($pingLimit > 0) {
|
||||
$adminIps = [];
|
||||
$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) {
|
||||
$adminIps[] = $ip;
|
||||
} else {
|
||||
$clientIps[] = $ip;
|
||||
}
|
||||
}
|
||||
|
||||
// Tomar solo las primeras N IPs de cliente
|
||||
$clientIpsToPing = array_slice($clientIps, 0, $pingLimit);
|
||||
|
||||
// IPs a verificar = IPs de cliente limitadas
|
||||
// (Las administrativas NO se verifican con ping en este modo para ahorrar tiempo)
|
||||
$ipsToPing = $clientIpsToPing;
|
||||
|
||||
if ($this->logger) {
|
||||
$this->logger->appendLog(sprintf(
|
||||
'Aplicando límite de ping: %d IPs de cliente (Total disponibles: %d)',
|
||||
count($ipsToPing),
|
||||
count($clientIps)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Hacer ping a las IPs seleccionadas
|
||||
$startTime = microtime(true);
|
||||
$pingResults = $pingService->pingMultipleIps($ipsDisponibles);
|
||||
$pingResults = $pingService->pingMultipleIps($ipsToPing);
|
||||
$executionTime = microtime(true) - $startTime;
|
||||
|
||||
// Procesar resultados
|
||||
@ -158,16 +202,37 @@ class IpSearchService
|
||||
));
|
||||
}
|
||||
|
||||
// Remover IPs que responden de la lista de disponibles
|
||||
$ipsDisponibles = array_values(array_diff($ipsDisponibles, $pingResponding));
|
||||
// Filtrar IPs que responden
|
||||
if ($pingLimit > 0) {
|
||||
// Si hay límite, reconstruimos la lista de disponibles:
|
||||
// Admin IPs (sin verificar) + Client IPs verificadas (que no respondieron)
|
||||
// Las Client IPs que excedieron el límite NO se incluyen en el resultado
|
||||
$clientIpsVerified = array_diff($clientIpsToPing, $pingResponding);
|
||||
$ipsDisponibles = array_merge($adminIps, $clientIpsVerified);
|
||||
|
||||
// Reordenar para mantener consistencia
|
||||
usort($ipsDisponibles, function($a, $b) {
|
||||
return intval(explode('.', $a)[3]) - intval(explode('.', $b)[3]);
|
||||
});
|
||||
} else {
|
||||
// Comportamiento normal: filtrar de la lista completa
|
||||
$ipsDisponibles = array_values(array_diff($ipsDisponibles, $pingResponding));
|
||||
}
|
||||
}
|
||||
|
||||
$pingVerified = true;
|
||||
|
||||
// Calcular estadísticas
|
||||
$totalChecked = count($ipsToPing);
|
||||
$respondingCount = count($pingResponding);
|
||||
$notRespondingCount = $totalChecked - $respondingCount;
|
||||
|
||||
$pingStats = [
|
||||
'total_checked' => $processed['stats']['total_checked'],
|
||||
'responding' => $processed['stats']['responding'],
|
||||
'not_responding' => $processed['stats']['not_responding'],
|
||||
'execution_time' => round($executionTime, 2) . 's'
|
||||
'total_checked' => $totalChecked,
|
||||
'responding' => $respondingCount,
|
||||
'not_responding' => $notRespondingCount,
|
||||
'execution_time' => number_format($executionTime, 2) . 's',
|
||||
'limit_applied' => $pingLimit > 0 ? $pingLimit : false
|
||||
];
|
||||
|
||||
if ($this->logger) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user