建议先看一下如何用telnet发送HTTP请求:
http://blog.csdn.net/whd526/article/details/75042691
http.class.php
<?php
class Http{
const CRLF = "\r\n";
protected $errno = -1;
protected $errstr = '';
protected $url = null;
protected $version = 'HTTP/1.1';
protected $fh = null;
protected $line = array();
protected $header = array();
protected $body = array();
protected $response = '';
public function __construct($url){
$this->conn($url);
$this->setHeader('Host',$this->url['host']);
}
/**
*此方法负责写请求行
*如 GET /index.php HTTP/1.1
*/
private function setLine($method){
$this->line[0] = $method.' '.$this->url['path'].$this->url['query'].' '.$this->version;
}
/**
*此方法负责写头信息
*如Host: localhost
*/
public function setHeader($key,$value){
$this->header[] = $key.': '.$value;
}
/**
*此方法负责写POST主体信息
*key=value的形式写进数组
*用http_build_query()封装成key1=value1&key2=value2
*/
public function setBody($key,$value){
//$this->body[] = $key.'='.$value;
$this->body[$key] = $value;
}
/**
*用fsockopen打开网络连接
*就像telnet 192.168.0.0 80
*/
private function conn($url){
//parse_url解析地址,返回其组成部分
$this->url = parse_url($url);
//如果URL没有port,则默认80端口
if(!isset($this->url['port'])){
$this->url['port'] = '80';
}
//如果URL没有path,则默认根路径'/'
//如www.baidu.com没有path
//如http://news.baidu.com/sports,path为/sports
if(!isset($this->url['path'])){
$this->url['path'] = '/';
}
if(!isset($this->url['query'])){
$this->url['query'] = '';
}else{
$this->url['query'] = '?'.$this->url['query'];
}
//打开网络连接
$this->fh = fsockopen($this->url['host'],$this->url['port'],$this->errno,$this->errstr,3);
if(!$this->fh){
echo "ERROR:$errno-$errstr";
exit;
}
}
public function get(){
$this->setLine('GET');
$this->body='';
$this->request();
return $this->response;
}
public function post(){
$this->setLine('POST');
$this->setHeader('Content-type','application/x-www-form-urlencoded');
$this->body = http_build_query($this->body);
//var_dump($this->body);exit();
$this->setHeader('Content-length',strlen($this->body));
$this->request();
return $this->response;
}
/**
*拼接请求信息,并写入response
*/
private function request(){
$req = array_merge($this->line,$this->header,array(''),array($this->body),array(''));
//var_dump($req);exit;
$req = implode(self::CRLF,$req);
//print_r($req);exit;
fwrite($this->fh, $req);
while(!feof($this->fh)){
$this->response .= fread($this->fh, 1024);
}
$this->close();
}
/**
*关闭socket连接
*/
public function close(){
fclose($this->fh);
}
}
//GET请求
// $url = 'http://www.baidu.com';
// $http = new Http($url);
// $http->setHeader('Connection','close');
// echo $http->get();
//POST请求
// $url = 'http://localhost/tel2.php';
// $http = new Http($url);
// $http->setHeader('Connection','close');
// $http->setBody('username','Edward');
// $http->setBody('age','20');
// $http->setBody('submit','提交');
// echo $http->post();
?>
为什么要在头信息设置Connection:close
如果不设置Connection:close,会发现速度非常慢,feof不能准确判断是否已经得到了所有的数据,直到超过设置的超时时间才结束。
Connection的状态有两种,一种是keep-alive 另外一种就是close。
keep-alive就是保持客户端与服务器的连接,这是默认的方式。
close表示服务器给客户端发送信息之后就断开了,.close对资源消耗占用的少一些。
再完善一点,其实这和TCP三次握手有关,如果返回的是keep-alive表示之前的握手还可以用在接下来的请求当中去,如果是close的话当前请求完成后会进行四次握手关闭连接,在接下来的请求就要重新握手,这是HTTP/1.1相对1.0新增的一个部分,加快了网络传输。
实战:
用HTTP请求,往电驴发送站内信(http://home.verycd.com/cp.php?ac=pm)
先注册登录,然后在线发送一遍,用谷歌浏览器的开发者模式观察请求头信息,至于具体的抓包细节就不一一赘述了
<?php
require('./http.class.php');
$url = 'http://home.verycd.com/cp.php?ac=pm&op=send&touid=0&pmid=0';
$http = new Http($url);
$http->setHeader('Connection','close');
$http->setHeader('Accept','text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8');
$http->setHeader('Accept-Encoding','gzip, deflate');
$http->setHeader('Accept-Language','zh-CN,zh;q=0.8');
$http->setHeader('Cookie','xxxx');//自己的cookie
$http->setHeader('Referer','http://home.verycd.com/cp.php?ac=pm&op=send&touid=0&pmid=0');
$http->setHeader('User-Agent','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36');
$http->setBody('username','test');
$http->setBody('message','robot2222');
$http->setBody('refer','');
$http->setBody('pmsubmit','true');
$http->setBody('pmsubmit_btn','发送');
$http->setBody('formhash','16f835b2');
$http->post();
echo "ok";
?>