Http.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. namespace Easemob\Http;
  3. /**
  4. * Http 请求类
  5. * @final
  6. */
  7. final class Http
  8. {
  9. /**
  10. * @var string $proxyIp 代理 ip
  11. */
  12. public static $proxyIp;
  13. /**
  14. * @var string $proxyPort 代理端口
  15. */
  16. public static $proxyPort;
  17. /**
  18. * @var string $proxyUser 代理用户名
  19. */
  20. public static $proxyUser;
  21. /**
  22. * @var string $proxyUser 代理密码
  23. */
  24. public static $proxyPass;
  25. /**
  26. * 设置代理信息
  27. * @param string $proxyIp 代理 ip
  28. * @param int $proxyPort 代理端口
  29. * @param string $proxyUser 代理用户名
  30. * @param string $proxyPass 代理密码
  31. * @example
  32. * <pre>
  33. * \Easemob\Http\Http::setProxy("ip", 8080);
  34. * </pre>
  35. */
  36. public static function setProxy($proxyIp, $proxyPort = 80, $proxyUser = '', $proxyPass = '')
  37. {
  38. self::$proxyIp = $proxyIp;
  39. self::$proxyPort = $proxyPort;
  40. self::$proxyUser = $proxyUser;
  41. self::$proxyPass = $proxyPass;
  42. }
  43. /**
  44. * @ignore 发送 get 请求
  45. * @param string $uri 请求 uri
  46. * @param mixed $headers 请求头
  47. * @return Response 响应对象
  48. */
  49. public static function get($uri, $headers = null)
  50. {
  51. return self::send(new Request('GET', $uri, $headers));
  52. }
  53. /**
  54. * @ignore 发送 post 请求
  55. * @param string $uri 请求 uri
  56. * @param mixed $body 请求体
  57. * @param mixed $headers 请求头
  58. * @return Response 响应对象
  59. */
  60. public static function post($uri, $body, $headers = null)
  61. {
  62. return self::send(new Request('POST', $uri, $headers, $body));
  63. }
  64. /**
  65. * @ignore 发送 put 请求
  66. * @param string $uri 请求 uri
  67. * @param mixed $body 请求体
  68. * @param mixed $headers 请求头
  69. * @return Response 响应对象
  70. */
  71. public static function put($uri, $body, $headers = null)
  72. {
  73. return self::send(new Request('PUT', $uri, $headers, $body));
  74. }
  75. /**
  76. * @ignore 发送 delete 请求
  77. * @param string $uri 请求 uri
  78. * @param mixed $headers 请求头
  79. * @return Response 响应对象
  80. */
  81. public static function delete($uri, $body, $headers = null)
  82. {
  83. return self::send(new Request('DELETE', $uri, $headers, $body));
  84. }
  85. /**
  86. * @ignore 发送 http 请求
  87. * @param Request $request 请求信息
  88. * @return Response 响应对象
  89. */
  90. public static function send($request)
  91. {
  92. $startTime = microtime(true);
  93. $ch = curl_init();
  94. $options = array(
  95. CURLOPT_RETURNTRANSFER => true, // 将 curl_exec() 获取的信息以字符串返回,而不是直接输出。
  96. CURLOPT_SSL_VERIFYPEER => false, // 禁止 cURL 验证证书
  97. CURLOPT_SSL_VERIFYHOST => false, // 不检查服务器SSL证书名称
  98. CURLOPT_HEADER => true, // 将头文件的信息作为数据流输出
  99. CURLOPT_NOBODY => false, // true 时将不输出 BODY 部分。同时 Mehtod 变成了 HEAD。修改为 false 时不会变成 GET。
  100. CURLOPT_CUSTOMREQUEST => $request->method, // 请求方法
  101. CURLOPT_URL => $request->uri, // 请求地址
  102. CURLOPT_USERAGENT => 'EasemobServerSDK-PHP/' . PHP_VERSION,
  103. );
  104. if (!empty($request->headers)) {
  105. if (!isset($request->headers['Content-Type']) || !$request->headers['Content-Type']) {
  106. $request->headers['Content-Type'] = (!$request->body || is_array($request->body)) ? 'application/json' : 'application/x-www-form-urlencoded';
  107. }
  108. $options[CURLOPT_HTTPHEADER] = self::buildHeaders($request->headers);
  109. }
  110. if (!empty($request->body)) {
  111. $request->body = is_array($request->body) ? json_encode($request->body) : $request->body;
  112. $options[CURLOPT_POSTFIELDS] = $request->body;
  113. }
  114. if (self::$proxyIp && self::$proxyPort) {
  115. $options[CURLOPT_PROXY] = self::$proxyIp;
  116. $options[CURLOPT_PROXYPORT] = self::$proxyPort;
  117. if (self::$proxyUser && self::$proxyPass) {
  118. $options[CURLOPT_PROXYUSERPWD] = self::$proxyUser .':'. self::$proxyPass;
  119. }
  120. }
  121. curl_setopt_array($ch, $options);
  122. $result = curl_exec($ch);
  123. $endTime = microtime(true);
  124. $duration = $endTime - $startTime;
  125. $code = curl_errno($ch);
  126. if ($code !== 0) {
  127. $response = new Response(-1, $duration, null, null, curl_error($ch));
  128. curl_close($ch);
  129. return $response;
  130. }
  131. $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  132. $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
  133. $headers = self::parseHeaders(substr($result, 0, $headerSize));
  134. $body = substr($result, $headerSize);
  135. curl_close($ch);
  136. return new Response($code, $duration, $headers, $body, null);
  137. }
  138. /**
  139. * @ignore 发送上传附件请求
  140. * @param string $uri 请求 uri
  141. * @param string $fileName 附件名
  142. * @param array $fileBody 附件信息
  143. * @param mixed $mimeType 附件 mime 类型
  144. * @param array $headers 请求头
  145. * @return Response 响应对象
  146. */
  147. public static function multipartPost(
  148. $uri,
  149. $fileName,
  150. $fileBody,
  151. $mimeType = null,
  152. $headers = array()
  153. ) {
  154. $data = array();
  155. $mimeBoundary = md5(microtime());
  156. array_push($data, '--' . $mimeBoundary);
  157. $finalMimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType;
  158. $finalFileName = self::escapeQuotes($fileName);
  159. array_push($data, "Content-Disposition: form-data; name=\"file\"; filename=\"$finalFileName\"");
  160. array_push($data, "Content-Type: $finalMimeType");
  161. array_push($data, '');
  162. array_push($data, $fileBody);
  163. array_push($data, '--' . $mimeBoundary . '--');
  164. array_push($data, '');
  165. $body = implode("\r\n", $data);
  166. $contentType = 'multipart/form-data; boundary=' . $mimeBoundary;
  167. $headers['Content-Type'] = $contentType;
  168. $headers['restrict-access'] = true;
  169. return self::send(new Request('POST', $uri, $headers, $body));
  170. }
  171. /**
  172. * @ignore 构造请求头信息
  173. * @param array $headers 请求头信息
  174. * @return array 请求头信息
  175. */
  176. private static function buildHeaders($headers)
  177. {
  178. $headersArr = array();
  179. foreach ($headers as $key => $value) {
  180. array_push($headersArr, "{$key}: {$value}");
  181. }
  182. return $headersArr;
  183. }
  184. /**
  185. * @ignore 解析请求头信息
  186. * @param string $headersRaw 请求头原始字符串
  187. * @return array 请求头信息
  188. */
  189. private static function parseHeaders($headersRaw)
  190. {
  191. $headers = array();
  192. $lines = explode("\r\n", $headersRaw);
  193. foreach ($lines as $line) {
  194. $item = explode(':', $line);
  195. if (trim($item[0])) {
  196. $headers[$item[0]] = isset($item[1]) ? trim($item[1]) : '';
  197. }
  198. }
  199. return $headers;
  200. }
  201. /**
  202. * @ignore 替换引号
  203. * @param string $str 原始字符串
  204. * @return string 替换之后的字符串
  205. */
  206. private static function escapeQuotes($str)
  207. {
  208. $find = array("\\", "\"");
  209. $replace = array("\\\\", "\\\"");
  210. return str_replace($find, $replace, $str);
  211. }
  212. }