PHP Socket编程 之 fsockopen指定ip获取远程数据 及 301自动跳转

当域名与ip不相符,又无法修改系统hosts时,我们需要指定ip来获取远程数据,通过搜索php curl相关资料,未发现可用方法,故写了如下两个函数。

函数支持get或者post方式,301自动跳转,支持自定义header,仅支持ipv4的http协议。

代码已集成到AlonePHP中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/* http_get_with_ip,用于ip解析错误或者需要指定ip的时候以get方式获取数据
 * @param string $url 远程地址
 * @param string $ip 需要访问的ip
 * @param array $header 需要添加的其它header参数
 * @return string|boolean 返回获取的内容,访问失败返回false
 */
function http_get_with_ip($url, $ip = '', $header = array()) {
    return curl_post_with_ip($url, null, $ip, $header);
}
  
/* http_post_with_ip,用于ip解析错误或者需要指定ip的时候以post方式获取数据
 * @param string $url 远程地址
 * @param array|null $post_data 以post方式提交数据,如果此参数为null,则使用get方式
 * @param string $ip 需要访问的ip
 * @param array $header 需要添加的其它header参数
 * @return string|boolean 返回获取的内容,访问失败返回false
 */
function http_post_with_ip($url, $post_data = null, $ip = '', $header = array()) {
    /* 最大循环跳转次数 */
    $loop_max_count = 5;
  
    static $loop_count = 0;
    $errstr = '';
    $errno = '';
    /* 解析URL */
    $url_array = parse_url($url);
    if ($url_array === false) {
        $loop_count = 0;
        return false;
    }
    $host = $url_array['host'];
    /* 域名解析失败则退出 */
    if (!$host) {
        $loop_count = 0;
        return false;
    }
    /* 获取端口 */
    $port = isset($url_array['port']) ? $url_array['port'] : 80;
    /* 获取ip */
    if ($ip === '') {
        $ip = gethostbyname($host);
    }
  
    $fp = fsockopen($ip, $port, $errno, $errstr, 90);
    if (!$fp) {
        $loop_count = 0;
        return false;
    } else {
        $out = (is_array($post_data) ? "POST" : "GET") . " {$url} HTTP/1.0\r\n";
        /* 最终的header数组 */
        $header_result = array();
        $header_result['Host'] = $host;
        /* 处理post数据 */
        if (is_array($post_data)) {
            $post_values = array();
            foreach ($post_data as $key => $value) {
                array_push($post_values, urlencode($key) . "=" . urlencode($value));
            }
            $post_content = implode("&", $post_values);
            $header_result['Content-type'] = "application/x-www-form-urlencoded";
            $header_result['Content-length'] = strlen($post_content);
        }
        /* 设置默认的header */
        $header_result['User-Agent'] = "Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0";
        $header_result = array_merge($header_result, $header);
        /* 载入用户的header */
        foreach ($header_result as $key => $value) {
            $out .= $key . ": " . $value . "\r\n";
        }
        $out .= "Connection: close\r\n\r\n";
        if (is_array($post_data)) {
            $out .= $post_content;
        }
        fputs($fp, $out);
  
        $response = '';
        while (($line = fread($fp, 4096))) {
            $response .= $line;
        }
        fclose($fp);
  
        //分离Header头信息
        $pos = strpos($response, "\r\n\r\n");
        $header_content = substr($response, 0, $pos);
        $response = substr($response, $pos + 4);
  
        if (preg_match("/HTTP\/\d\.\d (\d+) /", $header_content, $matches) !== 1) {
            $loop_count = 0;
            return false;
        }
  
        $http_status = $matches[1];
        /* 如果是30x,就跳转 */
        if ($http_status == 301 || $http_status == 302) {
            if (preg_match("/Location:(.*?)\n/", $header_content, $matches) !== 1) {
                $loop_count = 0;
                return false;
            }
            $url = trim($matches[1]);
            $loop_count++;
            return curl_post_with_ip($url, $post_data, $ip, $header);
        }
  
        $loop_count = 0;
        return $response;
    }
}

https://actom.me/blog/php%E4%BD%BF%E7%94%A8fsockopen%E6%8C%87%E5%AE%9Aip%E9%80%9A%E8%BF%87get%E6%88%96%E8%80%85post%E8%8E%B7%E5%8F%96%E8%BF%9C%E7%A8%8B%E6%95%B0%E6%8D%AE.html/comment-page-1

posted @   笠航  阅读(513)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示