微信支付小微商户V3版本接口使用libsodium扩展以及代码示例

微信支付小微商户接口:

微信支付小微商户接口地址

其接口操作中需要下载证书针对返回的AEAD_AES_256_GCM算法解密,其中用到了sodium_crypto_aead_aes256gcm_decrypt ( string $ciphertext , string $ad , string $nonce , string $key )这个函数。使用这个函数需要开启 libsodium 扩展。

官方文档对该扩展的说明如下:
As of PHP 7.2.0 this extension is bundled with PHP. For older PHP versions this extension is available via PECL.
从php 7.2.0开始,这个扩展与php捆绑在一起。对于旧的PHP版本,此扩展可通过pecl获得。

验证方法

<?php


namespace WechatBundleServices;

use CarbonCarbon;
use DingoApiExceptionResourceException;

/**
 * Class WechatCouponService
 * @package WechatBundleServices
 */
class WechatCouponService
{
    /**
     * @var string
     */
    public $baseUrl;
    /**
     * @var string
     */
    public $mch_id;
    /**
     * @var string
     */
    public $sub_mch_id;
    /**
     * @var string
     */
    public $app_id;
    /**
     * @var string
     */
    public $private_key;
    /**
     * @var string
     */
    public $serial_no;
    /**
     * @var string
     */
    public $mch_key;

    const REDIS_NAME_WECHAT_PAY_CERT = 'wechat_pay_v3_cert_no';

    const KEY_LENGTH_BYTE = 32;
    const AUTH_TAG_LENGTH_BYTE = 16;


    const GET_CERTIFICATES = '/v3/certificates';//获取商户平台证书
    const CREATE_COUPON_STOCKS = '/v3/marketing/favor/coupon-stocks';//创建代金券批次API
    const START_COUPON_STOCKS = '/v3/marketing/favor/stocks/%d/start';//激活代金券批次API
    const COUPON_SEND = '/v3/marketing/favor/users/%s/coupons';//发放代金券API
    const PAUSE_COUPON_STOCKS = '/v3/marketing/favor/stocks/%d/pause';//暂停代金券批次API
    const RESTART_COUPON_STOCKS = '/v3/marketing/favor/stocks/%d/pause';//重启代金券批次API
    const QUERY_COUPON_STOCKS = '/v3/marketing/favor/stocks';//条件查询批次列表API
    const QUERY_COUPON_STOCKS_INFO = '/v3/marketing/favor/stocks/%s';//查询批次详情API
    const QUERY_COUPON_INFO = '/v3/marketing/favor/users/%s/coupons/%s';//查询代金券详情API
    const QUERY_COUPON_MERCHANTS = '/v3/marketing/favor/stocks/%s/merchants';//查询代金券可用商户API
    const QUERY_COUPON_ITEMS = '/v3/marketing/favor/stocks/%s/items';//查询代金券可用单品API
    const QUERY_USER_COUPON = '/v3/marketing/favor/users/%s/coupons';//根据商户号查用户的券
    const COUPON_STOCKS_USER_FLOW_DOWNLOAD = '/v3/marketing/favor/stocks/%s/use-flow';//下载批次核销明细API
    const COUPON_STOCKS_REFUND_FLOW_DOWNLOAD = '/v3/marketing/favor/stocks/%s/refund-flow';//下载批次退款明细API
    const SETTING_COUPON_CALLBACKS = '/v3/marketing/favor/callbacks';//设置消息通知地址API
    /**
     * @var string
     */
    private $wechat_app_id;

    /**
     * WechatCouponService constructor.
     */
    public function __construct()
    {
        $this->baseUrl = 'https://api.mch.weixin.qq.com';
        // 微信支付 商户号
        $this->mch_id = '';
        // 二级商户号,需要走进件系统生成
        $this->sub_mch_id = '';
        // 微信支付 商户号绑定的appid
        $this->app_id = '';
        // 商户私钥
        $this->private_key = wordwrap(file_get_contents(storage_path('apiclient_key.pem')), 64, "n", true);
        // 商户证书序列号
        // 如何查看证书序列号:https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao
        $this->serial_no = '';
        // apiv3秘钥:https://wechatpay-api.gitbook.io/wechatpay-api-v3/ren-zheng/api-v3-mi-yao
        $this->mch_key = '';
    }

