写了一个简单的PHP反向代理

用PHP写了个简单的反代

特性

  • 直接输入域名即可访问, 例如 httpbin.org/get
  • 替换页面内的 URL, 例如 http://example.com/login => http://~/proxy/http://example.com/login
  • 支持 GET 和 POST 请求

已知 Bug

  • 无法识别重定向
  • 无法携带 Cookies
  • 不支持相对 URL 替换, 例如 /blog/1./features
  • 不支持前端路由
  • 不支持动态页面跳转, 例如 window.location.href = "/blog/" + ${blogId}

源码

已在 Github 开源

<?php
/** 
 * PHP Reverse Proxy
 * By shikukuya
 */

error_reporting(0); // 关闭第一次请求出错时的警告
$url_pattern = "/https?:\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/"; // 用于匹配页面内的URL
$real_url = $_SERVER["QUERY_STRING"]; // 真实的URL在问号(?)后
$server_name = $_SERVER["SERVER_NAME"]; // 服务器域名端口
$method = $_SERVER["REQUEST_METHOD"]; // 请求方法
$headers = getallheaders(); // Apache独有方法,获取请求头
$headers_string = ""; // 用于存放字符串格式请求头
foreach ($headers as $k => $v) { // 将键值对转为字符串
    $headers_string = "$headers_string$k: $v\n";
}
if (!preg_match($url_pattern, $real_url)) { // 如果只输入了域名
    $real_url = "http://$real_url"; // 添加“http://”
}

request: // 标签,重试时跳转到这里
$options["http"] = [
    "timeout" => 15, // 超时时间
    "method" => $method, // 请求方法
    "header" => $headers_string, // 请求头
];
$context = stream_context_create($options);
$response = file_get_contents($real_url, false, $context); // 发送请求
if ($response) { // 成功了
    $response = preg_replace_callback($url_pattern, function ($m) {
        global $server_name;
        return "http://$server_name/proxy/?" . $m[0];
    }, $response); // 替换页面内的URL
    header("Content-Type: " . $http_response_header["Content-Type"]); // 修改Content-Type
    echo $response; // 输出
} else { // 失败了
    if ($headers_string === "") { // 已经重试过了
        die("无法访问此页面");
    } else { // 还没有重试
        $headers_string = ""; // 清楚请求头重试
        goto request;
    }
}
posted @ 2023-06-18 08:50  shikukuya  阅读(988)  评论(0)    收藏  举报