php 利用socket发送HTTP请求(GET,POST)
今天给大家带来的是如何利用socket发送GET,POST请求。我借用燕十八老师封装好的一个Http类给进行说明。
在日常编程中相信很多人和我一样大部分时间是利用浏览器向服务器提出GET,POST请求,那么可否利用其它方式提出GET,POST请求呢?答案必然是肯定的。了解过HTTP协议的人知道,浏览器提交请求的实质是向服务器发送一个请求信息,这个请求信息有请求行,请求头,请求体(非必须)构成。服务器根据请求信息返回一个响应信息。连接断开。
HTTP请求的格式如下所示:
<request-line> <headers> <blankline> [<request-body>]
HTTP响应的格式与请求的格式十分相似:
<status-line> <headers> <blankline> [<response-body>]
我们可以利用HTTP发送请求的原理,可以重新考虑利用socket发送HTTP请求。
Socket的英文原义是“孔”或“插座”。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。如此看来,其实利用socket操作远程文件和读写本地的文件一样容易,把本地文件看成通过硬件传输,远程文件通过网线传输就行了。
因而可以将发送请求的考虑成建立连接->打开socket接口(fsockopen())->写入请求(fwrite())->读出响应(fread()->关闭文件(fclose())。话不多说,直接上代码:
<?php interfaceProto{ //连接url functionconn($url); //发送get查询 functionget(); //发送post查询 functionpost(); //关闭连接 functionclose(); } classHttpimplementsProto{ constCRLF="\r\n"; protected$errno=-1; protected$errstr=''; protected$response=''; protected$url=null; protected$version='HTTP/1.1'; protected$fh=null; protected$line=array(); protected$header=array(); protected$body=array(); publicfunction__construct($url){ $this->conn($url); $this->setHeader('Host:'.$this->url['host']); } //此方法负责写请求行 protectedfunctionsetLine($method){ $this->line[0]=$method.''.$this->url['path'].'?'.$this->url['query'].''.$this->version; } //此方法负责写头信息 publicfunctionsetHeader($headerline){ $this->header[]=$headerline; } //此方法负责写主体信息 protectedfunctionsetBody($body){ $this->body[]=http_build_query($body); } //连接url publicfunctionconn($url){ $this->url=parse_url($url); //判断端口 if(!isset($this->url['port'])){ $this->url['port']=80; } //判断query if(!isset($this->url['query'])){ $this->url['query']=''; } $this->fh=fsockopen($this->url['host'],$this->url['port'],$this->errno,$this->errstr,3); } //构造get请求的数据 publicfunctionget(){ $this->setLine('GET'); $this->request(); return$this->response; } //构造post查询的数据 publicfunctionpost($body=array()){ $this->setLine('POST'); //设计content-type $this->setHeader('Content-type:application/x-www-form-urlencoded'); //设计主体信息,比GET不一样的地方 $this->setBody($body); //计算content-length $this->setHeader('Content-length:'.strlen($this->body[0])); $this->request(); return$this->response; } //真正请求 publicfunctionrequest(){ //把请求行,头信息,实体信息放在一个数组里,便于拼接 $req=array_merge($this->line,$this->header,array(''),$this->body,array('')); //print_r($req); $req=implode(self::CRLF,$req); //echo$req;exit; fwrite($this->fh,$req); while(!feof($this->fh)){ $this->response.=fread($this->fh,1024); } $this->close();//关闭连接 } //关闭连接 publicfunctionclose(){ fclose($this->fh); } }
利用此类发送一个简单的GET请求:
<?php //记得引用Http类 $url="http://home.jb51.net/u/DeanChopper/"; $http=newHttp($url); $response=$http->get(); print_r($response);
返回值为信息,可以对响应信息进行进一步处理,得到自己想得到的内容。
我们来看下一个具体的实例
<?php /** *使用PHPSocket编程模拟Httppost和get请求 *@authorkoma */ classHttp{ private$sp="\r\n";//这里必须要写成双引号 private$protocol='HTTP/1.1'; private$requestLine=""; private$requestHeader=""; private$requestBody=""; private$requestInfo=""; private$fp=null; private$urlinfo=null; private$header=array(); private$body=""; private$responseInfo=""; privatestatic$http=null;//Http对象单例 privatefunction__construct(){} publicstaticfunctioncreate(){ if(self::$http===null){ self::$http=newHttp(); } returnself::$http; } publicfunctioninit($url){ $this->parseurl($url); $this->header['Host']=$this->urlinfo['host']; return$this; } publicfunctionget($header=array()){ $this->header=array_merge($this->header,$header); return$this->request('GET'); } publicfunctionpost($header=array(),$body=array()){ $this->header=array_merge($this->header,$header); if(!empty($body)){ $this->body=http_build_query($body); $this->header['Content-Type']='application/x-www-form-urlencoded'; $this->header['Content-Length']=strlen($this->body); } return$this->request('POST'); } privatefunctionrequest($method){ $header=""; $this->requestLine=$method.''.$this->urlinfo['path'].'?'.$this->urlinfo['query'].''.$this->protocol; foreach($this->headeras$key=>$value){ $header.=$header==""?$key.':'.$value:$this->sp.$key.':'.$value; } $this->requestHeader=$header.$this->sp.$this->sp; $this->requestInfo=$this->requestLine.$this->sp.$this->requestHeader; if($this->body!=""){ $this->requestInfo.=$this->body; } /* *注意:这里的fsockopen中的url参数形式为"www.xxx.com" *不能够带"http://"这种 */ $port=isset($this->urlinfo['port'])?isset($this->urlinfo['port']):'80'; $this->fp=fsockopen($this->urlinfo['host'],$port,$errno,$errstr); if(!$this->fp){ echo$errstr.'('.$errno.')'; returnfalse; } if(fwrite($this->fp,$this->requestInfo)){ $str=""; while(!feof($this->fp)){ $str.=fread($this->fp,1024); } $this->responseInfo=$str; } fclose($this->fp); return$this->responseInfo; } privatefunctionparseurl($url){ $this->urlinfo=parse_url($url); } } //$url="http://news.163.com/14/1102/01/AA0PFA7Q00014AED.html"; $url="http://localhost/httppro/post.php"; $http=Http::create()->init($url); /*发送get请求 echo$http->get(array( 'User-Agent'=>'Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/35.0.1916.153Safari/537.36', )); */ /*发送post请求*/ echo$http->post(array( 'User-Agent'=>'Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/35.0.1916.153Safari/537.36', ),array('username'=>'发一个中文','age'=>22));