PHP实现小程序微信支付(v3版本)

本文介绍如何使用PHP实现小程序微信支付的V3版本。内容涵盖小程序端JS代码、PHP类代码及调用方法,同时指出支付成功后的微信回调数据中存在加密内容,需要解密处理。注意代码具有时效性,作者会适时更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PS:本篇文章是PHP对小程序进行微信支付v3版本的实现,仅用于对支付流程的了解,具体使用方面需要大家自行调整

小程序端JS代码:

getPrepayID(){
    var that = this
    wx.getStorage({
      key:'openid',
      success(res){
        that.setData({
          'openid':res.data
        })
      }
    })
    wx.getStorage({
      key:'username',
      success(res){
        that.setData({
          'username':res.data
        })
      }
    })
    //console.log(that.data.openid)
    wx.request({
      url: 'http://127.0.0.1:2908/wxPayV3/v3GetPrepayId.php', //此处填写你的PHP文件url地址
      method:'POST',
      header:{
        'content-type':'application/x-www-form-urlencoded'
      },
      data:{  //发送的数据,大家根据需要自行调整
        'description':'0.38mm.pen',  //商品描述,自行调整
        'openid':that.data.openid,  //用户openid,此处是从缓存中获取到的
        'total':1,                  //订单总金额,单位为分,实际使用请乘100改为以元为单位
        'username':that.data.username,  //用户的昵称,此处从缓存中获取,用于后续存放于数据库中
        'goods_id':1                //商品编号,数据库使用
      },
      success(res){
        //console.log(res)
       // that.setData({
       //   'nonceStr':res.data.nonceStr,
       //   'package':res.data.package,
       //   'paySign':res.data.paySign,
       //   'timeStamp':res.data.timeStamp,
       //   'signType':res.data.signType
       // })
        console.log(res.data)
        wx.requestPayment({
          nonceStr: res.data.nonceStr,
          package: res.data.package,
          paySign: res.data.paySign,
          timeStamp: res.data.timeStamp,
          signType: 'RSA',
          success(res){
				//自行书写成功调用的逻辑,本篇仅为了实现成功支付
          }
        })
      }
    })
  },

PHP类的相关代码:

<?php
require_once('../config/appConfig.php');  //读取相关配置,主要是appid,mch_id,serial_no,APIv3

class API_v3Connect
{
    /**
     * 获取相关配置
     */
    public function __construct()
    {
        $appid = appid;
        $mch_id = mchID;
        $serial_no = serial_no;
        $APIv3 = APIv3;
        $this->appid = $appid;
        $this->mch_id = $mch_id;
        $this->serial_no = $serial_no;
        $this->APIv3 = $APIv3;
    }

    /**
     * 用于生成请求报文的主体,最终返回json格式数据
     * @param $description :商品描述
     * @param $out_trade_no :商户订单号
     * @param $total :订单总金额
     * @param $openid :小程序微信用户身份唯一标识符
     * @return false|string
     */
    public function requestBody($description, $out_trade_no, $total, $openid)
    {
        $data = array(
            'appid' => $this->appid,
            'mchid' => $this->mch_id,
            'description' => $description,
            'out_trade_no' => $out_trade_no,
            'notify_url' => 'http://001.chutest.xyz/v3Result.php',
            'amount' => [
                'total' => $total,
            ],
            'payer' => [
                'openid' => $openid
            ]
        );
        return json_encode($data);
    }

    /**
     * 用于生成签名数据主体
     * @param $disposeUrl :此处的url是接口地址去除域名后的url
     * @param $nonce_str :32位随机字符串
     * @param $requestBody :请求报文的主体
     * @return string
     */
    public function signBody($disposeUrl, $time, $nonce_str, $requestBody)
    {
        $data = array(
            'POST', $disposeUrl, $time, $nonce_str, $requestBody, ''
        );
        return join("\n", $data);
    }

    /**
     * 用于生成签名值
     * @param $data :用于签名的数据
     * @return string
     */
    public function getSignature($data)
    {
        $private = file_get_contents('./certificate/apiclient_key.pem');
        $key = openssl_pkey_get_private($private);
        openssl_sign($data, $signature, $key, 'sha256WithRSAEncryption');
        return base64_encode($signature);
    }

