safeLoad(); } } // Utilidades function envv($key, $default = null) { $val = getenv($key); if ($val === false && isset($_ENV[$key])) $val = $_ENV[$key]; return $val !== false && $val !== null ? $val : $default; } // Cabeceras CORS y respuesta JSON unificada if (!defined('NON_JSON')) { header('Content-Type: application/json; charset=utf-8'); } $allowOrigin = envv('CORS_ALLOW_ORIGIN', '*'); header('Access-Control-Allow-Origin: ' . $allowOrigin); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization, X-ESP-Dispositivos-Token'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; } function json_success($data = null, $message = 'OK', $code = 200) { http_response_code($code); echo json_encode([ 'success' => true, 'message' => $message, 'data' => $data ], JSON_UNESCAPED_UNICODE); exit; } function json_error($message = 'Error', $code = 400, $data = null) { http_response_code($code); echo json_encode([ 'success' => false, 'message' => $message, 'data' => $data ], JSON_UNESCAPED_UNICODE); exit; } function json_response($success, $data = null, $message = '', $code = 200) { http_response_code($code); echo json_encode([ 'success' => $success, 'data' => $data, 'message' => $message, 'timestamp' => time() ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); exit; }