您的位置:首页 > 理论基础 > 计算机网络

PHP HttpClient封装(可实现GET POST Cookie Session)

2012-12-22 23:13 686 查看
php封装的HttpClient,能实现些简单的功能。原来做过,这两天重新修改了一下。

<?php

/*
 * Filename: httpclient.php
 * Created on 2012-12-21
 * Created by RobinTang
 * To change the template for this generated file go to
 * Window - Preferences - PHPeclipse - PHP - Code Templates
 */
class SinCookie {
	public $name; // Cookie名称
	public $value; // Cookie值

	// 下面三个属性现在未实现
	public $expires; // 过期时间
	public $path; // 路径
	public $domain; // 域

	// 从Cookie字符串创建一个Cookie对象
	function __construct($s = false) {
		if ($s) {
			$i1 = strpos($s, '=');
			$i2 = strpos($s, ';');
			$this->name = trim(substr($s, 0, $i1));
			$this->value = trim(substr($s, $i1 +1, $i2 - $i1 -1));
		}
	}
	// 获取Cookie键值对
	function getKeyValue() {
		return "$this->name=$this->value";
	}
}

// 会话上下文
class SinHttpContext {
	public $cookies; // 会话Cookies
	public $referer; // 前一个页面地址

	function __construct() {
		$this->cookies = array ();
		$this->refrer = "";
	}

	// 设置Cookie
	function cookie($key, $val) {
		$ck = new SinCookie();
		$ck->name = $key;
		$ck->value = $val;
		$this->addCookie($ck);
	}
	// 添加Cookie
	function addCookie($ck) {
		$this->cookies[$ck->name] = $ck;
	}
	// 获取Cookies字串,请求时用到
	function cookiesString() {
		$res = '';
		foreach ($this->cookies as $ck) {
			$res .= $ck->getKeyValue() . ';';
		}
		return $res;
	}
}

// Http请求对象
class SinHttpRequest {
	public $url; // 请求地址
	public $method = 'GET'; // 请求方法
	public $host; // 主机
	public $path; // 路径
	public $scheme; // 协议,http
	public $port; // 端口

	public $header; // 请求头
	public $body; // 请求正文

	// 设置头
	function setHeader($k, $v) {
		if (!isset ($this->header)) {
			$this->header = array ();
		}
		$this->header[$k] = $v;
	}

	// 获取请求字符串
	// 包含头和请求正文
	// 获取之后直接写socket就行
	function reqString() {
		$matches = parse_url($this->url);
		!isset ($matches['host']) && $matches['host'] = '';
		!isset ($matches['path']) && $matches['path'] = '';
		!isset ($matches['query']) && $matches['query'] = '';
		!isset ($matches['port']) && $matches['port'] = '';

		$host = $matches['host'];
		$path = $matches['path'] ? $matches['path'] . ($matches['query'] ? '?' . $matches['query'] : '') : '/';
		$port = !empty ($matches['port']) ? $matches['port'] : 80;
		$scheme = $matches['scheme'] ? $matches['scheme'] : 'http';

		$this->host = $host;
		$this->path = $path;
		$this->scheme = $scheme;
		$this->port = $port;

		$method = strtoupper($this->method);
		$res = "$method $path HTTP/1.1\r\n";
		$res .= "Host: $host\r\n";

		if ($this->header) {
			reset($this->header);
			while (list ($k, $v) = each($this->header)) {
				if (isset ($v) && strlen($v) > 0)
					$res .= "$k: $v\r\n";
			}
		}
		$res .= "\r\n";
		if ($this->body) {
			$res .= $this->body;
			$res .= "\r\n\r\n";
		}
		return $res;
	}
}

// Http响应
class SinHttpResponse {
	public $scheme; // 协议
	public $stasus; // 状态,成功的时候是ok
	public $code; // 状态码,成功的时候是200
	public $header; // 响应头
	public $body; // 响应正文
	function __construct() {
		$this->header = array ();
		$this->body = null;
	}
	function setHeader($key, $val) {
		$this->header[$key] = $val;
	}
}

// HttpClient
class SinHttpClient {
	public $keepcontext = true; // 是否维持会话
	public $context; // 上下文
	public $request; // 请求
	public $response; // 响应

