php 利用socket发送HTTP请求(GET,POST)


Posted in PHP onAugust 24, 2015

今天给大家带来的是如何利用socket发送GET,POST请求。我借用燕十八老师封装好的一个Http类给进行说明。

在日常编程中相信很多人和我一样大部分时间是利用浏览器向服务器提出GET,POST请求,那么可否利用其它方式提出GET,POST请求呢?答案必然是肯定的。了解过HTTP协议的人知道,浏览器提交请求的实质是向服务器发送一个请求信息,这个请求信息有请求行,请求头,请求体(非必须)构成。服务器根据请求信息返回一个响应信息。连接断开。

 

HTTP请求的格式如下所示:

<request-line>
<headers>
<blank line>
[<request-body>]

HTTP响应的格式与请求的格式十分相似:

<status-line>
<headers>
<blank line>
[<response-body>]

我们可以利用HTTP发送请求的原理,可以重新考虑利用socket发送HTTP请求。

Socket的英文原义是“孔”或“插座”。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。如此看来,其实利用socket操作远程文件和读写本地的文件一样容易,把本地文件看成通过硬件传输,远程文件通过网线传输就行了。

因而可以将发送请求的考虑成 建立连接->打开socket接口(fsockopen())->写入请求(fwrite())->读出响应(fread()->关闭文件(fclose())。话不多说,直接上代码:

<?php 
interface Proto {
  // 连接url
  function conn($url);
  //发送get查询
  function get();
  // 发送post查询
  function post();
  // 关闭连接
  function close();
}
class Http implements Proto {
  const CRLF = "\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();
  public function __construct($url) {
    $this->conn($url);
    $this->setHeader('Host: ' . $this->url['host']);
  }
  // 此方法负责写请求行
  protected function setLine($method) {
    $this->line[0] = $method . ' ' . $this->url['path'] . '?' .$this->url['query'] . ' '. $this->version;
  }
  // 此方法负责写头信息
  public function setHeader($headerline) {
    $this->header[] = $headerline; 
  }
  // 此方法负责写主体信息
  protected function setBody($body) {
     $this->body[] = http_build_query($body);
  }
  // 连接url
  public function conn($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请求的数据
  public function get() {
    $this->setLine('GET');
    $this->request();
    return $this->response;
  }
  // 构造post查询的数据
  public function post($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;
  }
  // 真正请求
  public function request() {
    // 把请求行,头信息,实体信息 放在一个数组里,便于拼接
    $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(); // 关闭连接
  }
  // 关闭连接
  public function close() {
    fclose($this->fh);
  }
}

      利用此类发送一个简单的GET请求:

<?php
//记得引用Http类
$url="http://home.3water.com/u/DeanChopper/";
$http=new Http($url);
$response=$http->get();
print_r($response);

返回值为信息,可以对响应信息进行进一步处理,得到自己想得到的内容。

我们来看下一个具体的实例

<?php
/**
 * 使用PHP Socket 编程模拟Http post和get请求
 * @author koma
 */
class Http{
  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 = "";
  private static $http = null; //Http对象单例
   
  private function __construct() {}
   
  public static function create() {
    if ( self::$http === null ) { 
      self::$http = new Http();
    }
    return self::$http;
  }
   
  public function init($url) {
    $this->parseurl($url);
    $this->header['Host'] = $this->urlinfo['host'];
    return $this;
  }
   
  public function get($header = array()) {
    $this->header = array_merge($this->header, $header);
    return $this->request('GET');
  }
   
  public function post($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');
  }
   
  private function request($method) {
    $header = "";
    $this->requestLine = $method.' '.$this->urlinfo['path'].'?'.$this->urlinfo['query'].' '.$this->protocol;
    foreach ( $this->header as $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.')';
      return false;
    }
    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;
  }
   
  private function parseurl($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 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36',
));
*/
 
/* 发送post请求 */
echo $http->post(array(
    'User-Agent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36',
), array('username'=>'发一个中文', 'age'=>22));
PHP 相关文章推荐
php 清除网页病毒的方法
Dec 05 PHP
php cookie的操作实现代码(登录)
Dec 29 PHP
php学习笔记 [预定义数组(超全局数组)]
Jun 09 PHP
php从右向左/从左向右截取字符串的实现方法
Nov 28 PHP
Yii查询生成器(Query Builder)用法实例教程
Sep 04 PHP
PHP利用header跳转失效的解决方法
Oct 24 PHP
PHP.ini安全配置检测工具pcc简单介绍
Jul 02 PHP
PHP实现伪静态方法汇总
Jan 13 PHP
PHP实现的网站目录扫描索引工具
Sep 08 PHP
总结PHP如何获取当前主机、域名、网址、路径、端口和参数等
Sep 09 PHP
利用PHP访问MySql数据库的逻辑操作以及增删改查的实例讲解
Aug 30 PHP
基于php中echo用逗号和用点号的区别详解
Jan 23 PHP
php实现递归的三种基本方式
Jul 04 #PHP
php析构函数的简单使用说明
Aug 24 #PHP
分享微信扫码支付开发遇到问题及解决方案-附Ecshop微信支付插件
Aug 23 #PHP
dvwa+xampp搭建显示乱码的问题及解决方案
Aug 23 #PHP
详细解读PHP的Yii框架中登陆功能的实现
Aug 21 #PHP
使用PHP进行微信公众平台开发的示例
Aug 21 #PHP
PHP的Yii框架的基本使用示例
Aug 21 #PHP
You might like
php str_pad() 将字符串填充成指定长度的字符串
2010/02/23 PHP
深入PHP magic quotes的详解
2013/06/17 PHP
关于php内存不够用的快速解决方法
2013/10/26 PHP
ThinkPHP模板引擎之导入资源文件方法详解
2014/06/18 PHP
php中字符查找函数strpos、strrchr与strpbrk用法
2014/11/18 PHP
php使用pdo连接并查询sql数据库的方法
2014/12/24 PHP
Yii遍历行下每列数据的方法
2016/10/17 PHP
PHP命名空间定义与用法实例分析
2019/08/14 PHP
clientX,pageX,offsetX,x,layerX,screenX,offsetLeft区别分析
2010/03/12 Javascript
深入理解JavaScript作用域和作用域链
2011/10/21 Javascript
jquery实现的鼠标拖动排序Li或Table
2014/05/04 Javascript
node.js中的emitter.on方法使用说明
2014/12/10 Javascript
JavaScript不使用prototype和new实现继承机制
2014/12/29 Javascript
javascript实现在线客服效果
2015/07/15 Javascript
深入理解js函数的作用域与this指向
2016/05/28 Javascript
JavaScript中cookie工具函数封装的示例代码
2016/10/11 Javascript
浅谈Node.js:fs文件系统模块
2016/12/08 Javascript
JavaScript闭包_动力节点Java学院整理
2017/06/27 Javascript
Python引用传值概念与用法实例小结
2017/10/07 Python
python实现word 2007文档转换为pdf文件
2018/03/15 Python
通过Py2exe将自己的python程序打包成.exe/.app的方法
2018/05/26 Python
Caffe均值文件mean.binaryproto转mean.npy的方法
2018/07/09 Python
Python如何爬取qq音乐歌词到本地
2020/06/01 Python
Python函数的迭代器与生成器的示例代码
2020/06/18 Python
Django websocket原理及功能实现代码
2020/11/14 Python
python中delattr删除对象方法的代码分析
2020/12/15 Python
python opencv实现图像配准与比较
2021/02/09 Python
css3截图_动力节点Java学院整理
2017/07/11 HTML / CSS
美国最大的在线水培用品商店:GrowersHouse.com
2018/08/14 全球购物
客服专员岗位职责范本
2013/11/29 职场文书
委托协议书范本
2014/04/22 职场文书
做一个有道德的人活动方案
2014/08/25 职场文书
小学一年级数学教学计划
2015/01/20 职场文书
军训后的感想
2015/08/07 职场文书
一篇文章带你深入了解Mysql触发器
2021/08/02 MySQL