ホームページ WeChat アプレット WeChatの開発 WeChat支払いv3バージョンのphp復号化コードを共有する

WeChat支払いv3バージョンのphp復号化コードを共有する

Jul 15, 2021 pm 01:50 PM

WeChat Pay V3 バージョン アプレット支払い php 署名、署名検証、データ復号化コード共有

WeChat Pay v3 バージョン php 復号化コード

データ復号化に必要ほとんどの PHP Sodium に展開するバージョンはインストールする必要があります。

#証明書のシリアル番号はここで確認できます https://myssl.com/cert_decode.html

私が使用する PHP7.4 バージョン

コードに直接移動します:

//微信原生支付
class Wxpay
{
    /*
     * 支付(小程序支付)
     * @param type $sn        订单编号
     * @param type $money  金额
     * @param type $openid  用户小程序openid
     * @return type
     */
    public static function getPayParam($sn, $money, $openid)
    {
        $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi';
        $notify_url = url('/api/weixin/notify');
        $data = [];
        $data['appid'] = Action::config(CONFIG_WXXCX, 'app_id');
        $data['mchid'] = Action::config(CONFIG_WXXCX, 'mchid'); //商户号
        $data['description'] = 'xxx'; //描述?
        $data['out_trade_no'] = $sn; //商户系统内部订单号
        $data['time_expire'] = date('Y-m-d') . 'T' . date('H:i:s', (time() + 1800)) . '+08:00'; //订单失效时间2018-06-08T10:34:56+08:00
        $data['notify_url'] = $notify_url; //异步通知接口地址
        $data['amount'] = ['total' => $money * 100, 'currency' => 'CNY']; //金额
        $data['payer'] = ['openid' => $openid]; //用户
        $re = self::wxCurl($url, $data, 'POST');
        if (!isset($re['prepay_id'])) {
            api_fail('参数获取失败');
        }
        $result = [];
        $result['appId'] = Action::config(CONFIG_WXXCX, 'app_id');
        $result['timeStamp'] = (string)time();
        $result['nonceStr'] = uniqid();
        $result['package'] = 'prepay_id=' . $re['prepay_id'];
        $result['signType'] = 'RSA';
        $result['paySign'] = self::getPaySign($result);
        return $result;
    }
    /**
     * 查询订单
     * @param type $sn
     */
    public static function select($sn, $return = false)
    {
        $mchid = Action::config(CONFIG_WXXCX, 'mchid'); //商户号
        $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/' . $sn . '?mchid=' . $mchid;
        $re = self::wxCurl($url, [], 'GET');
        if ($return) {
            return $re;
        }
        if (isset($re['trade_state']) && $re['trade_state'] == 'SUCCESS') {
            return true;
        }
        return false;
    }
    /**
     * 关闭订单
     * @param type $sn
     */
    public static function close($sn)
    {
        $mchid = Action::config(CONFIG_WXXCX, 'mchid'); //商户号
        $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/' . $sn . '/close';
        $re = self::wxCurl($url, ['mchid'=>$mchid], 'POST');
        return true;
    }
    /**
     * 退款
     * @param type $sn
     */
    public static function refund($order_sn,$refund_sn,$total,$refund,$msg='退款')
    {
        $url='https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        $data=[];
        $data['notify_url']=url('ag/weixin/notify_refund');
        $data['out_trade_no']=$order_sn;//订单号
        $data['out_refund_no']=$refund_sn;//退款单号
        $data['reason']=$msg;
        $data['amount']=['refund'=>$refund*100,'total'=>$total*100,'currency'=>'CNY'];
        $re = self::wxCurl($url, $data, 'POST');
        return $re;
    }
    //请求
    public static function wxCurl($url, $data = [], $method = 'GET')
    {
        $Authorization = self::getReSign($url, $data, $method);
        $header = [
            'Content-Type: application/json',
            'Accept: application/json',
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63',
            'Authorization: ' . $Authorization
        ];
        $redata = $data ? json_encode($data) : '';
        $res = reCurl($url, $redata, $header);
        return $res ? json_decode($res, true) : [];
    }
    //后端请求签名
    public static function getReSign($url, $data, $method = 'GET')
    {
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $http_method = $method;
        $timestamp = time();
        $nonce = uniqid();
        $body = $data ? json_encode($data) : '';
        $mchid = Action::config(CONFIG_WXXCX, 'mchid'); //商户id
        $serial_no = Action::config(CONFIG_WXXCX, 'serial_no'); //证书编号
        $private_key = self::getPrivateKey(BASE_PATH . 'cert/apiclient_key.pem'); //商户私钥
        $message = $http_method . "\n" .
            $canonical_url . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
        openssl_sign($message, $raw_sign, $private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', $mchid, $nonce, $timestamp, $serial_no, $sign);
        return 'WECHATPAY2-SHA256-RSA2048 ' . $token;
    }
    //前端小程序签名
    public static function getPaySign($result)
    {
        $private_key = self::getPrivateKey(BASE_PATH . 'cert/apiclient_key.pem'); //商户私钥
        $message = $result['appId'] . "\n" .
            $result['timeStamp'] . "\n" .
            $result['nonceStr'] . "\n" .
            $result['package'] . "\n";
        openssl_sign($message, $raw_sign, $private_key, 'sha256WithRSAEncryption');
        $sign = base64_encode($raw_sign);
        return $sign;
    }
    //验证签名
    public static function checkSign()
    {
        $header = Context::get('header');
        $serial_no = $header['wechatpay-serial'] ?? ''; //微信平台序列号
        $timeStamp = $header['wechatpay-timestamp'] ?? '';
        $nonce = $header['wechatpay-nonce'] ?? '';
        $body = Context::get('raw');
        $wx_sign = $header['wechatpay-signature'] ?? '';
        $wx_serial_no = Action::config(CONFIG_WXXCX, 'wx_serial_no');//保存的序列号
        if (!$serial_no || $wx_serial_no != $serial_no) {
            \sff\Log::write('签名过期');
            return false;
        }
        $message = $timeStamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
        
        $wx_sign = base64_decode($wx_sign);
        $public_key = self::getPublicKey(BASE_PATH . 'cert/wx_public_cert.pem'); //平台公钥
        $res = openssl_verify($message, $wx_sign, $public_key, OPENSSL_ALGO_SHA256);
        if ($res == 1) {
            return true;
        }
        \sff\Log::write('验签失败');
        return false;
    }
    //获取私钥
    public static function getPrivateKey($filepath)
    {
        return openssl_get_privatekey(file_get_contents($filepath));
    }
    //获取公钥
    public static function getPublicKey($filepath)
    {
        return openssl_pkey_get_public(file_get_contents($filepath));
    }
    //加密数据
    public static function getEncrypt($str)
    {
//$str是待加密字符串 
        $public_key_path = BASE_PATH . 'cert/wx_public_cert.pem'; //'平台证书路径';
        $public_key = file_get_contents($public_key_path);
        $encrypted = '';
        if (openssl_public_encrypt($str, $encrypted, $public_key, OPENSSL_PKCS1_OAEP_PADDING)) {
            //base64编码 
            $sign = base64_encode($encrypted);
        } else {
            throw new Exception('encrypt failed');
        }
        return $sign;
    }
    //解密数据
    public static function decryptToString($ciphertext, $associatedData, $nonceStr)
    {
        $aesKey = Action::config(CONFIG_WXXCX, 'mch_keyv3'); //商户apiv3密钥解密
        $str = base64_decode($ciphertext);
        if (strlen($str) <= 16) {
            return &#39;&#39;;
        }
        // ext-sodium (default installed on >= PHP 7.2)
        return \sodium_crypto_aead_aes256gcm_decrypt($str, $associatedData, $nonceStr, $aesKey);
    }
    //下载平台证书
    public static function downCert()
    {
        $url = &#39;https://api.mch.weixin.qq.com/v3/certificates&#39;;
        $re = self::wxCurl($url, [], &#39;GET&#39;);
        if (!isset($re[&#39;data&#39;])) {
            api_fail(&#39;获取证书失败&#39;);
        }
        $ciphertext = $re[&#39;data&#39;][0][&#39;encrypt_certificate&#39;][&#39;ciphertext&#39;];
        $associatedData = $re[&#39;data&#39;][0][&#39;encrypt_certificate&#39;][&#39;associated_data&#39;];
        $nonceStr = $re[&#39;data&#39;][0][&#39;encrypt_certificate&#39;][&#39;nonce&#39;];
        $data = self::decryptToString($ciphertext, $associatedData, $nonceStr);
        if (!$data) {
            api_fail(&#39;获取证书解密失败&#39;);
        }
        file_put_contents(BASE_PATH . &#39;/cert/wx_public_cert.pem&#39;, $data);
        return $data;
    }
}
ログイン後にコピー

以上がWeChat支払いv3バージョンのphp復号化コードを共有するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)