    /**
     * @param $nonce_str :32位随机字符串,与上方的随机字符串保持一致
     * @param $signature :上方生成的签名值
     * @return string[]
     */
    public function getHeader($nonce_str, $signature)
    {
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%s",signature="%s"', $this->mch_id, $this->serial_no, $nonce_str, time(), $signature);
        $data = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36 Edg/103.0.1264.71',
            "Authorization: WECHATPAY2-SHA256-RSA2048 $token",
        );
        return $data;
    }

    /**
     * 使用curl完成对接口的请求
     * @param $url :接口的url地址
     * @param string $type :传输类型,若为POST需要提供$data与$header
     * @param string $data :当type = POST时需要提供,为请求主体数据
     * @param array $header :当type = POST时需要提供,为请求头
     * @return bool|string
     */
    public function curlRequest($url, string $type = '', string $data = '', array $header = [])
    {
        $action = curl_init();
        curl_setopt($action, CURLOPT_URL, $url);
        curl_setopt($action, CURLOPT_CONNECTTIMEOUT, 60);
        curl_setopt($action, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($action, CURLOPT_HEADER, 0);
        curl_setopt($action, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($action, CURLOPT_SSL_VERIFYHOST, 0);
        if ($type == 'POST') {
            curl_setopt($action, CURLOPT_POST, 1);
            curl_setopt($action, CURLOPT_POSTFIELDS, $data);
            curl_setopt($action, CURLOPT_HTTPHEADER, $header);
        }
        $result = curl_exec($action);
        curl_close($action);
        return $result;
    }

    /**
     * 构造对prepay_id再次签名的签名数据主体
     * @param $time :时间戳
     * @param $nonceStr :32位随机字符串
     * @param $prepay_id :预支付参数
     * @return string
     */
    public function paySignBody($time, $nonceStr, $prepay_id)
    {
        $data = array(
            $this->appid, $time, $nonceStr, "prepay_id=$prepay_id", ''
        );
        return join("\n", $data);
    }

    /**
     * 构造返回给小程序段的数据,json数据
     * @param $nonce_str :32位随机字符串
     * @param $prepay_id :预支付参数
     * @param $paySign :签名值
     * @param $time :时间戳
     * @param $out_trade_no :商户订单号
     * @return false|string
     */
    public function requestPayData($nonce_str, $prepay_id, $paySign, $time, $out_trade_no)
    {
        $data = array(
            'nonceStr' => $nonce_str,
            'package' => 'prepay_id=' . $prepay_id,
            'paySign' => $paySign,
            'timeStamp' => $time,
            'signType' => 'RSA',
            'out_trade_no' => $out_trade_no
        );
        return json_encode($data);
    }
}

PHP调用方法的代码:

<?php
require_once('./API_v3Connect.php');
require_once('../wxPayV2/API_Connect.php'); //此处调用v2是为了省去再次写一遍获取随机字符串与商户订单号的麻烦
require_once('../database/getDatabase.php'); //此处调用数据库,将该订单的相关信息加入数据库中

$description = $_POST['description'];  //接收商品描述
$openid = $_POST['openid'];  //接收用户的openid
$total = $_POST['total'];  //接收订单总金额
$total = (int)$total;  //将订单总金额转化为int类型,此处接收到的数据默认是string类型
$time = time();

$getPartData = new v2Connect;
$nonce_str = $getPartData->nonce_str();  //获取32位随机字符串
$out_trade_no = $getPartData->out_trade_no();  //获取商户订单号

$getData = new API_v3Connect;

$requestBody = $getData->requestBody($description, $out_trade_no, $total, $openid);  //获取请求主体的json数据

$disposeUrl = '/v3/pay/transactions/jsapi';  //处理过后的url地址 注:去掉前方的域名即可
$signBody = $getData->signBody($disposeUrl, $time, $nonce_str, $requestBody);  //获取参与签名的主体数据

$signature = $getData->getSignature($signBody);  //获取签名值

$header = $getData->getHeader($nonce_str, $signature);  //获取请求头

$url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi';  //接口的url地址
$prepay_id = $getData->curlRequest($url, 'POST', $requestBody, $header);  //获取预支付参数
$disposePrepayId = json_decode($prepay_id, true);   //将返回的数据转化为数组
$prepay_id = $disposePrepayId['prepay_id'];  //从转化的数组中获取prepay_id

$paySignBody = $getData->paySignBody($time, $nonce_str, $prepay_id);  //构造生成支付签名的签名主体数据

$paySign = $getData->getSignature($paySignBody); //对构造好的签名数据主体进行签名

$time = (string)$time; //将时间戳由int转化为string类型
$getPayData = $getData->requestPayData($nonce_str, $prepay_id, $paySign, $time, $out_trade_no); //获取返回给小程序段的数据
echo $getPayData;

支付成功后微信回调发送的数据:

{
  "id": "2dd87d80-2478-5ab0-852c-6d20084f8175",
  "create_time": "2022-07-26T17:07:28+08:00",
  "resource_type": "encrypt-resource",
  "event_type": "TRANSACTION.SUCCESS",
  "summary": "支付成功",
  "resource": {
    "original_type": "transaction",
    "algorithm": "AEAD_AES_256_GCM",
    "ciphertext": "此处显示密文,需要经过解密显示",
    "associated_data": "transaction",
    "nonce": "8oAAd7fCPvpO"
  }
}

PS:微信会掉返回的内容中部分数据是进过加密的,需要进过解密之后才会显示


本文由优快云用户: 缱绻淡蓝海 原创,代码具有时效性,作者会不定时对发布过的文章进行更新

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值