transport.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <?php
  2. class transport
  3. {
  4. /**
  5. * 脚本执行时间。-1表示采用PHP的默认值。
  6. *
  7. * @access private
  8. * @var integer $time_limit
  9. */
  10. var $time_limit = -1;
  11. /**
  12. * 在多少秒之内,如果连接不可用,脚本就停止连接。-1表示采用PHP的默认值。
  13. *
  14. * @access private
  15. * @var integer $connect_timeout
  16. */
  17. var $connect_timeout = -1;
  18. /**
  19. * 连接后,限定多少秒超时。-1表示采用PHP的默认值。此项仅当采用CURL库时启用。
  20. *
  21. * @access private
  22. * @var integer $stream_timeout
  23. */
  24. var $stream_timeout = -1;
  25. /**
  26. * 是否使用CURL库来连接。false表示采用fsockopen进行连接。
  27. *
  28. * @access private
  29. * @var boolean $use_curl
  30. */
  31. var $use_curl = true;
  32. /**
  33. * 构造函数
  34. *
  35. * @access public
  36. * @param integer $time_limit
  37. * @param integer $connect_timeout
  38. * @param integer $stream_timeout
  39. * @param boolean $use_curl
  40. * @return void
  41. */
  42. function __construct($time_limit = -1, $connect_timeout = -1, $stream_timeout = -1, $use_curl = false)
  43. {
  44. //$this->transport($time_limit, $connect_timeout, $stream_timeout, $use_curl);
  45. $this->time_limit = $time_limit;
  46. $this->connect_timeout = $connect_timeout;
  47. $this->stream_timeout = $stream_timeout;
  48. $this->use_curl = $use_curl;
  49. }
  50. /**
  51. * 请求远程服务器
  52. *
  53. * @access public
  54. * @param string $url 远程服务器的URL
  55. * @param mix $params 查询参数,形如bar=foo&foo=bar;或者是一维关联数组,形如array('a'=>'aa',...)
  56. * @param string $method 请求方式,是POST还是GET
  57. * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...)
  58. * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'),
  59. * 重大错误程序直接停止运行,否则返回false。
  60. */
  61. function request($url, $params = '', $method = 'POST', $my_header = '')
  62. {
  63. $fsock_exists = function_exists('fsockopen');
  64. $curl_exists = function_exists('curl_init');
  65. if (!$fsock_exists && !$curl_exists)
  66. {
  67. die('No method available!');
  68. }
  69. if (!$url)
  70. {
  71. die('Invalid url!');
  72. }
  73. if ($this->time_limit > -1)//如果为0,不限制执行时间
  74. {
  75. set_time_limit($this->time_limit);
  76. }
  77. $method = $method === 'GET' ? $method : 'POST';
  78. $response = '';
  79. $temp_str = '';
  80. /* 格式化将要发要送的参数 */
  81. if ($params && is_array($params))
  82. {
  83. foreach ($params AS $key => $value)
  84. {
  85. $temp_str .= '&' . $key . '=' . $value;
  86. }
  87. $params = preg_replace('/^&/', '', $temp_str);
  88. }
  89. if ($curl_exists)
  90. {
  91. $response = $this->use_curl($url, $params, $method, $my_header);
  92. }
  93. /* 空响应或者传输过程中发生错误,程序将返回false */
  94. if (!$response)
  95. {
  96. return false;
  97. }
  98. return $response;
  99. }
  100. /**
  101. * 使用fsockopen进行连接
  102. *
  103. * @access private
  104. * @param string $url 远程服务器的URL
  105. * @param string $params 查询参数,形如bar=foo&foo=bar
  106. * @param string $method 请求方式,是POST还是GET
  107. * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...)
  108. * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'),
  109. * 否则返回false。
  110. */
  111. function use_socket($url, $params, $method, $my_header)
  112. {
  113. $query = '';
  114. $auth = '';
  115. $content_type = '';
  116. $content_length = '';
  117. $request_body = '';
  118. $request = '';
  119. $http_response = '';
  120. $temp_str = '';
  121. $error = '';
  122. $errstr = '';
  123. $crlf = $this->generate_crlf();
  124. if ($method === 'GET')
  125. {
  126. $query = $params ? "?$params" : '';
  127. }
  128. else
  129. {
  130. $request_body = $params;
  131. $content_type = 'Content-Type: application/x-www-form-urlencoded' . $crlf;
  132. $content_length = 'Content-Length: ' . strlen($request_body) . $crlf . $crlf;
  133. }
  134. $url_parts = $this->parse_raw_url($url);
  135. $path = $url_parts['path'] . $query;
  136. if (!empty($url_parts['user']))
  137. {
  138. $auth = 'Authorization: Basic '
  139. . base64_encode($url_parts['user'] . ':' . $url_parts['pass']) . $crlf;
  140. }
  141. /* 格式化自定义头部信息 */
  142. if ($my_header && is_array($my_header))
  143. {
  144. foreach ($my_header AS $key => $value)
  145. {
  146. $temp_str .= $key . ': ' . $value . $crlf;
  147. }
  148. $my_header = $temp_str;
  149. }
  150. /* 构造HTTP请求头部 */
  151. $request = "$method $path HTTP/1.0$crlf"
  152. . 'Host: ' . $url_parts['host'] . $crlf
  153. . $auth
  154. . $my_header
  155. . $content_type
  156. . $content_length
  157. . $request_body;
  158. if ($this->connect_timeout > -1)
  159. {
  160. $fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr, $connect_timeout);
  161. }
  162. else
  163. {
  164. $fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr);
  165. }
  166. if (!$fp)
  167. {
  168. return false;//打开失败
  169. }
  170. if (!@fwrite($fp, $request))
  171. {
  172. return false;//写入失败
  173. }
  174. while (!feof($fp))
  175. {
  176. $http_response .= fgets($fp);
  177. }
  178. if (!$http_response)
  179. {
  180. return false;//空响应
  181. }
  182. $separator = '/\r\n\r\n|\n\n|\r\r/';
  183. list($http_header, $http_body) = preg_split($separator, $http_response, 2);
  184. $http_response = array('header' => $http_header,//header肯定有值
  185. 'body' => $http_body);//body可能为空
  186. @fclose($fp);
  187. return $http_response;
  188. }
  189. /**
  190. * 使用curl进行连接
  191. *
  192. * @access private
  193. * @param string $url 远程服务器的URL
  194. * @param string $params 查询参数,形如bar=foo&foo=bar
  195. * @param string $method 请求方式,是POST还是GET
  196. * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...)
  197. * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'),
  198. * 失败返回false。
  199. */
  200. function use_curl($url, $params, $method, $my_header)
  201. {
  202. /* 开始一个新会话 */
  203. $curl_session = curl_init();
  204. /* 基本设置 */
  205. curl_setopt($curl_session, CURLOPT_FORBID_REUSE, true); // 处理完后,关闭连接,释放资源
  206. curl_setopt($curl_session, CURLOPT_HEADER, true);//结果中包含头部信息
  207. curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);//把结果返回,而非直接输出
  208. curl_setopt($curl_session, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);//采用1.0版的HTTP协议
  209. $url_parts = $this->parse_raw_url($url);
  210. /* 设置验证策略 */
  211. if (!empty($url_parts['user']))
  212. {
  213. $auth = $url_parts['user'] . ':' . $url_parts['pass'];
  214. curl_setopt($curl_session, CURLOPT_USERPWD, $auth);
  215. curl_setopt($curl_session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  216. }
  217. $header = array();
  218. /* 设置主机 */
  219. // $header[] = 'Host: ' . $url_parts['host'];
  220. /* 格式化自定义头部信息 */
  221. if ($my_header && is_array($my_header))
  222. {
  223. foreach ($my_header AS $key => $value)
  224. {
  225. $header[] = $key . ': ' . $value;
  226. }
  227. }
  228. if ($method === 'GET')
  229. {
  230. curl_setopt($curl_session, CURLOPT_HTTPGET, true);
  231. $url .= $params ? '?' . $params : '';
  232. }
  233. else
  234. {
  235. curl_setopt($curl_session, CURLOPT_POST, true);
  236. $header[] = 'Content-Type: application/x-www-form-urlencoded';
  237. $header[] = 'Content-Length: ' . strlen($params);
  238. curl_setopt($curl_session, CURLOPT_POSTFIELDS, $params);
  239. }
  240. /* 设置请求地址 */
  241. curl_setopt($curl_session, CURLOPT_URL, $url);
  242. /* 设置头部信息 */
  243. //print_r($header);exit;
  244. curl_setopt($curl_session, CURLOPT_HTTPHEADER, $header);
  245. if ($this->connect_timeout > -1)
  246. {
  247. curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
  248. }
  249. if ($this->stream_timeout > -1)
  250. {
  251. curl_setopt($curl_session, CURLOPT_TIMEOUT, $this->stream_timeout);
  252. }
  253. /* 发送请求 */
  254. $http_response = curl_exec($curl_session);
  255. if (curl_errno($curl_session) != 0)
  256. {
  257. return false;
  258. }
  259. $separator = '/\r\n\r\n|\n\n|\r\r/';
  260. list($http_header, $http_body) = preg_split($separator, $http_response, 2);
  261. $http_response = array('header' => $http_header,//肯定有值
  262. 'body' => $http_body); //可能为空
  263. curl_close($curl_session);
  264. return $http_response;
  265. }
  266. /**
  267. * Similar to PHP's builtin parse_url() function, but makes sure what the schema,
  268. * path and port keys are set to http, /, 80 respectively if they're missing
  269. *
  270. * @access private
  271. * @param string $raw_url Raw URL to be split into an array
  272. * @author http://www.cpaint.net/
  273. * @return array
  274. */
  275. function parse_raw_url($raw_url)
  276. {
  277. $retval = array();
  278. $raw_url = (string) $raw_url;
  279. // make sure parse_url() recognizes the URL correctly.
  280. if (strpos($raw_url, '://') === false)
  281. {
  282. $raw_url = 'http://' . $raw_url;
  283. }
  284. // split request into array
  285. $retval = parse_url($raw_url);
  286. // make sure a path key exists
  287. if (!isset($retval['path']))
  288. {
  289. $retval['path'] = '/';
  290. }
  291. // set port to 80 if none exists
  292. if (!isset($retval['port']))
  293. {
  294. $retval['port'] = '80';
  295. }
  296. return $retval;
  297. }
  298. /**
  299. * 产生一个换行符,不同的操作系统会有不同的换行符
  300. *
  301. * @access private
  302. * @return string 用双引号引用的换行符
  303. */
  304. function generate_crlf()
  305. {
  306. $crlf = '';
  307. if (strtoupper(substr(PHP_OS, 0, 3) === 'WIN'))
  308. {
  309. $crlf = "\r\n";
  310. }
  311. elseif (strtoupper(substr(PHP_OS, 0, 3) === 'MAC'))
  312. {
  313. $crlf = "\r";
  314. }
  315. else
  316. {
  317. $crlf = "\n";
  318. }
  319. return $crlf;
  320. }
  321. }
  322. ?>