/home/suroeste/public_html/payments.transportessuroeste.com/public
Edit: /home/suroeste/public_html/payments.transportessuroeste.com/public/index.php (9280B)
getHttpCode() : 500;
$errors = $e instanceof ValidationException ? $e->getErrors() : [];
// Log completo (siempre, incluyendo detalles internos)
LogService::error('errors', $e->getMessage(), [
'exception' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => APP_DEBUG ? $e->getTraceAsString() : null
]);
$responseTime = (microtime(true) - $startTime) * 1000;
LogService::access($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $code, $responseTime);
// Mensaje seguro para el usuario: nunca filtrar SQL, paths, o stack traces
$safeMessage = $e->getMessage();
if (!($e instanceof ApiException)) {
// Excepcion no controlada: mensaje generico en produccion
$safeMessage = APP_DEBUG ? $e->getMessage() : 'Error interno del servidor';
$code = 500;
}
JsonResponse::error($safeMessage, $code, $errors);
});
// ============================================================================
// CORS
// ============================================================================
$allowedOrigin = getenv('CORS_ALLOWED_ORIGIN') ?: '';
if (empty($allowedOrigin) && !empty($_SERVER['HTTP_ORIGIN'])) {
// En produccion, restringir a origenes conocidos
$allowedOrigin = $_SERVER['HTTP_ORIGIN'];
}
if (empty($allowedOrigin)) {
$allowedOrigin = APP_URL;
}
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: ' . $allowedOrigin);
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-API-Key, X-Signature, X-Timestamp, X-Request-ID');
header('Access-Control-Max-Age: 86400');
exit(0);
}
header('Access-Control-Allow-Origin: ' . $allowedOrigin);
// ============================================================================
// SEGURIDAD
// ============================================================================
// Excluir webhooks de ePayco del middleware de seguridad
$isEpaycoWebhook = strpos($_SERVER['REQUEST_URI'], '/webhook/epayco') !== false ||
strpos($_SERVER['REQUEST_URI'], '/callback') !== false;
if (!$isEpaycoWebhook) {
$security = new SecurityMiddleware();
$security->apply();
}
// ============================================================================
// RATE LIMITING
// ============================================================================
$rateLimiter = new RateLimiter();
$clientIp = LogService::getClientIp();
try {
$rateLimiter->check($clientIp, $_SERVER['REQUEST_URI']);
foreach ($rateLimiter->getHeaders($clientIp) as $header => $value) {
header("{$header}: {$value}");
}
} catch (RateLimitException $e) {
throw $e;
}
// ============================================================================
// CALCULAR URI
// ============================================================================
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$scriptDir = dirname($_SERVER['SCRIPT_NAME']);
if ($scriptDir !== '/' && $scriptDir !== '\\' && strpos($uri, $scriptDir) === 0) {
$uri = substr($uri, strlen($scriptDir));
}
if (empty($uri) || $uri === false) {
$uri = '/';
} elseif ($uri[0] !== '/') {
$uri = '/' . $uri;
}
// ============================================================================
// RUTAS
// ============================================================================
$router = new Router();
$controller = new ApiController();
// Rutas públicas (sin autenticación)
$router->get('/api/v1/health', fn() => $controller->healthCheck(), false);
$router->get('/api/v1/banks/pse', fn() => $controller->getPseBanks(), false);
$router->post('/api/v1/webhook/epayco', fn() => $controller->handleCallback(), false);
$router->get('/api/v1/callback', fn() => $controller->handleCallback(), false);
$router->post('/api/v1/callback', fn() => $controller->handleCallback(), false);
// Rutas protegidas (requieren API Key)
$router->post('/api/v1/payments', fn() => $controller->createPayment(), true);
$router->get('/api/v1/payments/{uuid}', fn($p) => $controller->getPayment($p['uuid']), true);
$router->get('/api/v1/payments/ticket/{reference}', fn($p) => $controller->getPaymentByTicket($p['reference']), true);
// ============================================================================
// DESPACHAR
// ============================================================================
$route = $router->dispatch($method, $uri);
if ($route['handler'] === null) {
throw new ApiException("Endpoint no encontrado: {$method} {$uri}", 404);
}
// Autenticar si es necesario
$client = null;
if ($route['auth']) {
$auth = new AuthMiddleware();
$client = $auth->authenticate();
$controller->setClient($client);
}
// Ejecutar
$result = call_user_func($route['handler'], $route['params']);
// Responder
$responseTime = (microtime(true) - $startTime) * 1000;
LogService::access($method, $uri, 200, $responseTime, $client['uuid'] ?? null);
JsonResponse::send($result, 200);