transport.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. <?php
  2. class transport_sms
  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 = false;
  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. /* 如果fsockopen存在,且用户不指定使用curl,则调用use_socket函数 */
  90. if ($fsock_exists && !$this->use_curl)
  91. {
  92. $response = $this->use_socket($url, $params, $method, $my_header);
  93. }
  94. /* 只要上述条件中的任一个不成立,流程就转向这里,这时如果curl模块可用,就调用use_curl函数 */
  95. elseif ($curl_exists)
  96. {
  97. $response = $this->use_curl($url, $params, $method, $my_header);
  98. }
  99. /* 空响应或者传输过程中发生错误,程序将返回false */
  100. if (!$response)
  101. {
  102. return false;
  103. }
  104. return $response;
  105. }
  106. /**
  107. * 使用fsockopen进行连接
  108. *
  109. * @access private
  110. * @param string $url 远程服务器的URL
  111. * @param string $params 查询参数,形如bar=foo&foo=bar
  112. * @param string $method 请求方式,是POST还是GET
  113. * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...)
  114. * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'),
  115. * 否则返回false。
  116. */
  117. function use_socket($url, $params, $method, $my_header)
  118. {
  119. $query = '';
  120. $auth = '';
  121. $content_type = '';
  122. $content_length = '';
  123. $request_body = '';
  124. $request = '';
  125. $http_response = '';
  126. $temp_str = '';
  127. $error = '';
  128. $errstr = '';
  129. $crlf = $this->generate_crlf();
  130. if ($method === 'GET')
  131. {
  132. $query = $params ? "?$params" : '';
  133. }
  134. else
  135. {
  136. $request_body = $params;
  137. $content_type = 'Content-Type: application/x-www-form-urlencoded' . $crlf;
  138. $content_length = 'Content-Length: ' . strlen($request_body) . $crlf . $crlf;
  139. }
  140. $url_parts = $this->parse_raw_url($url);
  141. $path = $url_parts['path'] . $query;
  142. if (!empty($url_parts['user']))
  143. {
  144. $auth = 'Authorization: Basic '
  145. . base64_encode($url_parts['user'] . ':' . $url_parts['pass']) . $crlf;
  146. }
  147. /* 格式化自定义头部信息 */
  148. if ($my_header && is_array($my_header))
  149. {
  150. foreach ($my_header AS $key => $value)
  151. {
  152. $temp_str .= $key . ': ' . $value . $crlf;
  153. }
  154. $my_header = $temp_str;
  155. }
  156. /* 构造HTTP请求头部 */
  157. $request = "$method $path HTTP/1.0$crlf"
  158. . 'Host: ' . $url_parts['host'] . $crlf
  159. . $auth
  160. . $my_header
  161. . $content_type
  162. . $content_length
  163. . $request_body;
  164. if ($this->connect_timeout > -1)
  165. {
  166. $fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr, $connect_timeout);
  167. }
  168. else
  169. {
  170. $fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr);
  171. }
  172. if (!$fp)
  173. {
  174. return false;//打开失败
  175. }
  176. if (!@fwrite($fp, $request))
  177. {
  178. return false;//写入失败
  179. }
  180. while (!feof($fp))
  181. {
  182. $http_response .= fgets($fp);
  183. }
  184. if (!$http_response)
  185. {
  186. return false;//空响应
  187. }
  188. $separator = '/\r\n\r\n|\n\n|\r\r/';
  189. list($http_header, $http_body) = preg_split($separator, $http_response, 2);
  190. $http_response = array('header' => $http_header,//header肯定有值
  191. 'body' => $http_body);//body可能为空
  192. @fclose($fp);
  193. return $http_response;
  194. }
  195. /**
  196. * 使用curl进行连接
  197. *
  198. * @access private
  199. * @param string $url 远程服务器的URL
  200. * @param string $params 查询参数,形如bar=foo&foo=bar
  201. * @param string $method 请求方式,是POST还是GET
  202. * @param array $my_header 用户要发送的头部信息,为一维关联数组,形如array('a'=>'aa',...)
  203. * @return array 成功返回一维关联数组,形如array('header'=>'bar', 'body'=>'foo'),
  204. * 失败返回false。
  205. */
  206. function use_curl($url, $params, $method, $my_header)
  207. {
  208. /* 开始一个新会话 */
  209. $curl_session = curl_init();
  210. /* 基本设置 */
  211. curl_setopt($curl_session, CURLOPT_FORBID_REUSE, true); // 处理完后,关闭连接,释放资源
  212. curl_setopt($curl_session, CURLOPT_HEADER, true);//结果中包含头部信息
  213. curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);//把结果返回,而非直接输出
  214. curl_setopt($curl_session, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);//采用1.0版的HTTP协议
  215. $url_parts = $this->parse_raw_url($url);
  216. /* 设置验证策略 */
  217. if (!empty($url_parts['user']))
  218. {
  219. $auth = $url_parts['user'] . ':' . $url_parts['pass'];
  220. curl_setopt($curl_session, CURLOPT_USERPWD, $auth);
  221. curl_setopt($curl_session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
  222. }
  223. $header = array();
  224. /* 设置主机 */
  225. $header[] = 'Host: ' . $url_parts['host'];
  226. /* 格式化自定义头部信息 */
  227. if ($my_header && is_array($my_header))
  228. {
  229. foreach ($my_header AS $key => $value)
  230. {
  231. $header[] = $key . ': ' . $value;
  232. }
  233. }
  234. if ($method === 'GET')
  235. {
  236. curl_setopt($curl_session, CURLOPT_HTTPGET, true);
  237. $url .= $params ? '?' . $params : '';
  238. }
  239. else
  240. {
  241. curl_setopt($curl_session, CURLOPT_POST, true);
  242. $header[] = 'Content-Type: application/x-www-form-urlencoded';
  243. $header[] = 'Content-Length: ' . strlen($params);
  244. curl_setopt($curl_session, CURLOPT_POSTFIELDS, $params);
  245. }
  246. /* 设置请求地址 */
  247. curl_setopt($curl_session, CURLOPT_URL, $url);
  248. /* 设置头部信息 */
  249. curl_setopt($curl_session, CURLOPT_HTTPHEADER, $header);
  250. if ($this->connect_timeout > -1)
  251. {
  252. curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
  253. }
  254. if ($this->stream_timeout > -1)
  255. {
  256. curl_setopt($curl_session, CURLOPT_TIMEOUT, $this->stream_timeout);
  257. }
  258. /* 发送请求 */
  259. $http_response = curl_exec($curl_session);
  260. if (curl_errno($curl_session) != 0)
  261. {
  262. return false;
  263. }
  264. $separator = '/\r\n\r\n|\n\n|\r\r/';
  265. list($http_header, $http_body) = preg_split($separator, $http_response, 2);
  266. $http_response = array('header' => $http_header,//肯定有值
  267. 'body' => $http_body); //可能为空
  268. curl_close($curl_session);
  269. return $http_response;
  270. }
  271. /**
  272. * Similar to PHP's builtin parse_url() function, but makes sure what the schema,
  273. * path and port keys are set to http, /, 80 respectively if they're missing
  274. *
  275. * @access private
  276. * @param string $raw_url Raw URL to be split into an array
  277. * @author http://www.cpaint.net/
  278. * @return array
  279. */
  280. function parse_raw_url($raw_url)
  281. {
  282. $retval = array();
  283. $raw_url = (string) $raw_url;
  284. // make sure parse_url() recognizes the URL correctly.
  285. if (strpos($raw_url, '://') === false)
  286. {
  287. $raw_url = 'http://' . $raw_url;
  288. }
  289. // split request into array
  290. $retval = parse_url($raw_url);
  291. // make sure a path key exists
  292. if (!isset($retval['path']))
  293. {
  294. $retval['path'] = '/';
  295. }
  296. // set port to 80 if none exists
  297. if (!isset($retval['port']))
  298. {
  299. $retval['port'] = '80';
  300. }
  301. return $retval;
  302. }
  303. /**
  304. * 产生一个换行符,不同的操作系统会有不同的换行符
  305. *
  306. * @access private
  307. * @return string 用双引号引用的换行符
  308. */
  309. function generate_crlf()
  310. {
  311. $crlf = '';
  312. if (strtoupper(substr(PHP_OS, 0, 3) === 'WIN'))
  313. {
  314. $crlf = "\r\n";
  315. }
  316. elseif (strtoupper(substr(PHP_OS, 0, 3) === 'MAC'))
  317. {
  318. $crlf = "\r";
  319. }
  320. else
  321. {
  322. $crlf = "\n";
  323. }
  324. return $crlf;
  325. }
  326. }
  327. ?>