PHP代理服务器页面跳转重定向问题求助
PHP代理服务器跳转路径修复方案
问题说明
开发用于浏览器嵌套项目的PHP代理服务器时,出现路径跳转错误:
- 在代理内访问谷歌执行搜索,页面跳转到
proxyserver/search?q=hi,而非预期的proxyserver/proxy.php?url=https://google.com/search?q=hi - 代理内站点从
/pageone跳转至/pagetwo时,实际从proxyserver/proxy.php?url=https://example.com/pageone跳转到proxyserver/pagetwo,丢失代理转发逻辑
核心原因
当前代码直接返回目标站点的原始HTML内容,其中的相对链接、表单提交地址等都是基于目标站点域名的。浏览器解析这些路径时,会默认以代理服务器的根目录为基准,而非通过proxy.php脚本携带目标URL参数转发请求。
修复方案
需要对返回的HTML内容进行全局替换,将所有相对路径转换为通过proxy.php转发的绝对路径,具体步骤:
- 解析目标URL的基础URL(协议+域名+端口),用于拼接相对路径
- 重写所有
<a>标签的href属性 - 重写所有
<form>标签的action属性 - 处理页面内的JavaScript跳转逻辑(如
location.href)
修改后的完整代码
ob_start("ob_gzhandler"); ini_set('memory_limit', '128M'); session_start(); $cookieFile = 'cookies.txt'; if (!isset($_COOKIE['PHPSESSID'])) { clearCookies(); } if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['url'])) { $url = $_GET['url']; proxyRequest($url); } elseif ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['url'])) { $url = $_POST['url']; // 移除POST数据中的url字段,避免提交重复参数 unset($_POST['url']); $postData = http_build_query($_POST); if (!filter_var($url, FILTER_VALIDATE_URL)) { echo "Error: Invalid URL."; exit; } proxyRequest($url, $postData); } else { echo "Debug: Invalid request received. "; echo "Debug: GET Data - " . json_encode($_GET) . "<br>"; echo "Debug: POST Data - " . json_encode($_POST) . "<br>"; echo "Error: Invalid request."; } function proxyRequest($url, $postData = null) { header('Content-Type: text/html'); header('Access-Control-Allow-Origin: *'); global $cookieFile; $customDNS = [ 'example.com:80:1.1.1.1', 'example.com:443:8.8.8.8', ]; $ch = curl_init($url); // 解析目标URL的基础信息 $parsedUrl = parse_url($url); $baseUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host']; if (isset($parsedUrl['port'])) { $baseUrl .= ':' . $parsedUrl['port']; } $currentPath = isset($parsedUrl['path']) ? $parsedUrl['path'] : '/'; // 处理当前路径为目录(用于相对路径拼接) if (strpos($currentPath, '.') !== false) { $currentPath = dirname($currentPath); } if ($currentPath !== '/') { $currentPath .= '/'; } $options = [ CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', CURLOPT_HTTPHEADER => [ 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'Accept-Language: en-GB', 'Accept-Encoding: gzip, deflate', 'Dnt: 1', 'Sec-GPC: 1', 'Sec-Fetch-Dest: document', 'Sec-Fetch-Mode: navigate', 'Connection: keep-alive', 'Upgrade-Insecure-Requests: 1', ], CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 10, CURLOPT_AUTOREFERER => true, CURLOPT_ENCODING => '', CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_RESOLVE => $customDNS, ]; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $options[CURLOPT_POST] = true; $options[CURLOPT_POSTFIELDS] = $postData; } if (isset($_COOKIE['PHPSESSID'])) { $options[CURLOPT_COOKIEJAR] = $cookieFile; $options[CURLOPT_COOKIEFILE] = $cookieFile; } curl_setopt_array($ch, $options); $content = curl_exec($ch); if ($content !== false) { preg_match_all('/Set-Cookie: (.*?);/i', $content, $matches); $receivedCookies = implode('; ', $matches[1]); file_put_contents($cookieFile, $receivedCookies); // 开始重写内容中的路径 $proxyScript = $_SERVER['SCRIPT_NAME']; // 获取当前代理脚本路径,如/proxyserver/proxy.php // 1. 重写<a>标签的href属性 $content = preg_replace_callback('/<a[^>]+href=["\'](.*?)["\']/i', function($matches) use ($baseUrl, $currentPath, $proxyScript) { $href = $matches[1]; // 跳过绝对URL、mailto、tel等 if (preg_match('/^(https?:\/\/|mailto:|tel:|#)/i', $href)) { return $matches[0]; } // 处理相对路径 if (strpos($href, '/') === 0) { $fullUrl = $baseUrl . $href; } else { $fullUrl = $baseUrl . $currentPath . $href; } // 转换为代理地址 return str_replace($href, $proxyScript . '?url=' . urlencode($fullUrl), $matches[0]); }, $content); // 2. 重写<form>标签的action属性 $content = preg_replace_callback('/<form[^>]+action=["\'](.*?)["\']/i', function($matches) use ($baseUrl, $currentPath, $proxyScript) { $action = $matches[1]; if (empty($action)) { // action为空时,默认是当前页面URL $fullUrl = $baseUrl . $currentPath; } elseif (preg_match('/^(https?:\/\/)/i', $action)) { return $matches[0]; } elseif (strpos($action, '/') === 0) { $fullUrl = $baseUrl . $action; } else { $fullUrl = $baseUrl . $currentPath . $action; } // 转换为代理地址,同时保留原表单的method return str_replace($action, $proxyScript . '?url=' . urlencode($fullUrl), $matches[0]); }, $content); // 3. 重写JavaScript中的location.href跳转 $content = preg_replace_callback('/location\.href\s*=\s*["\'](.*?)["\']/i', function($matches) use ($baseUrl, $currentPath, $proxyScript) { $href = $matches[1]; if (preg_match('/^(https?:\/\/)/i', $href)) { return $matches[0]; } if (strpos($href, '/') === 0) { $fullUrl = $baseUrl . $href; } else { $fullUrl = $baseUrl . $currentPath . $href; } return 'location.href = "' . $proxyScript . '?url=' . urlencode($fullUrl) . '"'; }, $content); echo $content; } else { error_log('Error: Unable to fetch content from the external website. cURL Error: ' . curl_error($ch)); echo "Error: Unable to fetch content from the external website. cURL Error: " . curl_error($ch); } curl_close($ch); } function clearCookies() { global $cookieFile; if (file_exists($cookieFile)) { unlink($cookieFile); } } ?>
关键修改点
- 新增目标URL解析逻辑,提取基础域名和当前路径,用于拼接相对路径
- 添加
<a>标签href属性重写,将相对路径转换为代理转发地址 - 添加
<form>标签action属性重写,确保表单提交通过代理处理 - 添加JavaScript跳转逻辑重写,修正页面内脚本跳转路径
- 优化POST请求处理,移除POST数据中的
url字段,避免参数冗余
内容的提问来源于stack exchange,提问作者0x64
相关产品推荐
相关产品推荐