    /**
     * 获取API v3证书
     * @return mixed
     */
    public function getCert()
    {
        $wechatPayV3CertNo = app('redis')->get(self::REDIS_NAME_WECHAT_PAY_CERT);
        if (empty($wechatPayV3CertNo)) {
            try {
                $url = $this->baseUrl . self::GET_CERTIFICATES;
                $timestamp = time();
                $nonce = $this->nonce_str();
                $body = '';
                $sign = $this->sign($url, 'GET', $timestamp, $nonce, $body, $this->getPrivateKey($this->private_key), $this->mch_id,
                    $this->serial_no);

                $header = [
                    'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $sign,
                    'Accept:application/json',
                    'User-Agent:' . $this->mch_id,
                ];
                $result = $this->curl($url, '', $header, 'GET');
                $result = json_decode($result, true);
                if (!isset($result['data'])) {
                    throw new Exception('微信支付商户平台小微企业请求证书请求失败' . json_encode($result, 256));
                }
            } catch (Exception $e) {
                throw new ResourceException($e->getMessage());
                app('api.exception')->report($e->getMessage());
            }
            $wechatPayV3CertNo = $result['data']['0']['serial_no'];
            app('redis')->set(self::REDIS_NAME_WECHAT_PAY_CERT, $wechatPayV3CertNo, 'EX', 600);
        }
        return $wechatPayV3CertNo;
    }

