- const APPID = 'wxb111';
- const MCHID = '15011111';
- const KEY = 'ET5g111111E3dxMb7iUxL'; //这个KEY就是
- const NOTIFY_URL = "https://www.xxxx.cn/order/WxPay/notify.php";
然后在index.php里填写自己app或小程序传来的参数,这个index.php也就是自己的app或小程序访问的入口:
- ……
- 不管是用Post还是Get方法,总之要获取从app或小程序传来的自己的参数和生成预支付订单所需要的参数
- ……
- /////////////////////////
- //填写生成统一下单的各项参数
- /////////////////////////
- // 商品或支付单简要描述
- $subject = 'XXX-订单号:' . $request_json['jxcbillnumber']; //自己的商城或平台的商品名或订单号
- //之前有乱码问题,现在好像只要是utf-8就不会乱码,所以不用转成iso-8859-1了,至少php平台大家都会用utf-8来做开发,java平台对编码问题很敏感,可能要注意
- //$subject = iconv("utf-8","iso-8859-1",$subject);
- // 内部订单号,示例代码使用时间值作为唯一的订单ID号,如果使用自己创建的订单号,如果取消支付了,再次支付时会发生错误,所以可能要每次生成不同的内部订单号
- //$out_trade_no = date('YmdHis', time());
- //订单金额,以分为单位
- $total = 1;
- $unifiedOrder = new WxPayUnifiedOrder();
- $unifiedOrder->SetBody($subject); //商品或支付单简要描述
- $unifiedOrder->SetOut_trade_no($out_trade_no); //支付订单号
- $unifiedOrder->SetTotal_fee($total); //订单金额,也就支付金额,以分为单位
- ////////////////////////////////////////////////////////////////////////////////////
- //APP只要一个参数
- //$unifiedOrder->SetTrade_type("APP");
- //JSAPI需要再设置openid
- $unifiedOrder->SetTrade_type("JSAPI");
- $unifiedOrder->SetOpenid( $request_json['openid'] ); //openid是什么不用多解释了吧,做过微信公众号的都知道
- ///////////////////////////////////////////////////////////////////////////////////
- //查看生成订单前的各项数据
- console_log_wx( 'unifiedOrder前::' . json_encode( $unifiedOrder->GetValues() ) );
- $result1 = WxPayApi::unifiedOrder($unifiedOrder);
- //查看生成订单后的各项数据
- console_log_wx( 'unifiedOrder后::' . json_encode($result1) );
- //生成的统一下单结果发回app或小程序
- if (is_array($result1)) {
- echo json_encode($result1);
- }
- //查询生成的统一下单情况,可以看到生成的订单有什么错误,但是这个错误也不准确,很不靠谱
- $result2 = WxPayApi::orderQuery($unifiedOrder);
- console_log_wx( 'orderQuery::'.json_encode($result2) );
生成了统一下单的参数,返回给App或小程序,App用plus.payment.request(), 小程序用uni.requestPayment(),可以唤起支付窗口,但是得到一个-1的提示,大家遇到的最多了,如果查询统一下单查询的日志:
- $result2 = WxPayApi::orderQuery($unifiedOrder);
- console_log_wx( 'orderQuery::'.json_encode($result2) );
可能就会看到:调用支付JSAPI缺少参数: total_fee,支付验证签名失败,不识别的参数body!!!等奇怪错误,然后开始折腾total_fee,折腾utf-8转iso-8859-1,都没用,原因是微信那边在生成预支付订单后,不同的平台,对参数的个数和名字有所不同:
再仔细读一下这两个平台的流程和相关参数的说明:
========================
APP
========================
App的业务流程:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_3
App的参数说明:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12
没时间看文档,我们就直接贴图吧,这是供:plus.payment.request()在App唤起支付调用的参数,注意这里变量名都是小写的,而且没有下划线,没有驼峰命名
并且prepayid的内容就是prepayid的内容,不需要写成prepay_id=xxxxxx
========================
JSAPI
========================
JSAPI也就是公众号或小程序的业务流程:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_4
JSAPI也就是公众号或小程序的参数说明:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
***这些参数也就是供uni.requestPayment()在公众号或小程序里唤起支付调用的参数,注意这里的变量名跟App有所不同,个数也不同,而且package要写成prepay_id=xxxxxx的格式,真是个大坑啊!!!如果这里有一个字符不对或者大小写不对,就会支付失败,然后给出莫名其妙的错误
直接上图:
两种方式里都提到了签名,签名又是什么呢?看官方的说明,其实二者是一样的算法,只是参数个数不同,参数的名字也不同,参数的内容细微差别,两个文档里都提到:注意:签名方式一定要与统一下单接口使用的一致:
APP的签名说明:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
JSAPI的签名说明:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
是时候回去再看:https://github.com/dcloudio/H5P.Server/tree/master/payment/wxpayv3里的代码了,在WxPay.Api.php这个文件里,有关签名的部分:
- public static function unifiedOrder($inputObj, $timeOut = 6)
- {
- $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
- //检测必填参数
- if(!$inputObj->IsOut_trade_noSet()) {
- throw new WxPayException("缺少统一支付接口必填参数out_trade_no!");
- }else if(!$inputObj->IsBodySet()){
- throw new WxPayException("缺少统一支付接口必填参数body!");
- }else if(!$inputObj->IsTotal_feeSet()) {
- throw new WxPayException("缺少统一支付接口必填参数total_fee!");
- }else if(!$inputObj->IsTrade_typeSet()) {
- throw new WxPayException("缺少统一支付接口必填参数trade_type!");
- }
- //关联参数
- if($inputObj->GetTrade_type() == "JSAPI" && !$inputObj->IsOpenidSet()){
- throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
- }
- if($inputObj->GetTrade_type() == "NATIVE" && !$inputObj->IsProduct_idSet()){
- throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
- }
- //异步通知url未设置,则使用配置文件中的url
- if(!$inputObj->IsNotify_urlSet()){
- $inputObj->SetNotify_url(WxPayConfig::NOTIFY_URL);//异步通知url
- }
- $inputObj->SetAppid(WxPayConfig::APPID);//公众账号ID
- $inputObj->SetMch_id(WxPayConfig::MCHID);//商户号
- $inputObj->SetSpbill_create_ip($_SERVER['REMOTE_ADDR']);//终端ip
- //$inputObj->SetSpbill_create_ip("1.1.1.1");
- $inputObj->SetNonce_str(self::getNonceStr());//随机字符串
- //签名
- $inputObj->SetSign();
- $xml = $inputObj->ToXml();
- $startTimeStamp = self::getMillisecond();//请求开始时间
- $response = self::postXmlCurl($xml, $url, false, $timeOut);
- $result = WxPayResults::Init($response);
- // 统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP。
- // 参与签名的字段名为appId,partnerId,prepayId,nonceStr,timeStamp,package。注意:package的值格式为Sign=WXPay
- $time_stamp = time();
- $pack = 'Sign=WXPay';
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///重点在下面:这段代码是App的签名用的,小程序的要改成小程序的参数格式,根据自己的环境来选用哪一段
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////
- // App输出参数列表
- $prePayParams =array();
- $prePayParams['appid'] =$result['appid'];
- $prePayParams['partnerid'] =$result['mch_id'];
- $prePayParams['prepayid'] =$result['prepay_id'];
- $prePayParams['noncestr'] =$result['nonce_str']; //这里要改成 WxPayApi::getNonceStr();
- $prePayParams['package'] =$pack;
- $prePayParams['timestamp'] =$time_stamp;
- //////////////////////////////////////////////////////
- //////////////////////////////////////////////////////
- //JSAPI小程序输出参数列表
- //输出参数列表,与App的参数有所不同,请参考最新的文档来确定参数的个数和大小写,注意!!!
- $prePayParams =array();
- $prePayParams['appId'] = $result['appid'];
- $prePayParams['timeStamp'] = time();
- $prePayParams['nonceStr'] = WxPayApi::getNonceStr();
- $prePayParams['package'] = 'prepay_id=' . $result['prepay_id'];
- $prePayParams['signType'] = 'MD5';
- //echo json_encode($prePayParams);
- $result = WxPayResults::InitFromArray($prePayParams,true)->GetValues();
- self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间
- //////////////////////////////////////////////////////
- return $result;
- }
另外notify.php也要做一些修改,这是接受微信支付成功之后的异步回传的接口