BaseController.php 6.38 KB
<?php

namespace App\Http\Controllers\Release;

use App\Helper\CacheKeyTools;
use App\Helper\Response;
use App\Http\Controllers\Controller;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;


class BaseController extends Controller
{
    /**
     * @var string[]
     */
    protected $filterTmeBrandIdUri = [
        'queryAuthResources'
    ];

    /**
     * 基础变量
     * @var string
     */
    protected $domain, $appId;
    private $appSecret;
    protected $client;

    public function __construct()
    {
        $this->domain = env('TME_DOMAIN','https://openapi-sit.tencentmusic.com');
        $this->appId = env('TME_APPID','47820741');
        $this->appSecret = env('TME_APPSECRET','nPWFDDHKYCP4bUzoq9zyaJQx4ltQqMSs');
        $this->client = new Client(['verify'=>false]);
    }

    /**获取accessToken
     */
    function getToken()
    {
        $url = rtrim($this->domain,'/').'/oauth2/token';
        $data = ['appId'=>$this->appId,'appSecret'=>$this->appSecret];
        try {
            $response = $this->client->request('POST', $url, ['json' => $data]);

            $respArr = json_decode($response->getBody()->getContents(), true);
            Log::channel('api')->info(__METHOD__, $respArr);
            if (0 !== (int)$respArr['code']) {
                return null;
            } else {
                $res = $respArr['data'];
                Cache::put(CacheKeyTools::tmeAccessToken(), $res['accessToken'], ($res['expire'] ?? 900) - 100);  // 加入缓存
                return $res['accessToken'];
            }
        } catch (\Exception $e) {
            Log::channel('api')->error(__METHOD__, ['msg'=>$e->getMessage()]);
            return null;
        }
    }

    /**
     * 重组请求数据,返回headers
     * @param array $params
     * @return mixed
     */
    private function parseHeaders(array $params)
    {
        if (!$accessToken = Cache::get(CacheKeyTools::tmeAccessToken())) {$accessToken = $this->getToken();}



        $headers['appId']        =   $this->appId;
        $headers['accessToken']  =   $accessToken;
        $headers['timestamp']    =   (string)date('YmdHis');
        $headers['traceId']      =   'hk_'.(string)time();
        $headers['signMethod']   =   'md5';
        $headers['sign']         =   $this->getSign($headers, $params);

        return $headers;
    }

    /**
     * 请求接口
     * @param string $uri
     * @param array $reqData
     * @param string $method
     * @param bool $isLocal
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function doApi(string $uri, array $reqData = [], string $method = 'POST', bool $isLocal = false)
    {
        $token = uniqid();
        $url = rtrim($this->domain,'/').'/'.ltrim($uri,'/');
        try {
            if ($isLocal) {
                $data_file = database_path('Release/'.last(explode("/",$uri)).'.query.php');
                $params = include("$data_file");
            } else {
                $params = $reqData;
            }

            if (!$this->filterTmeBrandId($uri)) {
                $params['tmeBrandId'] = $params['tmeBrandId'] ?? 8888888;
            }

            $headers = $this->parseHeaders($params);

            Log::channel('api')->info(__METHOD__, ['token'=>$token, 'url'=>$url, 'params'=>$params, 'headers'=>$headers]);

            switch (strtoupper($method)) {
                case 'GET':
                    $response = $this->client->request('GET', $url, ['query' => $params, 'headers'=>$headers]);
                    break;
                case 'POST':
                default:
                    $response = $this->client->request('POST', $url, ['json' => $params,'headers'=>$headers]);
                    break;
            }
            $respArr = json_decode($response->getBody()->getContents(), true);

            Log::channel('api')->info(__METHOD__, ['token'=>$token,'respArr'=>$respArr]);

            if ($respArr['code'] == '0'){
                return [(int)$respArr['code'],$respArr['message'] ?? '操作失败',$respArr['data'] ?? []];
            } else {
                return [(int)$respArr['code'],$respArr['message'] ?? '操作失败',[$respArr['traceId']]];
            }

        } catch (\Exception $e) {
            Log::channel('api')->error(__METHOD__, ['token'=>$token, 'msg'=>$e->getMessage()]);
            return [-1,'接口请求失败',[]];
        }
    }

    /**
     * 过滤tmeBrandId字段
     * @param $uri
     * @return bool
     */
    protected function filterTmeBrandId($uri): bool
    {
        foreach ($this->filterTmeBrandIdUri as $item) {
            if (strpos($uri, $item) !== false) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取签名和去空的参数
     * @param $headers
     * @param $params
     * @return string
     */
    protected function getSign($headers, $params)
    {
        $common_params = array_merge($params, $headers);

        //排序
        ksort($common_params);
        $params = '';

        foreach ($common_params as $k=>$v)
        {
            if ('' === $v || null === $v || [] === $v) {
                continue;
            }
            if (is_array($v)) {
                $params .= $k . json_encode($this->handleSubArrayNumber($v), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            } else {
                $params .= $k . $v;
            }
        }


        Log::channel('api')->info(__METHOD__.':签名参数', [
            'appSecret'=>$this->appSecret,
            '$params'=>$params,
            'sign'=>strtoupper(md5($this->appSecret . $params . $this->appSecret)),
        ]);

        return strtoupper(md5($this->appSecret . $params . $this->appSecret));
    }

    /**
     * 签名需要,递归处理子数组中Int型数字转换成字符串
     * @param array $array
     * @return array
     */
    private function handleSubArrayNumber(array $array)
    {
        foreach ($array as $k=>$v) {
            if (is_array($v)) {
//                ksort($v);
                $array[$k] = $this->handleSubArrayNumber($v);
            } else {
                $array = array_filter($array, function ($item) {
                    if ($item === '' || $item === null) {
                        return false;
                    } else {
                        return true;
                    }
                });
            }
        }
        return $array;
    }
}