HTTP请求类 - HttpClient.class.php

HTTPClient

写一个Http类,能更好的了解HTTP

在这里用 socket 模拟 get, post 请求,并得到结果,其中也加了 head 请求,用 php 自带的函数 get_headers()得到结果,代替了浏览器的请求工作。

1. HTTP请求与响应信息

  1.1 请求信息

请求行(Method URI HttpVersion)
请求头信息
空行
请求主体(主体可有可无)
  1.2 响应信息

响应行(HttpVersion StatusCode StatusDesc)
响应头信息
空行
请求主体(主体可有可无)

2. 用 Telnet 模拟请求
  这里在本机运行
  开始 -> 运行 -> cmd, 回车 -> telnet localhost 80, 回车 -> 按 Ctrl+], 再回车
  2.1 get 方式
    几乎所有的方式包含一个头信息
    Host: localhost(本机用localhost)
HTTP请求类 - HttpClient.class.php_第1张图片
  2.2 post 方式
    可以照着完整的请求信息去灌水, 模拟登录...
    如果有表单内容要提交,需要包含
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 26(主体的长度)
HTTP请求类 - HttpClient.class.php_第2张图片
  2.3 head 方式
    仅获取服务器响应信息
HTTP请求类 - HttpClient.class.php_第3张图片

3. 用 php + socket 方式模拟请求
  直接贴代码,代码中有注释,实现 Telnet 中的请求 
  HttpClient.class.php code list

setUrl($url);
        $this->setLine();
        $this->setHeader();
        $this->request();
        return $this->response;
    }
    
    /**
     * 发送HTTP post请求
     * @access public
     */
    public function post() {
        $this->setLine('POST');
        $this->request();
        return $this->response;
    }
    
    /**
     * HTTP -> HEAD 方法,取得服务器响应一个 HTTP 请求所发送的所有标头
     * @access public
     * @param string $url 请求的url
     * @param int $fmt 数据返回形式,关联数组与普通数组
     * @return array 返回响应头信息
     */
    public function head($url = '', $fmt = 0) {
        $headers = null;
        if (is_string($url)) {
            $headers = get_headers($url, $fmt);
        }
        return $headers;
    }
    
    /**
     * 设置要请求的 url
     * @todo 这里未做url验证
     * @access public
     * @param string $url request url
     * @return bool
     */
    public function setUrl($url = '') {
        if (is_string($url)) {
            $this->url = parse_url($url);
            if (!isset($this->url['port'])) {//设置端口
                $this->url['port'] = 80;
            }
        } else {
            return false;
        }
    }
    
    /**
     * 设置HTTP协议的版本
     * @access public
     * @param string $version HTTP版本,default value = 1.1
     * @return bool 如果不在范围内返回false
     */
    public function setVersion($version = "1.1") {
        if ($version == '1.1' || $version == '1.0' || $version == '0.9') {
            $this->version = $version;
        } else {
            return false;
        }
    }
    
    /**
     * 设置HTTP请求行
     * @access public
     * @param string $method 请求方式 default value = GET
     */
    private function setLine($method = "GET") {
        //请求空:Method URI HttpVersion
        if (isset($this->url['query'])) {
            $this->line[0] = $method . " " . $this->url['path'] . "?" . $this->url['query'] . " HTTP/" . $this->version;
        } else {
            $this->line[0] = $method . " " . $this->url['path'] . " HTTP/" . $this->version;
        }
    }
    
    /**
     * 设置HTTP请求头信息
     * @access public
     * @param array $header 请求头信息
     */
    public function setHeader($header = null) {
        $this->header[0] = "Host: " . $this->url['host'];
        if (is_array($header)) {
            foreach($header as $k => $v) {
                $this->setHeaderKeyValue($k, $v);
            }
        }
    }
    
    /**
     * HTTP请求主体
     * @access public
     * @param array $body 请求主体
     */
    public function setBody($body = null) {
        if (is_array($body)) {
            foreach ($body as $k => $v) {
                $this->setBodyKeyValue($k, $v);
            }
        }
    }
    
    /**
     * 单条设置HTTP请求主体
     * @access public
     * @param string $key 请求主体的键
     * @param string $value 请求主体的值
     */
    public function setBodyKeyValue($key, $value) {
        if (is_string($key)) {
            $this->body[] = $key . "=" . $value;
        }
    }
    
    /**
     * 单条设置HTTP请求头信息
     * @access public
     * @param string $key 请求头信息的键
     * @param string $value 请求头信息的键
     */
    public function setHeaderKeyValue($key, $value) {
        if (is_string($key)) {
            $this->header[] = $key . ": " . $value;
        }
    }
    
    /**
     * socket连接host, 发送请求
     * @access private
     */
    private function request() {
        //构造http请求
        if (!empty($this->body)) {
            $bodyStr = implode("&", $this->body);
            $this->setHeaderKeyValue("Content-Length", strlen($bodyStr));
            $this->body[] = $bodyStr;
            $req = array_merge($this->line, $this->header, array(""), array($bodyStr), array(""));
        } else {
            $req = array_merge($this->line, $this->header, array(""), $this->body, array(""));
        }
        $req = implode(self::CRLF, $req);
        
        //socket连接host
        $this->fh = fsockopen($this->url['host'], $this->url['port'], $this->errno, $this->errstr, $this->timeout);
        
        if (!$this->fh) {
            echo "socket connect fail!";
            return false;
        }
        
        //写请求
        fwrite($this->fh, $req);
        
        //读响应
        while (!feof($this->fh)) {
            $this->response .= fread($this->fh, 1024);
        }
    }
    
    /**
     * 关闭socket连接
     * @access public
     */
    public function __destruct() {
        if ($this->fh) {
            fclose($this->fh);
        }
    }
    
}


$url = "http://localhost/xdebug/post_test.php";

/** get test **/
$http1 = new HttpClient();
var_dump($http1->get($url));

/** post test **/
$http2 = new HttpClient();
$header = array(
    "Content-Type" => "application/x-www-form-urlencoded"
);
$body = array(
    "username" => "1234",
    "submit" => "Login"
);
$http2->setUrl($url);
$http2->setHeader($header);
$http2->setBody($body);
var_dump($http2->post());

/** head test **/
$http3 = new HttpClient();
var_dump($http3->head($url, 1));
post_test.php code list




    
        post request test
    
    
        
运行结果:


你可能感兴趣的:(PHP,http)