HttpResponse.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. namespace loyalsoft\Util;
  3. class HttpResponse
  4. {
  5. /**
  6. * CURL操作对象,`curl_init()`的返回值
  7. * @var resource
  8. */
  9. public $handler;
  10. /**
  11. * 请求返回结果,包含返回头和返回主体
  12. * @var string
  13. */
  14. public $response;
  15. /**
  16. * 返回头, 最后一次请求的返回头
  17. * @var array
  18. */
  19. public $headers = array();
  20. /**
  21. * 返回头, 包含中间所有请求(即包含重定向)的返回头
  22. * @var array
  23. */
  24. public $allHeaders = array();
  25. /**
  26. * Cookie
  27. * @var array
  28. */
  29. public $cookies = array();
  30. /**
  31. * 头部内容
  32. * @var string
  33. */
  34. public $headerContent = '';
  35. /**
  36. * 返回结果
  37. * @var string
  38. */
  39. public $body = '';
  40. /**
  41. * 是否请求成功
  42. * @var boolean
  43. */
  44. public $success;
  45. /**
  46. * 构造方法
  47. */
  48. public function __construct($handler, $response)
  49. {
  50. $this->handler = $handler;
  51. $this->response = $response;
  52. $this->success = false !== $response;
  53. $this->parseResponse();
  54. }
  55. /**
  56. * 获取返回的主体内容
  57. * @param string $fromEncoding 请求返回数据的编码,如果不为空则进行编码转换
  58. * @param string $toEncoding 要转换到的编码,默认为UTF-8
  59. * @return void
  60. */
  61. public function body($fromEncoding = null, $toEncoding = 'UTF-8')
  62. {
  63. if (null === $fromEncoding) {
  64. return $this->body;
  65. } else {
  66. return mb_convert_encoding($this->body, $toEncoding, $fromEncoding);
  67. }
  68. }
  69. /**
  70. * 获取xml格式内容
  71. * @param boolean $assoc 为true时返回数组,为false时返回对象
  72. * @param string $fromEncoding 请求返回数据的编码,如果不为空则进行编码转换
  73. * @param string $toEncoding 要转换到的编码,默认为UTF-8
  74. * @return mixed
  75. */
  76. public function xml($assoc = false, $fromEncoding = null, $toEncoding = 'UTF-8')
  77. {
  78. $xml = simplexml_load_string($this->body($fromEncoding, $toEncoding), null, LIBXML_NOCDATA | LIBXML_COMPACT);
  79. if ($assoc) {
  80. $xml = (array) $xml;
  81. }
  82. return $xml;
  83. }
  84. /**
  85. * 获取json格式内容
  86. * @param boolean $assoc 为true时返回数组,为false时返回对象
  87. * @param string $fromEncoding 请求返回数据的编码,如果不为空则进行编码转换
  88. * @param string $toEncoding 要转换到的编码,默认为UTF-8
  89. * @return mixed
  90. */
  91. public function json($assoc = false, $fromEncoding = null, $toEncoding = 'UTF-8')
  92. {
  93. return json_decode($this->body($fromEncoding, $toEncoding), $assoc);
  94. }
  95. /**
  96. * 获取jsonp格式内容
  97. * @param boolean $assoc 为true时返回数组,为false时返回对象
  98. * @param string $fromEncoding 请求返回数据的编码,如果不为空则进行编码转换
  99. * @param string $toEncoding 要转换到的编码,默认为UTF-8
  100. * @return mixed
  101. */
  102. public function jsonp($assoc = false, $fromEncoding = null, $toEncoding = 'UTF-8')
  103. {
  104. $jsonp = trim($this->body($fromEncoding, $toEncoding));
  105. if (isset($jsonp[0]) && $jsonp[0] !== '[' && $jsonp[0] !== '{') {
  106. $begin = strpos($jsonp, '(');
  107. if (false !== $begin) {
  108. $end = strrpos($jsonp, ')');
  109. if (false !== $end) {
  110. $jsonp = substr($jsonp, $begin + 1, $end - $begin - 1);
  111. }
  112. }
  113. }
  114. return json_decode($jsonp, $assoc);
  115. }
  116. /**
  117. * 获取http状态码
  118. * @return int
  119. */
  120. public function httpCode()
  121. {
  122. return curl_getinfo($this->handler, CURLINFO_HTTP_CODE);
  123. }
  124. /**
  125. * 获取请求总耗时,单位:秒
  126. * @return int
  127. */
  128. public function totalTime()
  129. {
  130. return curl_getinfo($this->handler, CURLINFO_TOTAL_TIME);
  131. }
  132. /**
  133. * 处理
  134. */
  135. protected function parseResponse()
  136. {
  137. // 分离header和body
  138. $headerSize = curl_getinfo($this->handler, CURLINFO_HEADER_SIZE);
  139. $this->headerContent = substr($this->response, 0, $headerSize);
  140. $this->body = substr($this->response, $headerSize);
  141. // PHP 7.0.0开始substr()的 string 字符串长度与 start 相同时将返回一个空字符串。在之前的版本中,这种情况将返回 FALSE 。
  142. if (false === $this->body) {
  143. $this->body = '';
  144. }
  145. $this->parseHeader();
  146. $this->parseCookie();
  147. }
  148. /**
  149. * 处理header
  150. */
  151. protected function parseHeader()
  152. {
  153. $rawHeaders = explode("\r\n\r\n", trim($this->headerContent), 2);
  154. $requestCount = count($rawHeaders);
  155. for ($i = 0; $i < $requestCount; ++$i) {
  156. $this->allHeaders[] = $this->parseHeaderOneRequest($rawHeaders[$i]);
  157. }
  158. if ($requestCount > 0)
  159. $this->headers = $this->allHeaders[$requestCount - 1];
  160. }
  161. /**
  162. * parseHeaderOneRequest
  163. * @param string $piece
  164. * @return array
  165. */
  166. protected function parseHeaderOneRequest($piece)
  167. {
  168. $tmpHeaders = array();
  169. $lines = explode("\r\n", $piece);
  170. $linesCount = count($lines);
  171. //从1开始,第0行包含了协议信息和状态信息,排除该行
  172. for ($i = 1; $i < $linesCount; ++$i) {
  173. $line = trim($lines[$i]);
  174. if (empty($line) || strstr($line, ':') == false)
  175. continue;
  176. list($key, $value) = explode(':', $line, 2);
  177. $key = trim($key);
  178. $value = trim($value);
  179. if (isset($tmpHeaders[$key])) {
  180. if (is_array($tmpHeaders[$key])) {
  181. $tmpHeaders[$key][] = $value;
  182. } else {
  183. $tmp = $tmpHeaders[$key];
  184. $tmpHeaders[$key] = array(
  185. $tmp,
  186. $value
  187. );
  188. }
  189. } else {
  190. $tmpHeaders[$key] = $value;
  191. }
  192. }
  193. return $tmpHeaders;
  194. }
  195. /**
  196. * 处理cookie
  197. */
  198. protected function parseCookie()
  199. {
  200. $count = preg_match_all('/set-cookie\s*:\s*([^\r\n]+)/i', $this->headerContent, $matches);
  201. for ($i = 0; $i < $count; ++$i) {
  202. $list = explode(';', $matches[1][$i]);
  203. $count2 = count($list);
  204. if (isset($list[0])) {
  205. list($cookieName, $value) = explode('=', $list[0], 2);
  206. $cookieName = trim($cookieName);
  207. $this->cookies[$cookieName] = array('value' => $value);
  208. for ($j = 1; $j < $count2; ++$j) {
  209. $kv = explode('=', $list[$j], 2);
  210. $this->cookies[$cookieName][trim($kv[0])] = isset($kv[1]) ? $kv[1] : true;
  211. }
  212. }
  213. }
  214. }
  215. /**
  216. * 返回当前会话最后一次错误的字符串
  217. * @return string
  218. */
  219. public function error()
  220. {
  221. return curl_error($this->handler);
  222. }
  223. /**
  224. * 返回最后一次的错误代码
  225. * @return int
  226. */
  227. public function errno()
  228. {
  229. return curl_errno($this->handler);
  230. }
  231. }