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

先解答上一篇博客中form_id的获取方法:
js代码


Page({
  formSubmit: function (e) {
    console.log("formid:"+e.detail.formId)
  },
})

wxml代码

<form bindsubmit="formSubmit" report-submit="ture">
    <button formType="submit">submit</button>
</form>

结果:
在这里插入图片描述

注意两点

  1. 表单wxml中需要加入,普通表单是不携带formId。
  2. formId只在真器中才能获取,开发者工具无法获取。

下面开始讲解PHP实现微信小程序支付

准备工作:

1.你的小程序做过微信认证并且开通微信支付(相信能学编程的都不是愚笨之人,跟着微信指引填写资料就行,剩下就等他客服打电话给你)
2.微信小程序appid
3.微信商户号mch_id(开户邮件里面有)
4.微信API密钥key(登录商户平台->账户中心->API安全自行设置)

开发步骤:

1.获取prepay_id
2.获取paySign

封装方法代码:

<?php
namespace App\libs\Pay;
use App\libs\HttpUtils\HttpUtils;
class WxPay
{
    const url = "https://api.mch.weixin.qq.com/pay/unifiedorder";  
    const key = "";                                                                           
    const appid = "";                                                                       
    const mch_id = "";
    const total_fee = "";
    const notify_url = "";
    const body = "";

    /**
     * 微信统一下单 所有参数为必填项 数据传输格式为xml 提交方式POST 其他可选项参照微信官方文档
     * @param url 统一下单地址
     * @param key API密钥 微信支付平台自定义
     * @param appid 小程序appid 微信公众平台获取
     * @param mch_id 商户号 微信支付平台获取
     * @param total_fee 金额 单位:分  作者写的东西金额是固定的,可作为参数传入函数
     * @param notify_url 异步接收微信支付结果通知的回调地址
     * @param nonce_str  随机字符串,长度要求在32位以内 下方已给出方法str_rand()
     * @param sign 通过签名算法计算得出的签名值 签名算法getSignTemp():1.参数名ASCII码从小到大排序(字典序)2.如果参数的值为空不参与签名;3.参数名区分大小写 4.验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。
     * @param out_trade_no 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一
     * @param openid 用户对应小程序的openid
     * @param body 商品描述 如:腾讯充值中心-QQ会员充值
     * @param trade_type 小程序取值如下:JSAPI 其他支付参照官方文档
     */
    public static function PrePay($out_trade_no,$openid){
        $nonce_str=self::str_rand();      //生成随机32位字符串
        $SignTemp=self::getSignTemp($nonce_str,$openid,$out_trade_no);  // 生成签名
        $data=[
            "appid"=>self::appid,     //appid
            "mch_id"=>self::mch_id, //商户号
            "nonce_str"=>$nonce_str,  //随机字符串
            "sign"=>$SignTemp,    //签名
            "body"=>self::body,   //商品描述
            "out_trade_no"=>$out_trade_no, //订单号
            "total_fee"=>self::total_fee,   //金额
            "trade_type"=>"JSAPI",  //支付类型 小程序取值如下:JSAPI 其他支付参照官方文档
            "notify_url"=>self::notify_url,  //异步接收微信支付结果通知的回调地址
            "openid"=>$openid   //用户对应小程序的openid
        ];
        $result=HttpUtils::curl(self::url,$params=self::XmlAndArray($data,"array"),$ispost=1,$https=1);//请求接口得到预支付信息,curl方法在前一篇文章已经贴出,参数必须为xml格式,方法已给出XmlAndArray()
        return self::XmlAndArray($result,"xml"); //转化为数组方便取值,返回结果
    }
    public static function getPaySign($prepay_id,$nonce_str){
        $timeStamp=time();//时间戳
        $PaySign=md5("appId=".self::appid."&nonceStr=".$nonce_str."&package=prepay_id=".$prepay_id."&signType=MD5&timeStamp=".(string)$timeStamp."&key=".self::key);//生成支付签名,严格按照官方要求填写参数
        return ["PaySign"=>$PaySign,"timeStamp"=>$timeStamp];//返回签名以及时间戳
    }

    private static function getSignTemp($nonce_str,$openid,$out_trade_no){
        $SignTemp="appid=".self::appid."&body=".self::body."&mch_id=".self::mch_id."&nonce_str=".$nonce_str."&notify_url=".self::notify_url."&openid=".$openid."&out_trade_no=".$out_trade_no."&total_fee=".self::total_fee."&trade_type=JSAPI";//生成下单签名,严格按照官方要求填写参数
        $SignTemp=md5($SignTemp."&key=".self::key);
        return $SignTemp; //返回签名,统一下单需要调用
    }

