PHP网页代理重定向逻辑问题:跳转路径异常修正求助
解决PHP网页代理的重定向跳转问题
你的问题核心在于:代码开启了curl的自动跟随重定向,并且直接转发目标服务器的Location响应头,导致浏览器直接跳转到目标站点的路径,而非通过代理的?url=参数跳转。
解决步骤:
- 关闭curl自动跟随重定向:让curl返回原始的重定向响应,而非直接跳转后的内容,方便手动处理
Location头。 - 拦截重定向状态码:识别3xx系列HTTP状态码(301、302、303、307、308),提取目标跳转地址。
- 转换跳转地址为代理格式:若目标地址是相对路径,先拼接成完整URL;若是绝对URL则直接使用,再构造代理跳转路径
/?url=完整跳转URL。 - 替换响应头:用构造好的代理跳转地址替换原服务器的
Location头后发送给浏览器。
修改后的完整代码:
<?php if (!isset($_GET['url'])) { header('HTTP/1.1 400 Bad Request'); echo 'Missing URL parameter'; exit; } $url = $_GET['url']; if (!filter_var($url, FILTER_VALIDATE_URL)) { header('HTTP/1.1 400 Bad Request'); echo 'Invalid URL'; exit; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 关闭自动跟随重定向,手动处理跳转 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_BINARYTRANSFER, true); $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); $content_length = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD); // 获取当前请求的有效URL,用于拼接相对路径 $effective_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); curl_close($ch); // 处理重定向状态码 $redirect_codes = [301, 302, 303, 307, 308]; if (in_array($http_code, $redirect_codes)) { // 提取Location头内容 preg_match('/Location: (.*)\r\n/', $response, $matches); if (!empty($matches[1])) { $target_location = trim($matches[1]); // 处理相对路径,转换为绝对URL if (!filter_var($target_location, FILTER_VALIDATE_URL)) { $parsed_effective = parse_url($effective_url); $base_url = $parsed_effective['scheme'] . '://' . $parsed_effective['host']; if (!empty($parsed_effective['port'])) { $base_url .= ':' . $parsed_effective['port']; } // 拼接相对路径 if (str_starts_with($target_location, '/')) { $target_location = $base_url . $target_location; } else { $current_path = dirname($parsed_effective['path']); $target_location = $base_url . $current_path . '/' . $target_location; } } // 构造代理跳转地址 $proxy_redirect = '/?url=' . urlencode($target_location); // 发送重定向响应头 header('HTTP/1.1 ' . $http_code); header('Location: ' . $proxy_redirect); exit; } } if ($http_code !== 200) { header('HTTP/1.1 ' . $http_code); echo 'Failed to fetch the content'; exit; } $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = substr($response, 0, $header_size); $body = substr($response, $header_size); // 转发响应头时跳过Location(已处理)和不需要的头 foreach (explode("\r\n", $headers) as $header) { if (!empty($header) && stripos($header, 'Content-Length') === false && stripos($header, 'Transfer-Encoding') === false && stripos($header, 'Location') === false) { header($header); } } header('Content-Type: ' . $content_type); if ($content_length > 0) { header('Content-Length: ' . $content_length); } // (可选)处理响应体中的相对链接,比如a标签、img标签的路径 // 示例:$body = preg_replace('/href="([^"]+)"/', 'href="/?url=' . urlencode($base_url) . '/$1"', $body); echo $body; ?>
额外说明:
- 代码中新增了相对路径跳转的处理逻辑,确保目标服务器返回相对路径时,能正确转换为完整URL再构造代理地址。
- 若需要页面内所有链接(如
<a>、<img>)都通过代理访问,可参考代码中的注释添加正则替换逻辑,将相对路径转换为代理格式的URL。
内容的提问来源于stack exchange,提问作者Kaj
相关产品推荐
相关产品推荐

