2026-09-17 16:25:31 +08:00
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
namespace app\common\service;
|
|
|
|
|
|
|
|
|
|
|
|
use think\Log;
|
|
|
|
|
|
use think\Env;
|
|
|
|
|
|
use GuzzleHttp\Client;
|
|
|
|
|
|
use GuzzleHttp\Exception\RequestException;
|
|
|
|
|
|
use GuzzleHttp\Exception\TransferException;
|
|
|
|
|
|
|
|
|
|
|
|
class ToolService
|
|
|
|
|
|
{
|
|
|
|
|
|
/**
|
|
|
|
|
|
* get请求
|
|
|
|
|
|
* @param $url
|
|
|
|
|
|
* @param array $queryData
|
|
|
|
|
|
* @param array $headers
|
|
|
|
|
|
* @param bool $json
|
|
|
|
|
|
* @return mixed|string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function httpGet($url, $queryData = [], $headers = [], $json = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
try {
|
|
|
|
|
|
$client = new Client(['timeout' => 10]);
|
|
|
|
|
|
$response = $client->request('GET', $url, array_filter([
|
|
|
|
|
|
'query' => $queryData,
|
|
|
|
|
|
'headers' => $headers,
|
|
|
|
|
|
'verify' => false
|
|
|
|
|
|
]));
|
|
|
|
|
|
$body = (string)$response->getBody();
|
|
|
|
|
|
return $json ? json_decode($body, true) : $body;
|
|
|
|
|
|
} catch (RequestException $e) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* post请求
|
|
|
|
|
|
* @param $url
|
|
|
|
|
|
* @param array $postData
|
|
|
|
|
|
* @param array $headers
|
|
|
|
|
|
* @param bool $json
|
|
|
|
|
|
* @return mixed|string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function httpPost($url, $postData = [], $headers = [], $json = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
try {
|
|
|
|
|
|
$client = new Client(['timeout' => 10]);
|
|
|
|
|
|
$response = $client->request('POST', $url, array_filter([
|
|
|
|
|
|
'form_params' => $postData,
|
|
|
|
|
|
'headers' => $headers,
|
|
|
|
|
|
'verify' => false
|
|
|
|
|
|
]));
|
|
|
|
|
|
$body = (string)$response->getBody();
|
|
|
|
|
|
|
|
|
|
|
|
return $json ? json_decode($body, true) : $body;
|
|
|
|
|
|
} catch (RequestException $e) {
|
|
|
|
|
|
Log::info('httpPost-error:' . $e->getMessage());
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @param $method
|
|
|
|
|
|
* @param $url
|
|
|
|
|
|
* @param array $data
|
|
|
|
|
|
* @param array $headers
|
|
|
|
|
|
* @param bool $jsonRequest
|
|
|
|
|
|
* @param bool $jsonDecode
|
|
|
|
|
|
* @return mixed|string
|
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
|
* @throws \GuzzleHttp\Exception\GuzzleException
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function httpRequest($method, $url, $data = [], $headers = [], $jsonRequest = false, $jsonDecode = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
try {
|
|
|
|
|
|
$method = strtoupper($method);
|
|
|
|
|
|
$client = new Client(['verify' => false]);
|
|
|
|
|
|
$methodMap = [
|
|
|
|
|
|
'GET' => 'query',
|
|
|
|
|
|
'POST' => 'form_params',
|
|
|
|
|
|
];
|
|
|
|
|
|
$type = $jsonRequest ? 'json' : $methodMap[$method] ?? 'query';
|
|
|
|
|
|
$param = [$type => $data];
|
|
|
|
|
|
if ($headers) {
|
|
|
|
|
|
$param['headers'] = $headers;
|
|
|
|
|
|
}
|
|
|
|
|
|
$response = $client->request($method, $url, $param);
|
|
|
|
|
|
$body = (string)$response->getBody();
|
|
|
|
|
|
|
|
|
|
|
|
return $jsonDecode ? json_decode($body, true) : $body;
|
|
|
|
|
|
} catch (TransferException $e) {
|
|
|
|
|
|
throw new \Exception($e->getMessage(), $e->getCode());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 输出xml字符
|
|
|
|
|
|
* @param $values
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function ToXml($values)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!is_array($values) || count($values) <= 0) {
|
|
|
|
|
|
throw new \Exception("数组数据异常!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$xml = "<xml>";
|
|
|
|
|
|
foreach ($values as $key => $val) {
|
|
|
|
|
|
if (is_numeric($val)) {
|
|
|
|
|
|
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$xml .= "</xml>";
|
|
|
|
|
|
return $xml;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 将xml转为array
|
|
|
|
|
|
* @param $xml
|
|
|
|
|
|
* @return mixed
|
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function FromXml($xml)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!$xml) {
|
|
|
|
|
|
throw new \Exception("xml数据异常!");
|
|
|
|
|
|
}
|
|
|
|
|
|
//将XML转为array
|
2026-09-21 14:57:50 +08:00
|
|
|
|
//禁止引用外部xml实体(libxml 2.9+已默认禁用,PHP8起该函数已废弃)
|
|
|
|
|
|
if (PHP_VERSION_ID < 80000) {
|
|
|
|
|
|
libxml_disable_entity_loader(true);
|
|
|
|
|
|
}
|
2026-09-17 16:25:31 +08:00
|
|
|
|
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
|
|
|
|
|
|
return $values;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 格式化参数格式化成url参数
|
|
|
|
|
|
* @param $values
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function ToUrlParams($values)
|
|
|
|
|
|
{
|
|
|
|
|
|
$buff = "";
|
|
|
|
|
|
foreach ($values as $k => $v) {
|
|
|
|
|
|
if ($k != "sign" && $v != "" && !is_array($v)) {
|
|
|
|
|
|
$buff .= $k . "=" . $v . "&";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$buff = trim($buff, "&");
|
|
|
|
|
|
return $buff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 生成签名
|
|
|
|
|
|
* @param $values
|
|
|
|
|
|
* @param $key
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function MakeSign($values, $key = '')
|
|
|
|
|
|
{
|
|
|
|
|
|
unset($values['sign']);
|
|
|
|
|
|
//签名步骤一:按字典序排序参数
|
|
|
|
|
|
ksort($values);
|
|
|
|
|
|
$string = self::ToUrlParams($values);
|
|
|
|
|
|
//签名步骤二:在string后加入KEY
|
|
|
|
|
|
!$key && $key = Env::get('wechat.api_key');
|
|
|
|
|
|
$string = $string . "&key=" . $key;
|
|
|
|
|
|
//签名步骤三:MD5加密或者HMAC-SHA256
|
|
|
|
|
|
if (isset($values['sign_type']) && $values['sign_type'] == 'HMAC-SHA256') {
|
|
|
|
|
|
$sign = hash_hmac("sha256", $string, $key);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$sign = md5($string);
|
|
|
|
|
|
}
|
|
|
|
|
|
//签名步骤四:所有字符转为大写
|
|
|
|
|
|
$result = strtoupper($sign);
|
|
|
|
|
|
Log::info('通用工具签名-MakeSign:' . json_encode(['values' => $values, 'string' => $string, 'sign' => $sign]));
|
|
|
|
|
|
return $result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 验证签名是否正确
|
|
|
|
|
|
* @param $values
|
|
|
|
|
|
* @param $sign
|
|
|
|
|
|
* @param $key
|
|
|
|
|
|
* @return bool
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function CheckSign($values, $sign, $key = '')
|
|
|
|
|
|
{
|
|
|
|
|
|
$localSign = self::MakeSign($values, $key);
|
|
|
|
|
|
Log::info('通用工具签名信息-Tool-CheckSign' . json_encode(['data' => $values, 'sign' => $sign, 'localSign' => $localSign]));
|
|
|
|
|
|
if ($localSign == $sign) {
|
|
|
|
|
|
//签名正确
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 打包签名数据
|
|
|
|
|
|
* @param $values
|
|
|
|
|
|
* @return mixed
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function packSign($values)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isset($values['nonce_str'])) {
|
|
|
|
|
|
$values['nonce_str'] = uniqid();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!isset($values['time_stamp'])) {
|
|
|
|
|
|
$values['time_stamp'] = time();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//签名步骤四:所有字符转为大写
|
|
|
|
|
|
$values['sign'] = self::MakeSign($values, Env::get('app.token_key'));
|
|
|
|
|
|
|
|
|
|
|
|
return $values;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @param $array
|
|
|
|
|
|
* @return mixed
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function changeArrayKey($array)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach ($array as &$value) {
|
|
|
|
|
|
if (isset($value['name'])) {
|
|
|
|
|
|
$value['text'] = $value['name'];
|
|
|
|
|
|
unset($value['name']);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isset($value['subItems'])) {
|
|
|
|
|
|
foreach ($value['subItems'] as &$v) {
|
|
|
|
|
|
$v['text'] = $v['name'];
|
|
|
|
|
|
unset($v['name']);
|
|
|
|
|
|
}
|
|
|
|
|
|
$value['children'] = $value['subItems'];
|
|
|
|
|
|
unset($value['subItems']);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return $array;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 解析字符串数组
|
|
|
|
|
|
* @param $string
|
|
|
|
|
|
* @param $data
|
|
|
|
|
|
* @return mixed
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function parseArrStr($string, $data)
|
|
|
|
|
|
{
|
|
|
|
|
|
$fieldArr = explode('.', str_replace(['{', '}'], '', $string));
|
|
|
|
|
|
foreach ($fieldArr as $field) {
|
|
|
|
|
|
$data = $data[$field] ?? '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @param $value
|
|
|
|
|
|
* @param $data
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function parseTempData($value, $data)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (preg_match_all('/\{.*?\}/', $value, $matches)) {
|
|
|
|
|
|
$str = '';
|
|
|
|
|
|
foreach ($matches as $match){
|
|
|
|
|
|
$str .= ToolService::parseArrStr($match, $data);
|
|
|
|
|
|
}
|
|
|
|
|
|
$value = $str;
|
|
|
|
|
|
}
|
|
|
|
|
|
return $value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取请求缓存Key
|
|
|
|
|
|
* @param $url
|
|
|
|
|
|
* @param $param
|
|
|
|
|
|
* @return mixed
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function httpCacheKey($url, $param)
|
|
|
|
|
|
{
|
|
|
|
|
|
$query = http_build_query($param);
|
|
|
|
|
|
$parse = parse_url($url);
|
|
|
|
|
|
$urls = implode(':', ['http-cache', $parse['host'], $parse['path'], $query]);
|
|
|
|
|
|
$key = preg_replace('/[^a-zA-Z0-9_\-:]/', '', $urls);
|
|
|
|
|
|
|
|
|
|
|
|
return $key;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 递归实现无限极分类
|
|
|
|
|
|
* @param array $array 分类数据
|
|
|
|
|
|
* @param int $pid 父ID
|
|
|
|
|
|
* @param int $level 分类级别
|
|
|
|
|
|
* @return array 分好类的数组 直接遍历即可 $level可以用来遍历缩进
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static function getTree($array, $pid = 0, $level = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
//声明静态数组,避免递归调用时,多次声明导致数组覆盖
|
|
|
|
|
|
static $list = [];
|
|
|
|
|
|
foreach ($array as $key => $value) {
|
|
|
|
|
|
//第一次遍历,找到父节点为根节点的节点 也就是pid=0的节点
|
|
|
|
|
|
if ($value['parent_id'] == $pid) {
|
|
|
|
|
|
//父节点为根节点的节点,级别为0,也就是第一级
|
|
|
|
|
|
$value['level'] = $level;
|
|
|
|
|
|
$value['name'] = str_repeat('--', $level) . $value['name'];
|
|
|
|
|
|
//把数组放到list中
|
|
|
|
|
|
$list[] = $value;
|
|
|
|
|
|
//把这个节点从数组中移除,减少后续递归消耗
|
|
|
|
|
|
unset($array[$key]);
|
|
|
|
|
|
//开始递归,查找父ID为该节点ID的节点,级别则为原级别+1
|
|
|
|
|
|
self::getTree($array, $value['id'], $level + 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $list;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|