PHP Socket编程 之 fsockopen指定ip获取远程数据 及 301自动跳转
当域名与ip不相符,又无法修改系统hosts时,我们需要指定ip来获取远程数据,通过搜索php curl相关资料,未发现可用方法,故写了如下两个函数。
函数支持get或者post方式,301自动跳转,支持自定义header,仅支持ipv4的http协议。
代码已集成到AlonePHP中。
/* 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