	public $debug = false; // 是否在Debug模式,为true的时候会打印出请求内容和相同的头部

	function __construct() {
		$this->request = new SinHttpRequest();
		$this->response = new SinHttpResponse();
		$this->context = new SinHttpContext();
		$this->timeout = 15; // 默认的超时为15s
	}

	// 清除上一次的请求内容
	function clearRequest() {
		$this->request->body = '';
		$this->request->setHeader('Content-Length', false);
		$this->request->setHeader('Content-Type', false);
	}
	// post方法
	// data为请求的数据
	// 为键值对的时候模拟表单提交
	// 其他时候为数据提交,提交的形式为xml
	// 如有其他需求,请自行扩展
	function post($url, $data = false) {
		$this->clearRequest();
		if ($data) {
			if (is_array($data)) {
				$con = http_build_query($data);
				$this->request->setHeader('Content-Type', 'application/x-www-form-urlencoded');
			} else {
				$con = $data;
				$this->request->setHeader('Content-Type', 'text/xml; charset=utf-8');
			}
			$this->request->body = $con;
			$this->request->method = "POST";
			$this->request->setHeader('Content-Length', strlen($con));
		}
		$this->startRequest($url);
	}
	// get方法
	function get($url) {
		$this->clearRequest();
		$this->request->method = "GET";
		$this->startRequest($url);
	}
	//	该方法为内部调用方法,不用直接调用
	function startRequest($url) {
		$this->request->url = $url;
		if ($this->keepcontext) {
			// 如果保存上下文的话设置相关信息
			$this->request->setHeader('Referer', $this->context->refrer);
			$cks = $this->context->cookiesString();
			if (strlen($cks) > 0)
				$this->request->setHeader('Cookie', $cks);
		}
		// 获取请求内容
		$reqstring = $this->request->reqString();
		if ($this->debug)
			echo "Request:\n$reqstring\n";
		try {
			$fp = fsockopen($this->request->host, $this->request->port, $errno, $errstr, $this->timeout);
		} catch (Exception $ex) {
			echo $ex->getMessage();
			exit (0);
		}
		if ($fp) {
			stream_set_blocking($fp, true);
			stream_set_timeout($fp, $this->timeout);
			// 写数据
			fwrite($fp, $reqstring);
			$status = stream_get_meta_data($fp);
			if (!$status['timed_out']) { //未超时
				// 下面的循环用来读取响应头部
				while (!feof($fp)) {
					$h = fgets($fp);
					if ($this->debug)
						echo $h;
					if ($h && ($h == "\r\n" || $h == "\n"))
						break;
					$pos = strpos($h, ':');
					if ($pos) {
						$k = strtolower(trim(substr($h, 0, $pos)));
						$v = trim(substr($h, $pos +1));

						if ($k == 'set-cookie') {
							// 更新Cookie
							if ($this->keepcontext) {
								$this->context->addCookie(new SinCookie($v));
							}
						} else {
							// 添加到头里面去
							$this->response->setHeader($k, $v);
						}
					} else {
						// 第一行数据
						// 解析响应状态
						$preg = '/^(\S*) (\S*) (.*)$/';
						preg_match_all($preg, $h, $arr);
						isset ($arr[1][0]) & $this->response->scheme = trim($arr[1][0]);
						isset ($arr[2][0]) & $this->response->stasus = trim($arr[2][0]);
						isset ($arr[3][0]) & $this->response->code = trim($arr[3][0]);
					}
				}
				// 获取响应正文长度
				$len = (int) $this->response->header['content-length'];
				$res = '';
				// 下面的循环读取正文
				while (!feof($fp) && $len > 0) {
					$c = fread($fp, $len);
					$res .= $c;
					$len -= strlen($c);
				}
				$this->response->body = $res;
			}
			// 关闭Socket
			fclose($fp);
			// 把返回保存到上下文维持中
			$this->context->refrer = $url;
		}
	}
}

// demo
// now let begin test it
$client = new SinHttpClient();	// create a client
$client->get('http://www.baidu.com/');	// get
echo $client->response->body;	// echo
?>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: