$value) { $lower = strtolower((string) $name); if ($lower === 'host' || $lower === 'content-length') { continue; } $headers[] = $name . ': ' . $value; } } else { foreach ($_SERVER as $key => $value) { if (strpos($key, 'HTTP_') !== 0) { continue; } $name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5))))); if (strtolower($name) === 'host') { continue; } $headers[] = $name . ': ' . $value; } if (!empty($_SERVER['CONTENT_TYPE'])) { $headers[] = 'Content-Type: ' . $_SERVER['CONTENT_TYPE']; } } if (!function_exists('curl_init')) { http_response_code(500); header('Content-Type: application/json'); echo json_encode([ 'error' => 'PHP curl extension is required for the API proxy', 'code' => 'PROXY_MISCONFIGURED', ]); exit; } $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => $method, CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => true, CURLOPT_FOLLOWLOCATION => false, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 60, CURLOPT_HTTPHEADER => $headers, ]); if ($method !== 'GET' && $method !== 'HEAD') { curl_setopt($ch, CURLOPT_POSTFIELDS, $body); } $response = curl_exec($ch); if ($response === false) { $err = curl_error($ch); curl_close($ch); http_response_code(502); header('Content-Type: application/json'); echo json_encode([ 'error' => 'API server unreachable. On the host run: npm run server (port 3001)', 'detail' => $err, 'code' => 'BAD_GATEWAY', ]); exit; } $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); $headerSize = (int) curl_getinfo($ch, CURLINFO_HEADER_SIZE); curl_close($ch); $rawHeaders = substr($response, 0, $headerSize); $responseBody = substr($response, $headerSize); http_response_code($status > 0 ? $status : 502); $skip = ['transfer-encoding', 'connection', 'keep-alive', 'content-length']; foreach (explode("\r\n", $rawHeaders) as $line) { if ($line === '' || stripos($line, 'HTTP/') === 0) { continue; } $parts = explode(':', $line, 2); if (count($parts) < 2) { continue; } $name = trim($parts[0]); if (in_array(strtolower($name), $skip, true)) { continue; } header($name . ':' . $parts[1], false); } echo $responseBody;