• 技术文章 >微信小程序 >微信开发

    分享微信支付v3版 php解密解密代码

    藏色散人藏色散人2021-07-15 13:50:04转载407
    微信支付V3版本小程序支付 php签名,验签,数据解密代码分享

    微信支付v3版 php解密解密代码

    数据解密需要用到sodium扩展 大部分php版本需要安装

    证书序列号可以在这里查看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 '';
            }
            // ext-sodium (default installed on >= PHP 7.2)
            return \sodium_crypto_aead_aes256gcm_decrypt($str, $associatedData, $nonceStr, $aesKey);
        }
        //下载平台证书
        public static function downCert()
        {
            $url = 'https://api.mch.weixin.qq.com/v3/certificates';
            $re = self::wxCurl($url, [], 'GET');
            if (!isset($re['data'])) {
                api_fail('获取证书失败');
            }
            $ciphertext = $re['data'][0]['encrypt_certificate']['ciphertext'];
            $associatedData = $re['data'][0]['encrypt_certificate']['associated_data'];
            $nonceStr = $re['data'][0]['encrypt_certificate']['nonce'];
            $data = self::decryptToString($ciphertext, $associatedData, $nonceStr);
            if (!$data) {
                api_fail('获取证书解密失败');
            }
            file_put_contents(BASE_PATH . '/cert/wx_public_cert.pem', $data);
            return $data;
        }
    }

    以上就是分享微信支付v3版 php解密解密代码的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:机器翻译官,如有侵犯,请联系admin@php.cn删除
    专题推荐:微信支付v3版
    上一篇:【记录】PHP微信小程序 微信支付v3的使用 下一篇:如何解决微信支付API v3回调通知出现乱码问题
    大前端线上培训班

    相关文章推荐

    • 注销微信显示非法请求什么意思• 随着微信支付的升级,PHP微信支付类V3接口也来了• 关于微信支付小程序v3【附PHP完整后端代码】• 【记录】PHP微信小程序 微信支付v3的使用

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网