准备工作:
申请小程序AppID、APPSECRET、MCHID(商户ID)、KEY(商户密钥)
制作签名,签名需要五个参数分别是:appId(小程序AppID)、timeStamp(当前时间戳)、nonceStr(随机字符串)、package(统一下单返回数据包,注意参数值的格式一定要是:prepay_id=数据包)、signType(加密类型,默认MD5就行了)。
wx.requestPayment中的随机字符串与当前时间戳一定要与签名中的保持一致,不然会报“支付验证签名错误”,拿签名中的参数值拉起支付。
小程序端:
wxml
<button type='primary' class='submit' bindtap='payment'>确认充值</button> <view wx:if='{{show}}'> <view class='marks'> <view class='myLoginContent'> <view class='myLoginTitle'> <text>请先登录</text> </view> <button open-type="getUserInfo" bindgetuserinfo='bindGetUserInfo' class='myLogin'> <image src='/pages/images/wx.png'> </image> 微信用户快捷登录 </button> </view> </view> </view>js
// 登录授权 bindGetUserInfo: function (res) { let that = this; wx.login({ success: function (rea) { wx.getUserInfo({ success: function (info) { let obj = { userinfo: info.rawData, code: rea.code } utils.postRequest('Index/getModeOpenid', obj, '登录中', (res) => { wx.setStorageSync('modeInfo', res.data.data); console.log(res) that.setData({ modeInfo: wx.getStorageSync('modeInfo'), openid: res.data.data.openid, show: false }) }) } }) } }) }, /** * 充值支付 * store_id 门店id * total_fee 充值金额 */ payment: function() { let that = this; let payInfo = { store_id: that.data.store_id, sms_money: that.data.total_fee, openid: that.data.openid } utils.postRequest('Manager/WxPay', payInfo, '加载中', (res) => { let payResult = res.data.data; that.payCallBack(payResult); }) }, /** * 微信唤醒支付的回调操作 */ payCallBack: function(payResult) { wx.requestPayment({ 'timeStamp': payResult.timeStamp.toString(), 'nonceStr': payResult.nonceStr, 'package': payResult.package, 'signType': payResult.signType, 'paySign': payResult.paySign, 'success': function (res) { if (res.errMsg == "requestPayment:ok") { wx.showModal({ title: '支付', content: '恭喜您支付成功', showCancel: false, success: function (res) { that.onShow() }, }) } else if (res.errMsg == 'requestPayment:cancel') { wx.showModal({ title: '支付', content: '很遗憾!您支付失败啦', showCancel: false, success: function (res) { }, }) } }, 'fail': function (err) { // 取消支付 console.log(err) }, 'complete': function (comp) { } }) },服务端:
public function WxPay(){ $id = input('get.product_id/d') <= 0 ? $this->ReturnStatus(false,'充值ID异常') : input('get.product_id/d'); $uid = empty(input('get.uid')) ? $this->ReturnStatus(false,'UID异常') : input('get.uid/d'); $money = db('goods') ->field('price,describe,type_id') ->where('id',$id) ->find(); //导入微信支付类库 import('SmallWxPay.WxPayApi'); //调用统一下单接口 $input = new \WxPayUnifiedOrder(); $input->SetBody($money['describe']);//商品描述 $input->SetAttach($money['describe']);//商品附加描述 $out_trade_no = \WxPayConfig::MCHID.date("YmdHis"); $input->SetOut_trade_no($out_trade_no);//唯一订单号 $input->SetTotal_fee(intval($money['price']));//金额 $input->SetTime_start(date("YmdHis"));//开始时间 $input->SetTime_expire(date("YmdHis", time() + 600));//结束时间 $input->SetNotify_url("https://www.***.com/home/Wxnotify/notify");//异步回调地址 $input->SetTrade_type("JSAPI");//交易类型:小程序填JSAPI $openId = db('member') ->where('id',$uid) ->value('small_open_id'); $input->SetOpenid($openId);//用户Openid $result = \WxPayApi::unifiedOrder($input);//调用微信API提交数据并取得返回 $type = $money['type_id'] == 2 || $money['type_id'] == 3 ? 2 : 1;//充值类型 $res = array(); //判断预支付是否成功 if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){ //生成签名 $nonceStr = $this->createNoncestr();//随机字符串 //生成签名所需参数 $sign_arr = array( 'appId' => $result['appid'],//小程序Appid 'timeStamp' => strval(time()),//当前时间戳 'nonceStr' => $nonceStr,//随机字符串32位 'package' => 'prepay_id='.$result['prepay_id'],//统计下单返回 'signType' => 'MD5',//加密类型 ); ksort($sign_arr);//根据键,以升序对关联数组进行排序 $sign = ""; //拼接签名 foreach ($sign_arr as $k => $v) { if($k != "sign"){ $sign .= $k . "=" . $v . "&"; } } $sign = trim($sign, "&"); $sign = $sign.'&key='.\WxPayConfig::KEY;//KEY拼接到最后 $sign_md = md5($sign);//md5加密 $sign_res = strtoupper($sign_md);//转为大写 $res = array( 'sign' => $sign_res,//签名 'time' => $sign_arr['timeStamp'],//当前时间戳 'nonceStr' => $sign_arr['nonceStr'],//随机字符串32位 'prepay_id' => 'prepay_id='.$result['prepay_id'],//统一下单返回数据包 ); }else{ $this->ReturnStatus(false,'充值异常'); } return $result['return_code'] == 'SUCCESS' ? $this->ReturnStatus(true,'成功',$res) : $this->ReturnStatus(false,'失败',$result); } /* * 生成随机字符串 * @author DongQiang */ private function createNoncestr($length = 32) { $chars = "abcdefghijklmnopqrstuvwxyz0123456789"; $str = ""; for ($i = 0; $i < $length; $i++) { $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1); } return $str; }