    /**
     * 数组与XML互转 方便取数据
     * @param $data
     * @param $type 转换对象
     * return 数组或XML
     */

    private static function XmlAndArray($data,$type)
    {
        if(!$data){
            return false;
        }
        else if($type=="xml"){
            libxml_disable_entity_loader(true);
            $values = json_decode(json_encode(simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
            return $values;
        }
        else if($type=="array"){
            $xml="<xml>";
            foreach ($data as $key=>$val){

                $xml.="<".$key.">".$val."</".$key.">";

            }
            $xml.="</xml>";
            return $xml;
        }
    }
    /**
     * 随机字符串生成
     * @param $length 字符串长度
     * @param $char  字符集
     * return $string 随机字符串
     */

    private static function str_rand($length = 32, $char = 'abcdefghijklmnopqrstuvwxyz0123456789') {
        $str ="";
        for ( $i = 0; $i < $length; $i++ )  {
            $str .= substr($char, mt_rand(0, strlen($char)-1), 1);
        }
        return $str;
    }
}

调用代码,我用的laravel框架,可以自行重构

<?php


namespace App\Http\Controllers\Pay;
use App\Http\Controllers\Controller;
use App\libs\Pay\WxPay;
use Illuminate\Http\Request;


class PayController extends Controller
{
    public function getPrePay(Request $request){
        $openid=$request->get("openid");    //接收openid
        $out_trade_no="";  //订单号
        $PrePay=WxPay::PrePay($out_trade_no,$openid);  //统一下单
        if($PrePay["return_code"]=="FAIL"){
            /*返回错误*/
        }
        else{
            $PrePayId=$PrePay["prepay_id"];  // 获取预支付id
            $PaySign=WxPay::getPaySign($PrePayId,$PrePay["nonce_str"]); 生成支付签名
            echo json_encode(["prepay_id"=>$PrePayId,"paySign"=>$PaySign["PaySign"],"nonce_str"=>$PrePay["nonce_str"],"timeStamp"=>$PaySign["timeStamp"],"order_no"=>$out_trade_no]); //返回小程序中拉起支付所需要的信息
        }
    }
}

小程序调用代码:

 wx.request({
      url: "你的服务器端接口地址",
      data: {
        openid: "用户的openid",
      },
      header: {
        'content-type': 'application/json'
      },
      success: function (res) {
        let prepay_id = res.data.prepay_id  //预支付id
        let order_no = res.data.order_no    //订单号
        let timeStamp = String(res.data.timeStamp)  //服务器端返回的时间戳,必须强转字符串,微信要求的
        let nonceStr = res.data.nonce_str //服务器返回的随机字符串
        let package = 'prepay_id=' + res.data.prepay_id //package需要这么填写,自己注意
        let paySign = res.data.paySign //支付签名
        if (res.data.code == "") {  
         //服务器端预支付处理失败提示 
          wx.showToast({
            title: '下单失败',
            icon: 'none',
            duration: 1000
          })
        }
        else {
          // 拉起微信支付
          wx.requestPayment({
            'timeStamp': timeStamp,
            'nonceStr': nonceStr,
            'package': package,
            'signType': 'MD5',
            'paySign': paySign,
             success: function (res) {
              //接口调用成功的回调函数
             },
             fail:function(res){
               //接口调用失败的回调函数
             },
             complete:function(res){
               //接口调用结束的回调函数(调用成功、失败都会执行)
             }
          })
        }
      }
    })

总结

  1. 最重要的就是生成签名一定要按照官方给出的文档,参数顺序不能搞错!!!
  2. 所有接口返回的都是xml,为了方便我都转化成数组,方法也在代码中给出。
  3. 随机字符串生成后,会在统一下单接口返回值中给出,生成PaySign签名时延用就行,第一次开发就卡在这,能拉起支付,然后闪退说PaySign错误
  4. 统一下单接口返回的prepay_id就是模板消息需要的参数,支付成功后就可以用此参数调用模板消息提示用户
  5. 作者自己写了个小程序BadBoy,有兴趣的可以搜索来玩玩,其中的代码可找作者索取
  6. 微信小程序交流群:895964328 php交流群:165728481
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值