记录一下PHP使用微信小程序V3支付及申请退款

1.小程序V3支付

记录一下PHP使用微信小程序支付V3版本经历
官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_0.shtml

请详细查看文档中小程序支付接入前准备(https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml)

注意:配置好需要将已生成的证书下载放在自己的项目中
示例:
在这里插入图片描述

配置好后需要拿到以下参数:

  1. 小程序appid
  2. 商户号
  3. 微信支付API证书序列号
  4. 微信支付v3密钥(回调时需要)

支付大概流程:
1.小程序端提交订单

小程序端提交的订单就不做示例了

2.后端根据订单信息生成预订单通过小程序JSAPI下单返回预支付交易会话标识

	private $appid = '**********';//应用ID
    private $mchid = '************';//商户号
    private $serial_number = '***********';//微信支付API证书序列号
    private $v3_key = '***********';//微信支付v3密钥

    public function placeOrder()
    {
        //通过jsapi下单所需参数
        $pay_info = [
            'out_trade_no' => '',//自己平台的订单号
            'total' => '',//付款金额,单位为分
            'openid' => '',//付款用户的openid
        ];
        // 1、请求参数
        $postJson = [
            "appid" => $this->appid,
            "mchid" => $this->mchid,
            "description" => '商品信息',//商品信息
            "out_trade_no" => $pay_info['out_trade_no'],//自己平台的订单号
            //用于接收微信支付结果的回调接口(注意回调接口不能加什么是否登录验证信息,需要外网能直接访问的地址)
            "notify_url" => 'https://ffe8-113-249-28-138.ngrok-free.app/api/Pay/payBack',
            "amount" => [
                "total" => $pay_info['total'] //付款金额,单位为分
            ],
            "payer" => [
                "openid" => $pay_info['openid'],//付款用户的openid
            ],
        ];
        $time = time();
        // 2、头部签名
        $url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
        $urlarr = parse_url($url);
        $data = json_encode($postJson);
        $noncestr =$this-> randstrpay();//签名所需随机字符串
        $key = $this->getSign($data, $urlarr['path'], $noncestr, $time);//签名

//        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', '商户号', '微信支付API证书序列号', $noncestr, $time, $key);//头部信息
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $this->mchid, $this->serial_number, $noncestr, $time, $key);//头部信息
        $header = [
            'Content-Type:' . 'application/json; charset=UTF-8',
            'Accept:application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        ];
        $resp = postCurl($url, $data, $header);
        $resp = json_decode($resp, true);
        if (isset($resp['prepay_id'])) {
            $return = [
                "appId" => $this->appid,
                "timeStamp" => $time,
                'prepay_id' => 'prepay_id=' . $resp['prepay_id'],
                'paySign' => $this->getWechartSign('wxf1edd999226319ea', $time, $noncestr, 'prepay_id=' . $resp['prepay_id']),//微信支付(小程序)签名
                "nonceStr" => $noncestr
            ];
            return $return;
        } else {
            //apiReturn是我自己封装的返回的json格式
            apiReturn(303, '支付订单创建失败!', $resp);
        }

    }


    /**
     *Api Name:生成微信支付签名
     *Developer:TH
     *Time:2024年05月30日 09:31
     */
    public function getSign($data = [], $url, $randstr, $time)
    {
        $str = "POST" . "\n" . $url . "\n" . $time . "\n" . $randstr . "\n" . $data . "\n";
        $key = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apiclient_key.pem');//在商户平台下载的秘钥
        $str = $this->getSha256WithRSA($str, $key);
        return $str;
    }


    /**
     *Api Name:调起支付的签名
     *Developer:TH
     *Time:2024年05月30日 09:32
     */
    public function getWechartSign($appid, $timeStamp, $noncestr, $prepay_id)
    {
        $str = $appid . "\n" . $timeStamp . "\n" . $noncestr . "\n" . $prepay_id . "\n";

        $key = file_get_contents($_SERVER['DOCUMENT_ROOT'] . '/apiclient_key.pem');
        $str = $this->getSha256WithRSA($str, $key);
        return $str;
    }


    public function getSha256WithRSA($content, $privateKey)
    {
        $binary_signature = "";
        $algo = "SHA256";
        openssl_sign($content, $binary_signature, $privateKey, $algo);
        $sign = base64_encode($binary_signature);
        return $sign;
    }
		/**
		 *Api Name:生成32位随机字符串
		 *Developer:TH
		 *Time:2024年06月13日 10:22
		 */
		public function randstrpay($length = 32)
		{
		    $rand = '';
		    $randstr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
		    $max = strlen($randstr) - 1;
		    mt_srand((double)microtime() * 1000000);
		    for ($i = 0; $i < $length; $i++) {
		        $rand .= $randstr[mt_rand(0, $max)];
		    }
		    return $rand;
		}

