PHP使用fsockopen指定ip通过GET或者POST获取远程数据

27 11 月

当域名与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;
	}
}

 

2 Replies to “PHP使用fsockopen指定ip通过GET或者POST获取远程数据

  1. 这个方法不能,网上的方法,我看过主要是两种实现:
    1、利用浏览器发送多个php请求实现多线程,其实就等于服务器开了多个php线程
    2、利用pthread库,这个确实是可以的,但是不推荐用在web环境。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注