php 微信支付V3API 签名生成

class Formatter
{
    /**
     * Generate a random BASE62 string aka `nonce`, similar as `random_bytes`.
     *
     * @param int $size - Nonce string length, default is 32.
     *
     * @return string - base62 random string.
     */
    public static function nonce(int $size = 32): string
    {
        if ($size < 1) {
            throw new Exception('Size must be a positive integer.');
        }
        return implode('', array_map(static function(string $c): string {
            return '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'[ord($c) % 62];
        }, str_split(random_bytes($size))));
    }

    /**
     * Retrieve the current `Unix` timestamp.
     *
     * @return int - Epoch timestamp.
     */
    public static function timestamp(): int
    {
        return time();
    }

    /**
     * Formatting for the heading `Authorization` value.
     *
     * @param string $mchid - The merchant ID.
     * @param string $nonce - The Nonce string.
     * @param string $signature - The base64-encoded `Rsa::sign` ciphertext.
     * @param string $timestamp - The `Unix` timestamp.
     * @param string $serial - The serial number of the merchant public certification.
     *
     * @return string - The APIv3 Authorization `header` value
     */
    public static function authorization(string $mchid, string $nonce, string $signature, string $timestamp, string $serial): string
    {
        return sprintf(
            'WECHATPAY2-SHA256-RSA2048 mchid="%s",serial_no="%s",timestamp="%s",nonce_str="%s",signature="%s"',
            $mchid, $serial, $timestamp, $nonce, $signature
        );
    }

    /**
     * Formatting this `HTTP::request` for `Rsa::sign` input.
     *
     * @param string $method - The HTTP verb, must be the uppercase sting.
     * @param string $uri - Combined string with `URL::pathname` and `URL::search`.
     * @param string $timestamp - The `Unix` timestamp, should be the one used in `authorization`.
     * @param string $nonce - The `Nonce` string, should be the one used in `authorization`.
     * @param string $body - The playload string, HTTP `GET` should be an empty string.
     *
     * @return string - The content for `Rsa::sign`
     */
    public static function request(string $method, string $uri, string $timestamp, string $nonce, string $body = ''): string
    {
        return static::joinedByLineFeed($method, $uri, $timestamp, $nonce, $body);
    }

    /**
     * Formatting this `HTTP::response` for `Rsa::verify` input.
     *
     * @param string $timestamp - The `Unix` timestamp, should be the one from `response::headers[Wechatpay-Timestamp]`.
     * @param string $nonce - The `Nonce` string, should be the one from `response::headers[Wechatpay-Nonce]`.
     * @param string $body - The response payload string, HTTP status(`201`, `204`) should be an empty string.
     *
     * @return string - The content for `Rsa::verify`
     */
    public static function response(string $timestamp, string $nonce, string $body = ''): string
    {
        return static::joinedByLineFeed($timestamp, $nonce, $body);
    }

    /**
     * Joined this inputs by for `Line Feed`(LF) char.
     *
     * @param string|float|int|bool $pieces - The scalar variable(s).
     *
     * @return string - The joined string.
     */
    public static function joinedByLineFeed(...$pieces): string
    {
        return implode("\n", array_merge($pieces, ['']));
    }

    /**
     * Sort an array by key with `SORT_STRING` flag.
     *
     * @param array<string, string|int> $thing - The input array.
     *
     * @return array<string, string|int> - The sorted array.
     */
    public static function ksort(array $thing = []): array
    {
        ksort($thing, SORT_STRING);

        return $thing;
    }

    /**
     * Like `queryString` does but without the `sign` and `empty value` entities.
     *
     * @param array<string, string|int|null> $thing - The input array.
     *
     * @return string - The `key=value` pair string whose joined by `&` char.
     */
    public static function queryStringLike(array $thing = []): string
    {
        $data = [];

        foreach ($thing as $key => $value) {
            if ($key === 'sign' || is_null($value) || $value === '') {
                continue;
            }
            $data[] = implode('=', [$key, $value]);
        }

        return implode('&', $data);
    }
    public static function curlPostWithWx($params,$authorization,$url)
    {
        $paramsString = json_encode($params);
        // 初始化curl
        $ch = curl_init();
        // 设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        // post数据
        curl_setopt($ch, CURLOPT_POST, 1);
        // post的变量
        curl_setopt($ch, CURLOPT_POSTFIELDS, $paramsString);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json; charset=utf-8',
                'Content-Length: ' . strlen($paramsString),
                'Authorization: ' . "WECHATPAY2-SHA256-RSA2048 " . $authorization,
                'Accept: application/json',
                'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
            )
        );
        // 运行curl,结果以jason形式返回
        $res = curl_exec($ch);
        curl_close($ch);
        // 取出数据
        $data = json_decode($res, true);
        return $data;
    }

    /**
     * get请求
     * @param $url
     * @param $authorization
     * @return mixed
     */
    public static function curlGetWithWx($url, $authorization,$params=[])
    {
        $paramsString = json_encode($params);
        // 初始化curl
        $ch = curl_init();
        // 设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/json; charset=utf-8',
                'Content-Length: ' . strlen($paramsString),
                'Authorization: ' . "WECHATPAY2-SHA256-RSA2048 " . $authorization,
                'Accept: application/json',
                'User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
            )
        );
        // 运行curl,结果以jason形式返回
        $res = curl_exec($ch);
        curl_close($ch);
        // 取出数据
        $data = json_decode($res, true);
        //返回
        return $data;
    }
    public static function getAuthorization($url, $body,$mch_id, $priKey, $serial, $http_method = "POST")
    {
        // Authorization: <schema> <token>
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $timestamp = static::timestamp();
        $nonce = static::nonce();
        $message = static::request($http_method, $canonical_url, $timestamp, $nonce, json_encode($body));
        openssl_sign($message, $raw_sign, $priKey, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        return static::authorization($mch_id, $nonce, $sign, $timestamp, $serial);
    }

首先,把以上工具类,保存到自己项目中。(方法改源于微信官方建议 github sdk,点击可前往)调用方法如下:

$mch_id = '1630****';//商户号
$priKey = '';//私钥文本
$serial = '';//证书序号
$queryUrl = 'https://api.mch.weixin.qq.com/v3/bill/tradebill';//账单接口
$param = ['bill_date'=>'2022-09-01','sub_mchid'=>$mch_id,'bill_type'=>'ALL','tar_type'=>'GZIP'];
$authorization = Formatter::getAuthorization($queryUrl, $param, $mch_id, $priKey, $serial);//生成签名
$result = Formatter::curlGetWithWx($param, $authorization, $queryUrl);//接口请求
var_dump($result);

证书序号和私钥文本内容,是必须的。建议先仔细阅读官方文档。

https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml

 

posted @ 2022-09-27 13:48  知风阁  阅读(994)  评论(0编辑  收藏  举报