JSAPI下单成功后会返回以下参数
在这里插入图片描述

3.小程序端根据预支付交易会话标识 调起支付API

小程序端示例:

		// 模拟支付
		pay: function() {
			
			wx.requestPayment
			(
				{
					"timeStamp": "1718348859",
					"nonceStr": "R5AK20MQQZIZFMAD170J2124CE6WLJ1J",
					"package": "prepay_id=wx14150738126675942c8a76a8a13b8a0000",
					"signType": "RSA",
					"paySign": "q2ZVp5DUpYSxgUu5aCNrlLj7m81mL9GDMw0TE2EkYvqAI29/jFKP9FctE0f78S+qs1p3STaHKpOnHc6gy0K4FOW7CO8tER00FlNyxVYwhTOV0SsGwLaKV239iizt3iYVQS2VkfwdyH3mTn27PHyBdww1LvDLLlXdLCmdrcE4OM5VGemAHgJuPR0PcZC19ufweC8ALoKF/FHYra9uX3Rbph1LVeu6VpB2nCDO6fVR5TpY27cehJY7tGemar/f+9NAMvmgIZOpFps4kUNOV1wqcDjAkTJYIb5LmVdgiZbUwJYz9LCxvXEjXpsrj9VvTrwjyLc1Ifvj4JPzNlfIrf0fzw==",
					"success":function(res){
						console.log(res);
					},
					"fail":function(res){},
					"complete":function(res){}
				}
			)
			},

4.支付成功后通过第二步设置的回调地址进行支付成功后订单逻辑支付
示例:

    /**
     *Api Name:支付回调结果处理
     *Developer:TH
     *Time:2024年06月14日 10:06
     */
    public function payBack()
    {
        $xml = file_get_contents('php://input');//微信回调返回的结果

        $post = json_decode($xml, true);

        $text = base64_decode($post['resource']['ciphertext']);
        //对加密数据解密 注:sodium_crypto_aead_aes256gcm_decrypt需要你运行的PHP版本>=7.1
        $str = sodium_crypto_aead_aes256gcm_decrypt($text, $post['resource']['associated_data'], $post['resource']['nonce'], '微信支付v3密钥');
        $res = json_decode($str, true);
        if ($res['trade_state'] == 'SUCCESS') {
            //按照自己的需求,进行订单逻辑处理
            
        } else {
            apiReturn(303, '发生未知错误,请联系管理员处理');
        }
    }

小程序支付到这基本就算完成了,中途发生问题可以百度解决,实际请按自己的需求进行代码完善

2. 小程序申请退款

官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_9.shtml
根据文档说明,退款操作就比支付简单多了

 public function apply_refund()
    {
        //模拟退款数据
        $data = ['money' => '1',];


        // 1、请求参数
        $postJson = [
            "out_trade_no" => '',//原支付交易对应的商户订单号
            "out_refund_no" => '',//商户系统内部的退款单号
            //异步接收微信支付退款结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 如果参数中传了notify_url,
            //则商户平台上配置的回调地址将不会生效,优先回调当前传的这个地址。
            "notify_url" => '',
            "amount" => [
                "refund" => (int)$data['money'],//退款金额(注意数据类型为int类型)
                "total" => (int)$data['money'],//原支付交易的订单总金额,单位为分,只能为整数(注意数据类型为int类型)
                "currency" => "CNY",//符合ISO 4217标准的三位字母代码,目前只支持人民币:CNY。
            ],
        ];
        $time = time();
        // 2、头部签名
        $url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds';
        $urlarr = parse_url($url);
        $post = json_encode($postJson);
        $noncestr = $this->randstrpay();//签名所需随机字符串
        $key = $this->getSign($post, $urlarr['path'], $noncestr, $time);//签名

//        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', '商户号', '微信支付API证书序列号', $noncestr, $time, $key);//头部信息
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $this->mchid, $this->serial_number, $noncestr, $time, $key);//头部信息
        $header = [
            'Content-Type:' . 'application/json; charset=UTF-8',
            'Accept:application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        ];
        $resp = postCurl($url, json_encode($postJson), $header);
        $resp = json_decode($resp, true);
        if ($resp['status'] == 'SUCCESS' || $resp['status'] == 'PROCESSING') {
            //退款成功后逻辑处理
            return true;
        } else {
            //退款失败逻辑处理
            return false;
        }


    }

这里只做演示,具体应根据自己的需求做调整

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值