    /**
     * 获取随机字符串
     * @return string
     */
    protected function nonce_str()
    {
        static $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < 32; $i++) {
            $randomString .= $characters[rand(0, $charactersLength - 1)];
        }
        return $randomString;
    }

    /**
     * 获取签名
     * @param $url
     * @param $http_method
     * @param $timestamp
     * @param $nonce
     * @param $body
     * @param $mch_private_key
     * @param $merchant_id
     * @param $serial_no
     * @return string
     */
    protected function sign($url, $http_method, $timestamp, $nonce, $body, $mch_private_key, $merchant_id, $serial_no)
    {
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $message = $http_method . "n" .
            $canonical_url . "n" .
            $timestamp . "n" .
            $nonce . "n" .
            $body . "n";

        openssl_sign($message, $raw_sign, $mch_private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);

        $schema = 'WECHATPAY2-SHA256-RSA2048';
        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $merchant_id, $nonce, $timestamp, $serial_no, $sign);
        return $token;
    }

    /**
     * 验签
     * @param $message
     * @param $signature
     * @param $merchantPublicKey
     * @return bool|int
     */
    private function verify($message, $signature, $merchantPublicKey)
    {
        if (empty($merchantPublicKey)) {
            return false;
        }

        if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
            throw new RuntimeException("当前PHP环境不支持SHA256withRSA");
        }
        $signature = base64_decode($signature);
        return openssl_verify($message, $signature, $this->getPublicKey($merchantPublicKey), 'sha256WithRSAEncryption');
    }

    /**
     * @param $associatedData
     * @param $nonceStr
     * @param $ciphertext
     * @param $aesKey
     * @return bool|string
     */
    private function decryptToString($associatedData, $nonceStr, $ciphertext, $aesKey = '')
    {
        if (empty($aesKey)) {
            $aesKey = $this->mch_key;
        }
        $ciphertext = base64_decode($ciphertext);
        if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
            return false;
        }

        // ext-sodium (default installed on >= PHP 7.2)
        if (function_exists('sodium_crypto_aead_aes256gcm_is_available') &&
            sodium_crypto_aead_aes256gcm_is_available()) {
            return sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey);
        }

        // ext-libsodium (need install libsodium-php 1.x via pecl)
        if (function_exists('Sodiumcrypto_aead_aes256gcm_is_available') &&
            Sodiumcrypto_aead_aes256gcm_is_available()) {
            return Sodiumcrypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $aesKey);
        }

        // openssl (PHP >= 7.1 support AEAD)
        if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', openssl_get_cipher_methods())) {
            $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
            $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);

            return openssl_decrypt($ctext, 'aes-256-gcm', $aesKey, OPENSSL_RAW_DATA, $nonceStr,
                $authTag, $associatedData);
        }

        throw new RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
    }

    /**
     * 请求
     * @param $url
     * @param array $data
     * @param $header
     * @param string $method
     * @param int $time_out
     * @return mixed
     */
    private function curl($url, $data = [], $header, $method = 'POST', $time_out = 3)
    {
        $curl = curl_init();
        // 设置curl允许执行的最长秒数

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_TIMEOUT, $time_out);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);

        if ($method == 'POST') {
            curl_setopt($curl, CURLOPT_POST, true);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }

        // 执行操作
        $result = curl_exec($curl);

        curl_close($curl);
        return $result;
    }

    /**
     * 获取请求头
     * @param $url
     * @param $body
     * @param $method
     * @return array
     */
    protected function getCurlHeader($url, $body, $method)
    {
        $timestamp = time();
        $nonce = $this->nonce_str();
        $sign = $this->sign($url, $method, $timestamp, $nonce, $body, $this->getPrivateKey($this->private_key), $this->mch_id,
            $this->serial_no);

        return [
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $sign,
            'Accept:application/json',
            'User-Agent:' . $this->mch_id,
            'Content-Type:application/json',
            'Wechatpay-Serial:' . $this->getCert(),
        ];
    }

    /**
     * 获取私钥
     * @param $key
     * @return bool|resource
     */
    protected function getPrivateKey($key)
    {
        return openssl_get_privatekey($key);
    }

    /**
     * @param $key
     * @return resource
     */
    protected function getPublicKey($key)
    {
        return openssl_get_publickey($key);
    }

    /**
     * 获取请求头
     * @return array
     */
    private function getHeaders()
    {
        $headers = array();
        foreach ($_SERVER as $key => $value) {
            if ('HTTP_' == substr($key, 0, 5)) {
                $headers[str_replace('_', '-', substr($key, 5))] = $value;
            }
            if (isset($_SERVER['PHP_AUTH_DIGEST'])) {
                $header['AUTHORIZATION'] = $_SERVER['PHP_AUTH_DIGEST'];
            } elseif (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
                $header['AUTHORIZATION'] = base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW']);
            }
            if (isset($_SERVER['CONTENT_LENGTH'])) {
                $header['CONTENT-LENGTH'] = $_SERVER['CONTENT_LENGTH'];
            }
            if (isset($_SERVER['CONTENT_TYPE'])) {
                $header['CONTENT-TYPE'] = $_SERVER['CONTENT_TYPE'];
            }
        }
        return $headers;
    }

    /**
     * 发放代金券API
     * @param string $stockId 批次号
     * @param string $openId 用户openid
     * @param string $outRequestNo 商户单据号
     * @param int|null $couponValue 指定面额发券,面额
     * @param int|null $couponMinimum 指定面额发券,券门槛
     * @return array
     * @throws Exception
     */
    public function couponSend(string $stockId, string $openId, string $outRequestNo, ?int $couponValue, ?int $couponMinimum): array
    {
        try {
            $requestData = [
                'stock_id' => $stockId,
                'out_request_no' => $outRequestNo,
                'appid' => $this->app_id,
                'stock_creator_mchid' => $this->mch_id,
            ];
            if (!empty($couponValue)) {
                $requestData['coupon_value'] = $couponValue;
            }
            if (!empty($couponMinimum)) {
                $requestData['coupon_minimum'] = $couponMinimum;
            }
            $header = $this->getCurlHeader($this->baseUrl . sprintf(self::COUPON_SEND, $openId), json_encode($requestData), 'POST');
            $result = $this->curl($this->baseUrl . sprintf(self::COUPON_SEND, $openId), json_encode($requestData), $header, 'POST');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 条件查询批次列表API
     * @param string|null $createStartTime 起始时间
     * @param string|null $createEndTime 终止时间
     * @param string|null $status 批次状态unactivated:未激活 audit:审核中 running:运行中 stoped:已停止 paused:暂停发放
     * @param int $offset 分页页码
     * @param int $limit 分页大小
     * @return array
     * @throws Exception
     */
    public function queryCouponStocks(?string $createStartTime, ?string $createEndTime, ?string $status, $offset = 0, $limit = 10): ?array
    {
        try {
            if (!empty($status) && !in_array($status, ['unactivated', 'audit', 'running', 'stoped', 'paused'])) {
                throw new Exception('状态错误');
            }
            $requestData = [
                'stock_creator_mchid' => $this->mch_id,
                'offset' => $offset,
                'limit' => $limit
            ];
            if (!empty($status)) {
                $requestData['status'] = $status;
            }
            if (!empty($createStartTime)) {
                $requestData['create_start_time'] = Carbon::createFromTimestamp(strtotime($createStartTime))->toRfc3339String();
            }
            if (!empty($createEndTime)) {
                $requestData['create_end_time'] = Carbon::createFromTimestamp(strtotime($createEndTime))->toRfc3339String();
            }
            $url = $this->baseUrl . self::QUERY_COUPON_STOCKS . '?' . getSignContent($requestData);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 查询批次详情API
     * @param string $stockId 批次号
     * @return mixed
     */
    public function queryCouponStocksInfo(string $stockId)
    {
        try {
            if (empty($stockId)) {
                throw new Exception('批次号不能为空');
            }
            $requestData = [
                'stock_creator_mchid' => $this->mch_id
            ];
            $url = $this->baseUrl . sprintf(self::QUERY_COUPON_STOCKS_INFO, $stockId) . '?' . getSignContent($requestData);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 查询代金券详情API
     * @param string $openId openid
     * @param string $couponId 代金券id
     * @return mixed
     */
    public function queryCouponInfo(string $openId, string $couponId)
    {
        try {
            if (empty($openId)) {
                throw new Exception('openId不能为空');
            }
            if (empty($couponId)) {
                throw new Exception('优惠券id不能为空');
            }
            $requestData = [
                'appid' => $this->app_id
            ];
            $url = $this->baseUrl . sprintf(self::QUERY_COUPON_INFO, $openId, $couponId) . '?' . getSignContent($requestData);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 查询代金券可用商户API
     * @param string $stockId 批次号
     * @param int $offset 分页页码,最大1000。
     * @param int $limit 分页大小,最大50。
     * @return mixed
     */
    public function queryCouponMerchants(string $stockId, $offset = 1, $limit = 10)
    {
        try {
            if (empty($stockId)) {
                throw new Exception('批次号不能为空');
            }
            $requestData = [
                'stock_creator_mchid' => $this->mch_id,
                'offset' => $offset,
                'limit' => $limit
            ];
            $url = $this->baseUrl . sprintf(self::QUERY_COUPON_MERCHANTS, $stockId) . '?' . getSignContent($requestData);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 查询代金券可用单品API
     * @param string $stockId 批次号
     * @param int $offset 分页页码,最大1000。
     * @param int $limit 分页大小,最大50。
     * @return mixed
     */
    public function queryCouponItems(string $stockId, $offset = 1, $limit = 10)
    {
        try {
            if (empty($stockId)) {
                throw new Exception('批次号不能为空');
            }
            $requestData = [
                'stock_creator_mchid' => $this->mch_id,
                'offset' => $offset,
                'limit' => $limit
            ];
            $url = $this->baseUrl . sprintf(self::QUERY_COUPON_ITEMS, $stockId) . '?' . getSignContent($requestData);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 根据商户号查用户的券
     * @param string $openId 用户标识
     * @param string $stockId 批次号
     * @param string $status 状态SENDED:可用 USED:已实扣
     * @param string $creatorMchid 创建批次的商户号
     * @param string $senderMchid 批次发放商户号
     * @param string $availableMchid 可用商户号
     * @param int $offset 分页页码
     * @param int $limit 分页大小
     * @return mixed
     */
    public function queryUserCoupon(string $openId, $stockId = '', $status = '', $creatorMchid = '', $senderMchid = '', $availableMchid = '', $offset = 0, $limit = 20)
    {
        try {
            if (!empty($status) && !in_array($status, ['SENDED', 'USED'])) {
                throw new Exception('状态错误');
            }
            $requestData = [
                'appid' => $this->app_id,
                'offset' => $offset,
                'limit' => $limit,
                'creator_mchid' => $this->mch_id,
            ];
            if (!empty($stockId)) {
                $requestData['stock_id'] = $stockId;
            }
            if (!empty($status)) {
                $requestData['status'] = $status;
            }
            if (!empty($senderMchid)) {
                $requestData['available_mchid'] = $senderMchid;
            }
            if (!empty($availableMchid)) {
                $requestData['available_mchid'] = $availableMchid;
            }
            $url = $this->baseUrl . sprintf(self::QUERY_USER_COUPON, $openId) . '?' . getSignContent($requestData);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 下载批次核销明细API
     * @param string $stockId 批次号
     * @return mixed
     */
    public function couponStocksUserFlowDownload(string $stockId)
    {
        try {
            if (empty($stockId)) {
                throw new Exception('批次号不能为空');
            }
            $url = $this->baseUrl . sprintf(self::COUPON_STOCKS_USER_FLOW_DOWNLOAD, $stockId);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 下载批次退款明细API
     * @param string $stockId 批次号
     * @return mixed
     */
    public function couponStocksRefundFlowDownload(string $stockId)
    {
        try {
            if (empty($stockId)) {
                throw new Exception('批次号不能为空');
            }
            $url = $this->baseUrl . sprintf(self::COUPON_STOCKS_REFUND_FLOW_DOWNLOAD, $stockId);
            $header = $this->getCurlHeader($url, '', 'GET');
            $result = $this->curl($url, '', $header, 'GET');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }

    /**
     * 设置消息通知地址API
     * @param string $notifyUrl 支付通知商户url地址。
     * @param bool $switch 如果商户不需要再接收营销事件通知,可通过该开关关闭。枚举值:true:开启推送 false:停止推送
     * @return mixed
     */
    public function settingCouponCallbacks(string $notifyUrl, bool $switch)
    {
        try {
            if (empty($notifyUrl)) {
                throw new ResourceException('回调地址不能为空,且必须是完整的https链接');
            }
            $requestData = [
                'mchid' => $this->mch_id,
                'notify_url' => $notifyUrl,
                'switch' => $switch
            ];
            $url = $this->baseUrl . self::SETTING_COUPON_CALLBACKS;
            $header = $this->getCurlHeader($url, json_encode($requestData), 'POST');
            $result = $this->curl($url, json_encode($requestData), $header, 'POST');
            $result = json_decode($result, true);
            if (!$result || isset($result['code'])) {
                if (!$result) {
                    throw new ResourceException('操作失败,请刷新页面后重试');
                }
                throw new ResourceException($result['code'] . '---' . $result['message']);
            }
            return $result;
        } catch (Exception $e) {
            throw new ResourceException($e->getMessage());
        }
    }
}
?>
<?php
if (!function_exists('getSignContent')) {
    /**
     * 拼接uri 用于验签等功能
     */
    function getSignContent($params) {
        ksort($params);
        $i                = 0;
        $stringToBeSigned = "";
        foreach ($params as $k => $v) {
            if ($i == 0) {
                $stringToBeSigned .= "$k" . "=" . "$v";
            } else {
                $stringToBeSigned .= "&" . "$k" . "=" . "$v";
            }
            $i++;
        }
        unset ($k, $v);
        return $stringToBeSigned;
    }

}
?>php
本作品采用《CC 协议》,转载必须注明作者和本文链接
wd731869706
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!