ToolService.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. <?php
  2. namespace app\common\service;
  3. use think\Log;
  4. use think\Env;
  5. use GuzzleHttp\Client;
  6. use GuzzleHttp\Exception\RequestException;
  7. use GuzzleHttp\Exception\TransferException;
  8. class ToolService
  9. {
  10. /**
  11. * get请求
  12. * @param $url
  13. * @param array $queryData
  14. * @param array $headers
  15. * @param bool $json
  16. * @return mixed|string
  17. */
  18. public static function httpGet($url, $queryData = [], $headers = [], $json = true)
  19. {
  20. try {
  21. $client = new Client(['timeout' => 10]);
  22. $response = $client->request('GET', $url, array_filter([
  23. 'query' => $queryData,
  24. 'headers' => $headers,
  25. 'verify' => false
  26. ]));
  27. $body = (string)$response->getBody();
  28. return $json ? json_decode($body, true) : $body;
  29. } catch (RequestException $e) {
  30. return false;
  31. }
  32. }
  33. /**
  34. * post请求
  35. * @param $url
  36. * @param array $postData
  37. * @param array $headers
  38. * @param bool $json
  39. * @return mixed|string
  40. */
  41. public static function httpPost($url, $postData = [], $headers = [], $json = true)
  42. {
  43. try {
  44. $client = new Client(['timeout' => 10]);
  45. $response = $client->request('POST', $url, array_filter([
  46. 'form_params' => $postData,
  47. 'headers' => $headers,
  48. 'verify' => false
  49. ]));
  50. $body = (string)$response->getBody();
  51. return $json ? json_decode($body, true) : $body;
  52. } catch (RequestException $e) {
  53. Log::info('httpPost-error:' . $e->getMessage());
  54. return false;
  55. }
  56. }
  57. /**
  58. * @param $method
  59. * @param $url
  60. * @param array $data
  61. * @param array $headers
  62. * @param bool $jsonRequest
  63. * @param bool $jsonDecode
  64. * @return mixed|string
  65. * @throws \Exception
  66. * @throws \GuzzleHttp\Exception\GuzzleException
  67. */
  68. public static function httpRequest($method, $url, $data = [], $headers = [], $jsonRequest = false, $jsonDecode = true)
  69. {
  70. try {
  71. $method = strtoupper($method);
  72. $client = new Client(['verify' => false]);
  73. $methodMap = [
  74. 'GET' => 'query',
  75. 'POST' => 'form_params',
  76. ];
  77. $type = $jsonRequest ? 'json' : $methodMap[$method] ?? 'query';
  78. $param = [$type => $data];
  79. if ($headers) {
  80. $param['headers'] = $headers;
  81. }
  82. $response = $client->request($method, $url, $param);
  83. $body = (string)$response->getBody();
  84. return $jsonDecode ? json_decode($body, true) : $body;
  85. } catch (TransferException $e) {
  86. throw new \Exception($e->getMessage(), $e->getCode());
  87. }
  88. }
  89. /**
  90. * 输出xml字符
  91. * @param $values
  92. * @return string
  93. * @throws \Exception
  94. */
  95. public static function ToXml($values)
  96. {
  97. if (!is_array($values) || count($values) <= 0) {
  98. throw new \Exception("数组数据异常!");
  99. }
  100. $xml = "<xml>";
  101. foreach ($values as $key => $val) {
  102. if (is_numeric($val)) {
  103. $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
  104. } else {
  105. $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
  106. }
  107. }
  108. $xml .= "</xml>";
  109. return $xml;
  110. }
  111. /**
  112. * 将xml转为array
  113. * @param $xml
  114. * @return mixed
  115. * @throws \Exception
  116. */
  117. public static function FromXml($xml)
  118. {
  119. if (!$xml) {
  120. throw new \Exception("xml数据异常!");
  121. }
  122. //将XML转为array
  123. //禁止引用外部xml实体
  124. libxml_disable_entity_loader(true);
  125. $values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
  126. return $values;
  127. }
  128. /**
  129. * 格式化参数格式化成url参数
  130. * @param $values
  131. * @return string
  132. */
  133. public static function ToUrlParams($values)
  134. {
  135. $buff = "";
  136. foreach ($values as $k => $v) {
  137. if ($k != "sign" && $v != "" && !is_array($v)) {
  138. $buff .= $k . "=" . $v . "&";
  139. }
  140. }
  141. $buff = trim($buff, "&");
  142. return $buff;
  143. }
  144. /**
  145. * 生成签名
  146. * @param $values
  147. * @param $key
  148. * @return string
  149. */
  150. public static function MakeSign($values, $key = '')
  151. {
  152. unset($values['sign']);
  153. //签名步骤一:按字典序排序参数
  154. ksort($values);
  155. $string = self::ToUrlParams($values);
  156. //签名步骤二:在string后加入KEY
  157. !$key && $key = Env::get('wechat.api_key');
  158. $string = $string . "&key=" . $key;
  159. //签名步骤三:MD5加密或者HMAC-SHA256
  160. if (isset($values['sign_type']) && $values['sign_type'] == 'HMAC-SHA256') {
  161. $sign = hash_hmac("sha256", $string, $key);
  162. } else {
  163. $sign = md5($string);
  164. }
  165. //签名步骤四:所有字符转为大写
  166. $result = strtoupper($sign);
  167. Log::info('通用工具签名-MakeSign:' . json_encode(['values' => $values, 'string' => $string, 'sign' => $sign]));
  168. return $result;
  169. }
  170. /**
  171. * 验证签名是否正确
  172. * @param $values
  173. * @param $sign
  174. * @param $key
  175. * @return bool
  176. */
  177. public static function CheckSign($values, $sign, $key = '')
  178. {
  179. $localSign = self::MakeSign($values, $key);
  180. Log::info('通用工具签名信息-Tool-CheckSign' . json_encode(['data' => $values, 'sign' => $sign, 'localSign' => $localSign]));
  181. if ($localSign == $sign) {
  182. //签名正确
  183. return true;
  184. }
  185. return false;
  186. }
  187. /**
  188. * 打包签名数据
  189. * @param $values
  190. * @return mixed
  191. */
  192. public static function packSign($values)
  193. {
  194. if (!isset($values['nonce_str'])) {
  195. $values['nonce_str'] = uniqid();
  196. }
  197. if (!isset($values['time_stamp'])) {
  198. $values['time_stamp'] = time();
  199. }
  200. //签名步骤四:所有字符转为大写
  201. $values['sign'] = self::MakeSign($values, Env::get('app.token_key'));
  202. return $values;
  203. }
  204. /**
  205. * @param $array
  206. * @return mixed
  207. */
  208. public static function changeArrayKey($array)
  209. {
  210. foreach ($array as &$value) {
  211. if (isset($value['name'])) {
  212. $value['text'] = $value['name'];
  213. unset($value['name']);
  214. }
  215. if (isset($value['subItems'])) {
  216. foreach ($value['subItems'] as &$v) {
  217. $v['text'] = $v['name'];
  218. unset($v['name']);
  219. }
  220. $value['children'] = $value['subItems'];
  221. unset($value['subItems']);
  222. }
  223. }
  224. return $array;
  225. }
  226. /**
  227. * 解析字符串数组
  228. * @param $string
  229. * @param $data
  230. * @return mixed
  231. */
  232. public static function parseArrStr($string, $data)
  233. {
  234. $fieldArr = explode('.', str_replace(['{', '}'], '', $string));
  235. foreach ($fieldArr as $field) {
  236. $data = $data[$field] ?? '';
  237. }
  238. return $data;
  239. }
  240. /**
  241. * @param $value
  242. * @param $data
  243. * @return string
  244. */
  245. public static function parseTempData($value, $data)
  246. {
  247. if (preg_match_all('/\{.*?\}/', $value, $matches)) {
  248. $str = '';
  249. foreach ($matches as $match){
  250. $str .= ToolService::parseArrStr($match, $data);
  251. }
  252. $value = $str;
  253. }
  254. return $value;
  255. }
  256. /**
  257. * 获取请求缓存Key
  258. * @param $url
  259. * @param $param
  260. * @return mixed
  261. */
  262. public static function httpCacheKey($url, $param)
  263. {
  264. $query = http_build_query($param);
  265. $parse = parse_url($url);
  266. $urls = implode(':', ['http-cache', $parse['host'], $parse['path'], $query]);
  267. $key = preg_replace('/[^a-zA-Z0-9_\-:]/', '', $urls);
  268. return $key;
  269. }
  270. /**
  271. * 递归实现无限极分类
  272. * @param array $array 分类数据
  273. * @param int $pid 父ID
  274. * @param int $level 分类级别
  275. * @return array 分好类的数组 直接遍历即可 $level可以用来遍历缩进
  276. */
  277. public static function getTree($array, $pid = 0, $level = 0)
  278. {
  279. //声明静态数组,避免递归调用时,多次声明导致数组覆盖
  280. static $list = [];
  281. foreach ($array as $key => $value) {
  282. //第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点
  283. if ($value['parent_id'] == $pid) {
  284. //父节点为根节点的节点,级别为0,也就是第一级
  285. $value['level'] = $level;
  286. $value['name'] = str_repeat('--', $level) . $value['name'];
  287. //把数组放到list中
  288. $list[] = $value;
  289. //把这个节点从数组中移除,减少后续递归消耗
  290. unset($array[$key]);
  291. //开始递归,查找父ID为该节点ID的节点,级别则为原级别+1
  292. self::getTree($array, $value['id'], $level + 1);
  293. }
  294. }
  295. return $list;
  296. }
  297. }