false, 'message' => 'Error fatal: ' . $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine() ]); exit; }); chdir(__DIR__); require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/src/IpSearchService.php'; require_once __DIR__ . '/src/PingService.php'; require_once __DIR__ . '/src/ApiHandlers.php'; require_once __DIR__ . '/src/AdminRangeHelper.php'; use Ubnt\UcrmPluginSdk\Service\PluginLogManager; use Ubnt\UcrmPluginSdk\Service\PluginConfigManager; use Ubnt\UcrmPluginSdk\Service\UcrmApi; use SiipAvailableIps\IpSearchService; use SiipAvailableIps\PingService; // Manejo de errores para el handler de configuración avanzada error_reporting(E_ALL); ini_set('display_errors', 1); // Handler para guardar configuración avanzada if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_advanced_config'])) { try { $jsonData = $_POST['save_advanced_config']; // Validar JSON $validation = \SiipAvailableIps\AdminRangeHelper::validateConfigJson($jsonData); if (!$validation['valid']) { die('Error: ' . $validation['error']); } // 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; 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'); exit; } catch (Exception $e) { die('Error al guardar configuración: ' . $e->getMessage()); } } // Get UCRM log manager $log = PluginLogManager::create(); // Log TODAS las peticiones $log->appendLog('=== NUEVA PETICIÓN ===' ); $log->appendLog('Método: ' . $_SERVER['REQUEST_METHOD']); $log->appendLog('POST data: ' . json_encode($_POST)); $log->appendLog('GET data: ' . json_encode($_GET)); $log->appendLog('Content-Type: ' . ($_SERVER['CONTENT_TYPE'] ?? 'no definido')); $log->appendLog('User Agent: ' . ($_SERVER['HTTP_USER_AGENT'] ?? 'no definido')); // ============================================================================ // API REST - Manejar peticiones JSON (Postman, Webhooks, etc.) // ============================================================================ $contentType = $_SERVER['CONTENT_TYPE'] ?? ''; $isJsonRequest = stripos($contentType, 'application/json') !== false; if ($isJsonRequest && $_SERVER['REQUEST_METHOD'] === 'POST') { $log->appendLog('>>> Petición API JSON detectada'); $rawInput = file_get_contents('php://input'); $log->appendLog('Raw input length: ' . strlen($rawInput) . ' bytes'); $jsonData = json_decode($rawInput, true); if (json_last_error() !== JSON_ERROR_NONE) { $log->appendLog('ERROR: JSON inválido - ' . json_last_error_msg()); header('Content-Type: application/json'); echo json_encode([ 'success' => false, 'error' => 'Invalid JSON', 'message' => json_last_error_msg() ]); exit; } $log->appendLog('JSON parseado correctamente: ' . json_encode($jsonData)); // Procesar petición API handleApiRequest($jsonData, $log); exit; } // ============================================================================ // FRONTEND HTML - Manejar peticiones AJAX del formulario // ============================================================================ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'search') { $log->appendLog('>>> Entrando al handler de búsqueda AJAX'); try { // Obtener configuración del plugin desde data/config.json $configManager = PluginConfigManager::create(); $config = $configManager->loadConfig(); $log->appendLog('Configuración cargada: ' . json_encode([ 'ipserver' => $config['ipserver'] ?? 'NO CONFIGURADO', 'hasUnmsToken' => !empty($config['unmsApiToken']), 'hasApiToken' => !empty($config['apitoken']) ])); // Validar que exista la configuración necesaria if (empty($config['ipserver'])) { $log->appendLog('ERROR: No se ha configurado ipserver'); header('Content-Type: application/json'); echo json_encode([ 'success' => false, 'message' => 'El plugin no está configurado correctamente. Falta la dirección del servidor.' ]); exit; } if (empty($config['unmsApiToken'])) { $log->appendLog('ERROR: No se ha configurado unmsApiToken'); header('Content-Type: application/json'); echo json_encode([ 'success' => false, 'message' => 'El plugin no está configurado correctamente. Falta el token de API de UNMS.' ]); exit; } $segmento = $_POST['segment'] ?? ''; // 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'; $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"; $apiToken = $config['unmsApiToken']; $log->appendLog("URL de API: $apiUrl"); // 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, false); $log->appendLog('Resultado de búsqueda: ' . json_encode([ 'success' => $resultado['success'], 'ipsDisponibles' => count($resultado['data'] ?? []), 'ipsEnUso' => count($resultado['used'] ?? []) ])); header('Content-Type: application/json'); echo json_encode($resultado); } catch (Exception $e) { $log->appendLog('EXCEPCIÓN en búsqueda de IPs: ' . $e->getMessage() . ' | Trace: ' . $e->getTraceAsString()); header('Content-Type: application/json'); echo json_encode([ 'success' => false, 'message' => 'Error al procesar la solicitud: ' . $e->getMessage(), 'error_file' => $e->getFile(), 'error_line' => $e->getLine() ]); } catch (Error $e) { $log->appendLog('ERROR FATAL en búsqueda de IPs: ' . $e->getMessage() . ' | Trace: ' . $e->getTraceAsString()); header('Content-Type: application/json'); echo json_encode([ 'success' => false, 'message' => 'Error fatal: ' . $e->getMessage(), 'error_file' => $e->getFile(), 'error_line' => $e->getLine() ]); } $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 (Throwable $e) { $log->appendLog('ERROR en verify_batch: ' . $e->getMessage()); echo json_encode(['success' => false, 'message' => $e->getMessage()]); } 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')); } // Log de acceso público $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 = !empty($config['enablePingVerification']) && ($config['enablePingVerification'] === true || $config['enablePingVerification'] === '1'); ?>
Sistema de gestión de direcciones IP para UISP
Consultando IPs disponibles...
| # | Dirección IP | Estado | Acción |
|---|