false, 'message' => 'Método no permitido. Solo se acepta POST.' ]); exit; } // Configuración de la API Laravel $API_CONFIG = [ 'base_url' => $ruta.'/api', // Cambiar por tu URL de Laravel 'endpoint' => '/regUsuario', // Tu endpoint de Laravel 'timeout' => 30, // Timeout en segundos 'auth_token' => '', // Token de autenticación si es necesario ]; try { // Validar y procesar datos del formulario $formData = validateAndProcessForm(); // Enviar datos a la API Laravel usando cURL $apiResponse = sendToLaravelAPI($formData, $API_CONFIG); // Procesar respuesta de la API $response = processAPIResponse($apiResponse); // Log de éxito logActivity('success', 'Usuario enviado a API', [ 'usuario' => $formData['usuario'] ?? 'N/A', 'empresa' => $formData['empresa'] ?? 'N/A', 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'N/A' ]); // Retornar respuesta echo json_encode($response); } catch (ValidationException $e) { // Errores de validación http_response_code(422); echo json_encode([ 'success' => false, 'message' => 'Error de validación', 'errors' => $e->getErrors() ]); } catch (APIException $e) { // Errores de la API http_response_code($e->getHttpCode()); echo json_encode([ 'success' => false, 'message' => $e->getMessage(), 'api_error' => $e->getApiError() ]); } catch (Exception $e) { // Errores generales logActivity('error', 'Error general en process_user.php', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'N/A' ]); http_response_code(500); echo json_encode([ 'success' => false, 'message' => 'Error interno del servidor. Por favor intente nuevamente.'.$e->getMessage() ]); } // ============================================================================ // FUNCIONES PRINCIPALES // ============================================================================ /** * Validar y procesar datos del formulario */ function validateAndProcessForm() { $errors = []; // Campos requeridos $requiredFields = [ 'empresa' => 'Nombre de la Empresa', 'usuario' => 'Nombre de Usuario', 'email' => 'Correo Electrónico', 'clavePublica' => 'Clave Pública', 'clavePrivada' => 'Clave Privada', 'colorValue' => 'Color de Branding' ]; // Validar campos requeridos foreach ($requiredFields as $field => $label) { if (empty($_POST[$field]) || trim($_POST[$field]) === '') { $errors[$field] = ["$label es obligatorio"]; } } // Validar formato de email if (!empty($_POST['email']) && !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { $errors['email'] = ['El formato del correo electrónico no es válido']; } // Validar usuario (solo alfanuméricos, guiones y guiones bajos) if (!empty($_POST['usuario']) && !preg_match('/^[a-zA-Z0-9_-]+$/', $_POST['usuario'])) { $errors['usuario'] = ['El usuario solo puede contener letras, números, guiones y guiones bajos']; } // Si hay errores, lanzar excepción if (!empty($errors)) { throw new ValidationException($errors); } // Procesar y limpiar datos $formData = [ 'empresa' => trim($_POST['empresa']), 'usuario' => trim($_POST['usuario']), 'email' => strtolower(trim($_POST['email'])), 'platf_pago' => !empty($_POST['platf_pago']) ? $_POST['platf_pago'] : 'stripe', 'clavePublica' => formatKey($_POST['clavePublica']), 'clavePrivada' => formatKey($_POST['clavePrivada']), 'colorBrand' => formatKey($_POST['colorValue']), ]; // Procesar logo si se envió if (isset($_FILES['logo']) && isset($_FILES['logo']['error']) && $_FILES['logo']['error'] !== UPLOAD_ERR_NO_FILE) { // processLogo validará el archivo y devolverá la info necesaria $formData['logo'] = processLogo($_FILES['logo']); } return $formData; } /** * Enviar datos a la API Laravel usando cURL */ function sendToLaravelAPI($formData, $config) { $url = $config['base_url'] . $config['endpoint']; // Inicializar cURL $ch = curl_init(); // Preparar campos para envío multipart/form-data $postFields = []; foreach ($formData as $key => $value) { if ($key === 'logo' && is_array($value) && isset($value['tmp_name'])) { // Verificar que el archivo existe y es legible if (!is_readable($value['tmp_name'])) { throw new Exception('No se puede leer el archivo de logo'); } // Crear CURLFile para enviar el archivo $postFields['logo'] = new CURLFile( $value['tmp_name'], $value['type'], $value['name'] ); // Agregar información adicional del archivo $postFields['logo_name'] = $value['name']; $postFields['logo_type'] = $value['type']; } else { $postFields[$key] = $value; } } // Cabeceras - NO establecer 'Content-Type: multipart/form-data' manualmente // cURL añadirá la cabecera Content-Type con el boundary correcto cuando se use CURLFile $headers = [ 'Accept: application/json', 'X-Requested-With: XMLHttpRequest' ]; if (!empty($config['auth_token'])) { $headers[] = 'Authorization: Bearer ' . $config['auth_token']; } // Configurar cURL curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $postFields, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => $config['timeout'], CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 3, CURLOPT_SSL_VERIFYPEER => false, // Solo para desarrollo CURLOPT_USERAGENT => 'PHP-FormProcessor/1.0', CURLOPT_HTTPHEADER => $headers ]); // Log de depuración: claves y estado del archivo (no logeamos contenido binario) logActivity('debug', 'Preparando campos para enviar a API', [ 'url' => $url, 'post_keys' => array_keys($postFields) ]); if (isset($postFields['logo']) && isset($formData['logo'])) { $tmp = $formData['logo']['tmp_name'] ?? null; logActivity('debug', 'Estado logo antes de cURL', [ 'tmp_name' => $tmp, 'exists' => $tmp ? file_exists($tmp) : false, 'readable' => $tmp ? is_readable($tmp) : false, 'size' => $formData['logo']['size'] ?? null, 'error' => $formData['logo']['error'] ?? null ]); } // Ejecutar petición $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); // Verificar errores de cURL if ($response === false || !empty($error)) { throw new Exception("Error de conexión con la API: $error"); } // Decodificar respuesta JSON $decodedResponse = json_decode($response, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception("Respuesta inválida de la API: " . $response); } return [ 'http_code' => $httpCode, 'data' => $decodedResponse, 'raw_response' => $response ]; } /** * Procesar respuesta de la API */ function processAPIResponse($apiResponse) { $httpCode = $apiResponse['http_code']; $data = $apiResponse['data']; // Verificar código de estado HTTP if ($httpCode >= 200 && $httpCode < 300) { // Éxito return [ 'success' => true, 'message' => $data['message'] ?? 'Usuario registrado exitosamente', 'data' => $data['data'] ?? null ]; } else { // Error de la API throw new APIException( $data['message'] ?? 'Error en la API', $httpCode, $data ); } } /** * Formatear claves (limpiar espacios y normalizar) */ function formatKey($key) { // Limpiar espacios extra $cleanKey = trim($key); // Normalizar saltos de línea $cleanKey = str_replace(["\r\n", "\r"], "\n", $cleanKey); return $cleanKey; } /** * Procesar archivo de logo */ function processLogo($logoFile) { // Validar archivo $allowedTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/svg+xml']; $maxSize = 2 * 1024 * 1024; // 2MB if (!in_array($logoFile['type'], $allowedTypes)) { throw new ValidationException(['logo' => ['El logo debe ser un archivo JPG, PNG o SVG']]); } if ($logoFile['size'] > $maxSize) { throw new ValidationException(['logo' => ['El logo no puede ser mayor a 2MB']]); } // Verificar que el archivo se subió correctamente if (!is_uploaded_file($logoFile['tmp_name'])) { throw new ValidationException(['logo' => ['Error al subir el archivo']]); } // Verificar que podemos leer el archivo if (!is_readable($logoFile['tmp_name'])) { throw new ValidationException(['logo' => ['No se puede leer el archivo subido']]); } return [ 'name' => $logoFile['name'], 'type' => $logoFile['type'], 'tmp_name' => $logoFile['tmp_name'], 'size' => $logoFile['size'], 'error' => $logoFile['error'] ]; } /** * Registrar actividad en log */ function logActivity($level, $message, $context = []) { $logEntry = [ 'timestamp' => date('Y-m-d H:i:s'), 'level' => $level, 'message' => $message, 'context' => $context ]; $logFile = 'logs/form_processor.log'; // Crear directorio de logs si no existe if (!file_exists(dirname($logFile))) { mkdir(dirname($logFile), 0755, true); } // Escribir al log file_put_contents($logFile, json_encode($logEntry) . "\n", FILE_APPEND | LOCK_EX); } // ============================================================================ // CLASES DE EXCEPCIÓN PERSONALIZADAS // ============================================================================ class ValidationException extends Exception { private $errors; public function __construct($errors) { $this->errors = $errors; parent::__construct('Errores de validación'); } public function getErrors() { return $this->errors; } } class APIException extends Exception { private $httpCode; private $apiError; public function __construct($message, $httpCode = 500, $apiError = null) { $this->httpCode = $httpCode; $this->apiError = $apiError; parent::__construct($message); } public function getHttpCode() { return $this->httpCode; } public function getApiError() { return $this->apiError; } } ?>