PHP 兼容 Curl/Socket/Stream 的 HTTP 操作类

来源:互联网 发布:如何自学中医 知乎 编辑:程序博客网 时间:2024/04/29 02:22

  1. /************************************************************ 
  2. * 描述:HTTP操作类 
  3. * 作者:heiyeluren 
  4. * 创建:2009/12/13 04:43 
  5. * 修改:2009/12/16 10:30 实现基本HTTP各种接口操作支持 
  6. * 
  7. ************************************************************/ 
  8.  
  9.  
  10. /** 
  11. * HTTP功能工厂方法类 
  12. * 
  13. * 调用示例代码: 
  14. try { 
  15. $http = Http::factory('http://www.baidu.com', Http::TYPE_SOCK ); 
  16. echo $http->get(); 
  17. $http = Http::factory('http://127.0.0.1/test/i.php', Http::TYPE_SOCK ); 
  18. echo $http->post('', array('user'=>'我们', 'nick'=>'ASSADF@#!32812989+-239%ASDF'), '', array('aa'=>'bb', 'cc'=>'dd')); 
  19. } catch (Exception $e) { 
  20. echo $e->getMessage(); 
  21. } 
  22. */ 
  23. class Http 
  24. /** 
  25. * @var 使用 CURL 
  26. */ 
  27. const TYPE_CURL   = 1; 
  28. /** 
  29. * @var 使用 Socket 
  30. */ 
  31. const TYPE_SOCK   = 2; 
  32. /** 
  33. * @var 使用 Stream 
  34. */ 
  35. const TYPE_STREAM = 3; 
  36.  
  37.  
  38. /** 
  39. * 保证对象不被clone 
  40. */ 
  41. private function __clone() {} 
  42.  
  43.     /** 
  44. * 构造函数 
  45. */ 
  46. private function __construct() {} 
  47.  
  48.  
  49. /** 
  50. * HTTP工厂操作方法 
  51. * 
  52. * @param string $url 需要访问的URL 
  53. * @param int $type 需要使用的HTTP类 
  54. * @return object 
  55. */ 
  56. public static function factory($url = ''$type = self::TYPE_SOCK){ 
  57. if ($type == ''){ 
  58.    $type = self::TYPE_SOCK; 
  59. switch($type) { 
  60.    case self::TYPE_CURL : 
  61.     if (!function_exists('curl_init')){ 
  62.      throw new Exception(__CLASS__ . " PHP CURL extension not install"); 
  63.     } 
  64.     $obj = Http_Curl::getInstance($url); 
  65.     break
  66.    case self::TYPE_SOCK : 
  67.     if (!function_exists('fsockopen')){ 
  68.      throw new Exception(__CLASS__ . " PHP function fsockopen() not support"); 
  69.     }    
  70.     $obj = Http_Sock::getInstance($url); 
  71.     break
  72.    case self::TYPE_STREAM : 
  73.     if (!function_exists('stream_context_create')){ 
  74.      throw new Exception(__CLASS__ . " PHP Stream extension not install"); 
  75.     }    
  76.     $obj = Http_Stream::getInstance($url); 
  77.     break
  78.    default
  79.     throw new Exception("http access type $type not support"); 
  80. return $obj
  81.  
  82.  
  83. /** 
  84. * 生成一个供Cookie或HTTP GET Query的字符串 
  85. * 
  86. * @param array $data 需要生产的数据数组,必须是 Name => Value 结构 
  87. * @param string $sep 两个变量值之间分割的字符,缺省是 & 
  88. * @return string 返回生成好的Cookie查询字符串 
  89. */ 
  90. public static function makeQuery($data$sep = '&'){ 
  91. $encoded = ''
  92. while (list($k,$v) = each($data)) { 
  93.    $encoded .= ($encoded ? "$sep" : ""); 
  94.    $encoded .= rawurlencode($k)."=".rawurlencode($v); 
  95. return $encoded
  96.  
  97.  
  98.  
  99. /** 
  100. * 使用CURL 作为核心操作的HTTP访问类 
  101. * 
  102. * @desc CURL 以稳定、高效、移植性强作为很重要的HTTP协议访问客户端,必须在PHP中安装 CURL 扩展才能使用本功能 
  103. */ 
  104. class Http_Curl 
  105. /** 
  106. * @var object 对象单例 
  107. */ 
  108. static $_instance = NULL; 
  109.  
  110. /** 
  111. * @var string 需要发送的cookie信息 
  112. */ 
  113. private $cookies = ''
  114. /** 
  115. * @var array 需要发送的头信息 
  116. */ 
  117. private $header = array(); 
  118. /** 
  119. * @var string 需要访问的URL地址 
  120. */ 
  121. private $uri = ''
  122. /** 
  123. * @var array 需要发送的数据 
  124. */ 
  125. private $vars = array(); 
  126.  
  127. /** 
  128. * 构造函数 
  129. * 
  130. * @param string $configFile 配置文件路径 
  131. */ 
  132. private function __construct($url){ 
  133. $this->uri = $url
  134.  
  135. /** 
  136. * 保证对象不被clone 
  137. */ 
  138. private function __clone() {} 
  139.  
  140.  
  141. /** 
  142. * 获取对象唯一实例 
  143. * 
  144. * @param string $configFile 配置文件路径 
  145. * @return object 返回本对象实例 
  146. */ 
  147. public static function getInstance($url = ''){ 
  148. if (!(self::$_instance instanceof self)){ 
  149.    self::$_instance = new self($url); 
  150. return self::$_instance
  151.  
  152. /** 
  153. * 设置需要发送的HTTP头信息 
  154. * 
  155. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  156. *       或单一的一条类似于 'Host: example.com' 头信息字符串 
  157. * @return void 
  158. */ 
  159. public function setHeader($header){ 
  160. if (emptyempty($header)) { 
  161.    return
  162. if (is_array($header)){ 
  163.    foreach ($header as $k => $v){ 
  164.     $this->header[] = is_numeric($k) ? trim($v) : (trim($k) .": ". trim($v));    
  165.    } 
  166. elseif (is_string($header)){ 
  167.    $this->header[] = $header
  168.  
  169. /** 
  170. * 设置Cookie头信息 
  171. * 
  172. * 注意:本函数只能调用一次,下次调用会覆盖上一次的设置 
  173. * 
  174. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  175. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  176. * @return void 
  177. */ 
  178. public function setCookie($cookie){ 
  179. if (emptyempty($cookie)) { 
  180.    return
  181. if (is_array($cookie)){ 
  182.    $this->cookies = Http::makeQuery($cookie';'); 
  183. elseif (is_string($cookie)){ 
  184.    $this->cookies = $cookie
  185.  
  186. /** 
  187. * 设置要发送的数据信息 
  188. * 
  189. * 注意:本函数只能调用一次,下次调用会覆盖上一次的设置 
  190. * 
  191. * @param array 设置需要发送的数据信息,一个类似于 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  192. * @return void 
  193. */ 
  194. public function setVar($vars){ 
  195. if (emptyempty($vars)) { 
  196.    return
  197. if (is_array($vars)){ 
  198.    $this->vars = $vars
  199.  
  200. /** 
  201. * 设置要请求的URL地址 
  202. * 
  203. * @param string $url 需要设置的URL地址 
  204. * @return void 
  205. */ 
  206. public function setUrl($url){ 
  207. if ($url != '') { 
  208.    $this->uri = $url
  209.  
  210. /** 
  211. * 发送HTTP GET请求 
  212. * 
  213. * @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数 
  214. * @param array $vars 需要单独返送的GET变量 
  215. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  216. *         或单一的一条类似于 'Host: example.com' 头信息字符串 
  217. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  218. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  219. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  220. * @param array $options 当前操作类一些特殊的属性设置 
  221. * @return unknown 
  222. */ 
  223. public function get($url = ''$vars = array(), $header = array(), $cookie = ''$timeout = 5, $options = array()){ 
  224. $this->setUrl($url); 
  225. $this->setHeader($header); 
  226. $this->setCookie($cookie); 
  227. $this->setVar($vars); 
  228. return $this->send('GET'$timeout); 
  229.  
  230. /** 
  231. * 发送HTTP POST请求 
  232. * 
  233. * @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数 
  234. * @param array $vars 需要单独返送的GET变量 
  235. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  236. *         或单一的一条类似于 'Host: example.com' 头信息字符串 
  237. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  238. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  239. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  240. * @param array $options 当前操作类一些特殊的属性设置 
  241. * @return unknown 
  242. */ 
  243. public function post($url = ''$vars = array(), $header = array(), $cookie = ''$timeout = 5, $options = array()){ 
  244. $this->setUrl($url); 
  245. $this->setHeader($header); 
  246. $this->setCookie($cookie); 
  247. $this->setVar($vars); 
  248. return $this->send('POST'$timeout); 
  249.  
  250. /** 
  251. * 发送HTTP请求核心函数 
  252. * 
  253. * @param string $method 使用GET还是POST方式访问 
  254. * @param array $vars 需要另外附加发送的GET/POST数据 
  255. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  256. * @param array $options 当前操作类一些特殊的属性设置 
  257. * @return string 返回服务器端读取的返回数据 
  258. */ 
  259. public function send($method = 'GET'$timeout = 5, $options = array()){ 
  260. //处理参数是否为空 
  261. if ($this->uri == ''){ 
  262.    throw new Exception(__CLASS__ .": Access url is empty"); 
  263.     
  264. //初始化CURL 
  265.         $ch = curl_init(); 
  266.         curl_setopt($ch, CURLOPT_HEADER, 0); 
  267.         curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 
  268.         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
  269.         curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); 
  270.         
  271.         //设置特殊属性 
  272.         if (!emptyempty($options)){ 
  273.          curl_setopt_array($ch , $options); 
  274.         }        
  275.         //处理GET请求参数 
  276.         if ($method == 'GET' && !emptyempty($this->vars)){ 
  277.          $query = Http::makeQuery($this->vars); 
  278.          $parse = parse_url($this->uri); 
  279.          $sep = isset($parse['query']) ? '&' : '?'
  280.          $this->uri .= $sep . $query
  281.         } 
  282.         //处理POST请求数据 
  283.         if ($method == 'POST'){ 
  284.             curl_setopt($ch, CURLOPT_POST, 1 ); 
  285.             curl_setopt($ch, CURLOPT_POSTFIELDS, $this->vars); 
  286.         } 
  287.         
  288.         //设置cookie信息 
  289.         if (!emptyempty($this->cookies)){ 
  290.             curl_setopt($ch, CURLOPT_COOKIE, $this->cookies); 
  291.         } 
  292.         //设置HTTP缺省头 
  293.         if (emptyempty($this->header)){ 
  294.          $this->header = array
  295.           'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)'
  296.           //'Accept-Language: zh-cn',          
  297.           //'Cache-Control: no-cache', 
  298.          ); 
  299.         } 
  300.         curl_setopt($ch, CURLOPT_HTTPHEADER, $this->header); 
  301.  
  302.         //发送请求读取输数据 
  303.         curl_setopt($ch, CURLOPT_URL, $this->uri);        
  304.         $data = curl_exec($ch); 
  305.         if( ($err = curl_error($ch)) ){ 
  306.             curl_close($ch); 
  307.    throw new Exception(__CLASS__ ." error: "$err); 
  308.         } 
  309.         curl_close($ch); 
  310.         return $data
  311.  
  312.  
  313.  
  314.  
  315.  
  316. /** 
  317. * 使用 Socket操作(fsockopen) 作为核心操作的HTTP访问接口 
  318. * 
  319. * @desc Network/fsockopen 是PHP内置的一个Sokcet网络访问接口,必须安装/打开 fsockopen 函数本类才能工作, 
  320. *    同时确保其他相关网络环境和配置是正确的 
  321. */ 
  322. class Http_Sock 
  323. /** 
  324. * @var object 对象单例 
  325. */ 
  326. static $_instance = NULL; 
  327.  
  328. /** 
  329. * @var string 需要发送的cookie信息 
  330. */ 
  331. private $cookies = ''
  332. /** 
  333. * @var array 需要发送的头信息 
  334. */ 
  335. private $header = array(); 
  336. /** 
  337. * @var string 需要访问的URL地址 
  338. */ 
  339. private $uri = ''
  340. /** 
  341. * @var array 需要发送的数据 
  342. */ 
  343. private $vars = array(); 
  344.  
  345. /** 
  346. * 构造函数 
  347. * 
  348. * @param string $configFile 配置文件路径 
  349. */ 
  350. private function __construct($url){ 
  351. $this->uri = $url
  352.  
  353. /** 
  354. * 保证对象不被clone 
  355. */ 
  356. private function __clone() {} 
  357.  
  358.  
  359. /** 
  360. * 获取对象唯一实例 
  361. * 
  362. * @param string $configFile 配置文件路径 
  363. * @return object 返回本对象实例 
  364. */ 
  365. public static function getInstance($url = ''){ 
  366. if (!(self::$_instance instanceof self)){ 
  367.    self::$_instance = new self($url); 
  368. return self::$_instance
  369.  
  370. /** 
  371. * 设置需要发送的HTTP头信息 
  372. * 
  373. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  374. *       或单一的一条类似于 'Host: example.com' 头信息字符串 
  375. * @return void 
  376. */ 
  377. public function setHeader($header){ 
  378. if (emptyempty($header)) { 
  379.    return
  380. if (is_array($header)){ 
  381.    foreach ($header as $k => $v){ 
  382.     $this->header[] = is_numeric($k) ? trim($v) : (trim($k) .": ". trim($v));    
  383.    } 
  384. elseif (is_string($header)){ 
  385.    $this->header[] = $header
  386.  
  387. /** 
  388. * 设置Cookie头信息 
  389. * 
  390. * 注意:本函数只能调用一次,下次调用会覆盖上一次的设置 
  391. * 
  392. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  393. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  394. * @return void 
  395. */ 
  396. public function setCookie($cookie){ 
  397. if (emptyempty($cookie)) { 
  398.    return
  399. if (is_array($cookie)){ 
  400.    $this->cookies = Http::makeQuery($cookie';'); 
  401. elseif (is_string($cookie)){ 
  402.    $this->cookies = $cookie
  403.  
  404. /** 
  405. * 设置要发送的数据信息 
  406. * 
  407. * 注意:本函数只能调用一次,下次调用会覆盖上一次的设置 
  408. * 
  409. * @param array 设置需要发送的数据信息,一个类似于 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  410. * @return void 
  411. */ 
  412. public function setVar($vars){ 
  413. if (emptyempty($vars)) { 
  414.    return
  415. if (is_array($vars)){ 
  416.    $this->vars = $vars
  417.  
  418. /** 
  419. * 设置要请求的URL地址 
  420. * 
  421. * @param string $url 需要设置的URL地址 
  422. * @return void 
  423. */ 
  424. public function setUrl($url){ 
  425. if ($url != '') { 
  426.    $this->uri = $url
  427.  
  428. /** 
  429. * 发送HTTP GET请求 
  430. * 
  431. * @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数 
  432. * @param array $vars 需要单独返送的GET变量 
  433. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  434. *         或单一的一条类似于 'Host: example.com' 头信息字符串 
  435. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  436. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  437. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  438. * @param array $options 当前操作类一些特殊的属性设置 
  439. * @return unknown 
  440. */ 
  441. public function get($url = ''$vars = array(), $header = array(), $cookie = ''$timeout = 5, $options = array()){ 
  442. $this->setUrl($url); 
  443. $this->setHeader($header); 
  444. $this->setCookie($cookie); 
  445. $this->setVar($vars); 
  446. return $this->send('GET'$timeout); 
  447.  
  448. /** 
  449. * 发送HTTP POST请求 
  450. * 
  451. * @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数 
  452. * @param array $vars 需要单独返送的GET变量 
  453. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  454. *         或单一的一条类似于 'Host: example.com' 头信息字符串 
  455. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  456. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  457. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  458. * @param array $options 当前操作类一些特殊的属性设置 
  459. * @return unknown 
  460. */ 
  461. public function post($url = ''$vars = array(), $header = array(), $cookie = ''$timeout = 5, $options = array()){ 
  462. $this->setUrl($url); 
  463. $this->setHeader($header); 
  464. $this->setCookie($cookie); 
  465. $this->setVar($vars); 
  466. return $this->send('POST'$timeout); 
  467.  
  468. /** 
  469. * 发送HTTP请求核心函数 
  470. * 
  471. * @param string $method 使用GET还是POST方式访问 
  472. * @param array $vars 需要另外附加发送的GET/POST数据 
  473. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  474. * @param array $options 当前操作类一些特殊的属性设置 
  475. * @return string 返回服务器端读取的返回数据 
  476. */ 
  477. public function send($method = 'GET'$timeout = 5, $options = array()){ 
  478. //处理参数是否为空 
  479. if ($this->uri == ''){ 
  480.    throw new Exception(__CLASS__ .": Access url is empty"); 
  481.  
  482.         //处理GET请求参数 
  483.         if ($method == 'GET' && !emptyempty($this->vars)){ 
  484.          $query = Http::makeQuery($this->vars); 
  485.          $parse = parse_url($this->uri); 
  486.          $sep = isset($parse['query'])&&($parse['query']!='') ? '&' : '?'
  487.          $this->uri .= $sep . $query
  488.         } 
  489.         
  490.         //处理POST请求数据 
  491.         $data = ''
  492.         if ($method == 'POST' && !emptyempty($this->vars)){ 
  493.          $data = Http::makeQuery($this->vars); 
  494.           $this->setHeader('Content-Type: application/x-www-form-urlencoded'); 
  495.          $this->setHeader('Content-Length: 'strlen($data)); 
  496.         } 
  497.         
  498. //解析URL地址 
  499. $url = parse_url($this->uri); 
  500. $host = $url['host']; 
  501. $port = isset($url['port']) && ($url['port']!='') ? $url['port'] : 80; 
  502. $path = isset($url['path']) && ($url['path']!='') ? $url['path'] : '/'
  503. $path .= isset($url['query']) ? "?"$url['query'] : ''
  504.  
  505. //组织HTTP请求头信息 
  506. array_unshift(&$this->header, $method ." "$path ." HTTP/1.1"); 
  507.         $this->setHeader('User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)'); 
  508. if (!preg_match("/^[/d]{1,3}/.[/d]{1,3}/.[/d]{1,3}/.[/d]{1,3}$/"$host)){ 
  509.    $this->setHeader("Host: ".$host); 
  510. if ($this->cookies != ''){ 
  511.    $this->setHeader("Cookie: "$this->cookies); 
  512. $this->setHeader("Connection: Close"); 
  513. //'Accept-Language: zh-cn', 
  514.      //'Cache-Control: no-cache', 
  515.      
  516.      //构造请求信息 
  517.      $header = ''
  518. foreach ($this->header as $h) { 
  519.    $header .= $h ."/r/n"
  520. $header .= "/r/n"
  521. if ($method == 'POST' && $data != ''){ 
  522.    $header .= $data ."/r/n"
  523.  
  524. //连接服务器发送请求数据 
  525. $ip = gethostbyname($host); 
  526. if (!($fp = fsockopen($ip$port, &$errno, &$errstr$timeout))){ 
  527.    throw new Exception(__CLASS__ .": Can't connect $host:$port, errno:$errno,message:$errstr"); 
  528. fputs($fp$header); 
  529. $lineSize = 1024; 
  530.  
  531. //处理301,302跳转页面访问 
  532. $line = fgets($fp$lineSize); 
  533. $first = preg_split("//s/", trim($line)); 
  534. if ( isset($first[1]) && in_array($first[1], array('301','302')) ){ 
  535.    while (!feof($fp)) {   
  536.     $line = fgets($fp$lineSize); 
  537.     $second = preg_split("//s/", trim($line)); 
  538.     if (ucfirst(trim($second[0]))=='Location:' && $second[1]!=''){ 
  539.      $this->header = array(); 
  540.      return $this->get(trim($second[1])); 
  541.     } 
  542.    } 
  543.  
  544. //正常读取返回数据 
  545. $buf = ''
  546. $inheader = 1; 
  547. while (!feof($fp)) { 
  548.    if ($inheader && ($line == "/n" || $line == "/r/n")) { 
  549.      $inheader = 0; 
  550.    }   
  551.    $line = fgets($fp$lineSize); 
  552.    if ($inheader == 0) { 
  553.     $buf .=$line
  554.    } 
  555. fclose($fp); 
  556.  
  557. return $buf
  558.  
  559.  
  560.  
  561. /** 
  562. * 使用文件流操作函数为核心操作的HTTP访问接口 
  563. * 
  564. * @desc stream_* 和 fopen/file_get_contents 是PHP内置的一个流和文件操作接口,必须打开 fsockopen 函数本类才能工作, 
  565. *    同时确保其他相关网络环境和配置是正确的,包括 allow_url_fopen 等设置 
  566. */ 
  567. class Http_Stream 
  568.  
  569. /** 
  570. * @var object 对象单例 
  571. */ 
  572. static $_instance = NULL; 
  573.  
  574. /** 
  575. * @var string 需要发送的cookie信息 
  576. */ 
  577. private $cookies = ''
  578. /** 
  579. * @var array 需要发送的头信息 
  580. */ 
  581. private $header = array(); 
  582. /** 
  583. * @var string 需要访问的URL地址 
  584. */ 
  585. private $uri = ''
  586. /** 
  587. * @var array 需要发送的数据 
  588. */ 
  589. private $vars = array(); 
  590.  
  591. /** 
  592. * 构造函数 
  593. * 
  594. * @param string $configFile 配置文件路径 
  595. */ 
  596. private function __construct($url){ 
  597. $this->uri = $url
  598.  
  599. /** 
  600. * 保证对象不被clone 
  601. */ 
  602. private function __clone() {} 
  603.  
  604.  
  605. /** 
  606. * 获取对象唯一实例 
  607. * 
  608. * @param string $configFile 配置文件路径 
  609. * @return object 返回本对象实例 
  610. */ 
  611. public static function getInstance($url = ''){ 
  612. if (!(self::$_instance instanceof self)){ 
  613.    self::$_instance = new self($url); 
  614. return self::$_instance
  615.  
  616. /** 
  617. * 设置需要发送的HTTP头信息 
  618. * 
  619. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  620. *       或单一的一条类似于 'Host: example.com' 头信息字符串 
  621. * @return void 
  622. */ 
  623. public function setHeader($header){ 
  624. if (emptyempty($header)) { 
  625.    return
  626. if (is_array($header)){ 
  627.    foreach ($header as $k => $v){ 
  628.     $this->header[] = is_numeric($k) ? trim($v) : (trim($k) .": ". trim($v));    
  629.    } 
  630. elseif (is_string($header)){ 
  631.    $this->header[] = $header
  632.  
  633. /** 
  634. * 设置Cookie头信息 
  635. * 
  636. * 注意:本函数只能调用一次,下次调用会覆盖上一次的设置 
  637. * 
  638. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  639. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  640. * @return void 
  641. */ 
  642. public function setCookie($cookie){ 
  643. if (emptyempty($cookie)) { 
  644.    return
  645. if (is_array($cookie)){ 
  646.    $this->cookies = Http::makeQuery($cookie';'); 
  647. elseif (is_string($cookie)){ 
  648.    $this->cookies = $cookie
  649.  
  650. /** 
  651. * 设置要发送的数据信息 
  652. * 
  653. * 注意:本函数只能调用一次,下次调用会覆盖上一次的设置 
  654. * 
  655. * @param array 设置需要发送的数据信息,一个类似于 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  656. * @return void 
  657. */ 
  658. public function setVar($vars){ 
  659. if (emptyempty($vars)) { 
  660.    return
  661. if (is_array($vars)){ 
  662.    $this->vars = $vars
  663.  
  664. /** 
  665. * 设置要请求的URL地址 
  666. * 
  667. * @param string $url 需要设置的URL地址 
  668. * @return void 
  669. */ 
  670. public function setUrl($url){ 
  671. if ($url != '') { 
  672.    $this->uri = $url
  673.  
  674. /** 
  675. * 发送HTTP GET请求 
  676. * 
  677. * @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数 
  678. * @param array $vars 需要单独返送的GET变量 
  679. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  680. *         或单一的一条类似于 'Host: example.com' 头信息字符串 
  681. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  682. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  683. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  684. * @param array $options 当前操作类一些特殊的属性设置 
  685. * @return unknown 
  686. */ 
  687. public function get($url = ''$vars = array(), $header = array(), $cookie = ''$timeout = 5, $options = array()){ 
  688. $this->setUrl($url); 
  689. $this->setHeader($header); 
  690. $this->setCookie($cookie); 
  691. $this->setVar($vars); 
  692. return $this->send('GET'$timeout); 
  693.  
  694. /** 
  695. * 发送HTTP POST请求 
  696. * 
  697. * @param string $url 如果初始化对象的时候没有设置或者要设置不同的访问URL,可以传本参数 
  698. * @param array $vars 需要单独返送的GET变量 
  699. * @param array/string 需要设置的头信息,可以是一个 类似 array('Host: example.com', 'Accept-Language: zh-cn') 的头信息数组 
  700. *         或单一的一条类似于 'Host: example.com' 头信息字符串 
  701. * @param string/array 需要设置的Cookie信息,一个类似于 'name1=value1&name2=value2' 的Cookie字符串信息, 
  702. *         或者是一个 array('name1'=>'value1', 'name2'=>'value2') 的一维数组 
  703. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  704. * @param array $options 当前操作类一些特殊的属性设置 
  705. * @return unknown 
  706. */ 
  707. public function post($url = ''$vars = array(), $header = array(), $cookie = ''$timeout = 5, $options = array()){ 
  708. $this->setUrl($url); 
  709. $this->setHeader($header); 
  710. $this->setCookie($cookie); 
  711. $this->setVar($vars); 
  712. return $this->send('POST'$timeout); 
  713.  
  714. /** 
  715. * 发送HTTP请求核心函数 
  716. * 
  717. * @param string $method 使用GET还是POST方式访问 
  718. * @param array $vars 需要另外附加发送的GET/POST数据 
  719. * @param int $timeout 连接对方服务器访问超时时间,单位为秒 
  720. * @param array $options 当前操作类一些特殊的属性设置 
  721. * @return string 返回服务器端读取的返回数据 
  722. */ 
  723. public function send($method = 'GET'$timeout = 5, $options = array()){ 
  724. //处理参数是否为空 
  725. if ($this->uri == ''){ 
  726.    throw new Exception(__CLASS__ .": Access url is empty"); 
  727. $parse = parse_url($this->uri); 
  728. $host = $parse['host']; 
  729.  
  730.         //处理GET请求参数 
  731.         if ($method == 'GET' && !emptyempty($this->vars)){ 
  732.          $query = Http::makeQuery($this->vars); 
  733.          $sep = isset($parse['query'])&&($parse['query']!='') ? '&' : '?'
  734.          $this->uri .= $sep . $query
  735.         } 
  736.         
  737.         
  738.         //处理POST请求数据 
  739.         $data = ''
  740.         if ($method == 'POST' && !emptyempty($this->vars)){ 
  741.          $data = Http::makeQuery($this->vars); 
  742.         } 
  743.         
  744.         //设置缺省头 
  745.         $this->setHeader('User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)'); 
  746. if (!preg_match("/^[/d]{1,3}/.[/d]{1,3}/.[/d]{1,3}/.[/d]{1,3}$/"$host)){ 
  747.    $this->setHeader("Host: ".$host); 
  748. if ($this->cookies != ''){ 
  749.    $this->setHeader("Cookie: "$this->cookies); 
  750. $this->setHeader("Connection: Close"); 
  751. //'Accept-Language: zh-cn', 
  752.      //'Cache-Control: no-cache',        
  753.         
  754.         //构造头信息 
  755.         $opts = array
  756.          'http' => array
  757.           'method'   => $method
  758.           'timeout' => $timeout
  759.          ) 
  760.         ); 
  761.         if ($data != ''){ 
  762.          $opts['http']['content'] = $data
  763.         } 
  764.         $opts['http']['header'] = ''
  765.         foreach ($this->header as $h){ 
  766.          $opts['http']['header'] .= $h . "/r/n"
  767.         } 
  768.         //print_r($opts);exit; 
  769.         
  770.         //读取扩展设置选项 
  771.         if (!emptyempty($options)){ 
  772.          isset($options['proxy']) ? $opts['http']['proxy'] = $options['proxy'] : '';         
  773.          isset($options['max_redirects']) ? $opts['http']['max_redirects'] = $options['max_redirects'] : ''
  774.          isset($options['request_fulluri']) ? $opts['http']['request_fulluri'] = $options['request_fulluri'] : ''
  775.         } 
  776.         
  777.         //发送数据返回 
  778.        $context = stream_context_create($opts); 
  779.        if (($buf = file_get_contents($this->uri, null, $context)) === false){ 
  780.    throw new Exception(__CLASS__ .": file_get_contents("$this->uri .") fail"); 
  781.        } 
  782.        
  783.        return $buf
  784.        
  785.