about:blank

'; exit; } // CORS preflight if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS'); header('Access-Control-Allow-Headers: *'); header('Access-Control-Max-Age: 86400'); exit; } // Build target URL from path + query string $target = substr($_SERVER['REQUEST_URI'], 1); // strip leading / $query = $_SERVER['QUERY_STRING']; if ($query !== '') { $target .= '?' . $query; } if (!preg_match('#^https?://#i', $target)) { $target = 'http://' . $target; } $parts = parse_url($target); if (!$parts || !isset($parts['host'])) { http_response_code(400); echo 'Invalid target URL provided.'; exit; } // Collect and clean request headers $requestHeaders = getallheaders(); $forwardHeaders = []; // Hop-by-hop headers that should NOT be forwarded (both request and response) $hopByHop = [ 'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'te', 'trailer', 'transfer-encoding', 'upgrade' ]; foreach ($requestHeaders as $name => $value) { $lower = strtolower($name); // Drop Cloudflare headers, real IP, and original Host if (strpos($lower, 'cf-') === 0 || $lower === 'x-real-ip' || $lower === 'host') { continue; } // Don't forward hop-by-hop request headers if (in_array($lower, $hopByHop)) { continue; } // Accept-Encoding is handled by cURL automatically; do not forward it if ($lower === 'accept-encoding') { continue; } $forwardHeaders[] = "$name: $value"; } // Set the target host $forwardHeaders[] = 'Host: ' . $parts['host']; // Fallback User-Agent (only if client didn't send one) $hasUserAgent = false; foreach ($forwardHeaders as $h) { if (stripos($h, 'User-Agent:') === 0) { $hasUserAgent = true; break; } } if (!$hasUserAgent) { $forwardHeaders[] = 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36'; } // cURL request $ch = curl_init($target); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => $_SERVER['REQUEST_METHOD'], CURLOPT_HTTPHEADER => $forwardHeaders, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HEADER => true, // include headers in output CURLOPT_TIMEOUT => 30, CURLOPT_ENCODING => '', // accept any compression, decompress automatically CURLOPT_SSL_VERIFYPEER => true, // keep enabled (HF has CA certs) ]); // Forward request body (if any) $body = file_get_contents('php://input'); if ($body !== '' && $body !== false) { curl_setopt($ch, CURLOPT_POSTFIELDS, $body); } $response = curl_exec($ch); $error = curl_error($ch); $info = curl_getinfo($ch); curl_close($ch); if ($error) { http_response_code(502); echo 'Upstream server fetch failed. Please check the URL and network.'; exit; } // Split headers and body $headerSize = $info['header_size']; $responseHeaders = substr($response, 0, $headerSize); $responseBody = substr($response, $headerSize); // Parse incoming response headers $headersArr = explode("\r\n", $responseHeaders); $statusCode = 200; $outHeaders = []; // name -> value pairs (duplicates allowed, but we'll filter some) foreach ($headersArr as $line) { // Status line if (stripos($line, 'HTTP/') === 0) { preg_match('/\d{3}/', $line, $m); $statusCode = (int)($m[0] ?? 200); continue; } if (trim($line) === '') { continue; } $colon = strpos($line, ':'); if ($colon !== false) { $name = substr($line, 0, $colon); $value = trim(substr($line, $colon + 1)); $lower = strtolower($name); // Remove security headers that block iframes if ($lower === 'content-security-policy' || $lower === 'x-frame-options') { continue; } // Remove hop-by-hop response headers if (in_array($lower, $hopByHop)) { continue; } // cURL already decompressed the body – remove Content-Encoding if ($lower === 'content-encoding') { continue; } $outHeaders[] = [$name, $value]; } } // --- Send final response --- http_response_code($statusCode); // Always add CORS and no-cache headers header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: *'); header('Access-Control-Allow-Headers: *'); header('Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate'); header('Pragma: no-cache'); header('Expires: 0'); // Forward upstream headers (except those we filtered out) foreach ($outHeaders as $h) { header($h[0] . ': ' . $h[1]); } echo $responseBody;