php 微信小程序支付
直接贴代码:
前端测试按钮wxml:
<view class="container"> <text class="name">当前选择:《参加活动》 ¥0.01</text> <view class="pay" bindtap="onTap">确认支付</view> </view>
wxss:
.container { padding: 50rpx; } .pay { margin-top: 30rpx; color: #fff; background-color: #1fb922; }
js:
Page({ /** * 页面的初始数据 */ onTap () { console.log(‘6666‘); let _self = this; _self._togglePay(); //发起网络请求 wx.request({ url: ‘付款url‘, method: "POST", data: { openid: ‘‘, money:0.01 }, header: { "content-type": "application/x-www-form-urlencoded" }, success(res) { var params = res.data.data; wx.requestPayment({ ‘timeStamp‘: String(params[‘timeStamp‘]), ‘nonceStr‘: params[‘nonceStr‘], ‘package‘: params[‘package‘], ‘signType‘: params[‘signType‘], ‘paySign‘: params[‘paySign‘], ‘success‘: function (res) { wx.showToast({ title: ‘支付成功‘, icon: ‘success‘, duration: 2000 }) _self._togglePay(); }, ‘fail‘: function (res) { wx.showToast({ title: ‘支付失败‘, icon: ‘none‘, duration: 2000 }) _self._togglePay(); }, }) } }) }, _togglePay() { this.setData({ pay: !this.data.pay }); } })
后端PHP代码:
首先是公共函数,处理数据用的:
// curl请求方法封装 private function postXmlCurl($xml, $url, $second = 30) { $ch = curl_init(); //设置超时 curl_setopt($ch, CURLOPT_TIMEOUT, $second); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验 //设置header curl_setopt($ch, CURLOPT_HEADER, FALSE); //要求结果为字符串且输出到屏幕上 curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); //post提交方式 curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $xml); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); curl_setopt($ch, CURLOPT_TIMEOUT, 40); set_time_limit(0); //运行curl $data = curl_exec($ch); //返回结果 if ($data) { curl_close($ch); return $data; } else { $error = curl_errno($ch); curl_close($ch); throw new Exception("curl出错,错误码:$error"); } } //数组转换成xml private function arrayToXml($arr) { $xml = "<xml>"; foreach ($arr as $key => $val) { if (is_array($val)) { $xml .= "<" . $key . ">" . $this->arrayToXml($val) . "</" . $key . ">"; } else { $xml .= "<" . $key . ">" . $val . "</" . $key . ">"; } } $xml .= "</xml>"; return $xml; } //xml转换成数组 private function xmlToArray($xml) { //禁止引用外部xml实体 libxml_disable_entity_loader(true); $xmlstring = simplexml_load_string($xml, ‘SimpleXMLElement‘, LIBXML_NOCDATA); $val = json_decode(json_encode($xmlstring), true); return $val; } //作用:产生随机字符串,不长于32位 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; } //作用:生成签名 private function getSign($Obj) { foreach ($Obj as $k => $v) { $Parameters[$k] = $v; } //签名步骤一:按字典序排序参数 ksort($Parameters); $String = $this->formatBizQueryParaMap($Parameters, false); //签名步骤二:在string后加入KEY $String = $String . "&key=" . $this->key; //签名步骤三:MD5加密 $String = md5($String); //签名步骤四:所有字符转为大写 $result_ = strtoupper($String); return $result_; } // 作用:格式化参数,签名过程需要使用 private function formatBizQueryParaMap($paraMap, $urlencode) { $buff = ""; ksort($paraMap); foreach ($paraMap as $k => $v) { if ($urlencode) { $v = urlencode($v); } $buff .= $k . "=" . $v . "&"; } $reqPar=‘‘; if (strlen($buff) > 0) { $reqPar = substr($buff, 0, strlen($buff) - 1); } return $reqPar; } /*生成订单号*/ private function out_trade_no(){ //return date(‘YmdHis‘).md5($openid.time().rand(10,99));//32位 return date(‘YmdHis‘,time()).time().rand(10,99); }
业务代码:
//统一下单 private function unifiedorder($body,$openid,$pay) { $url = ‘https://api.mch.weixin.qq.com/pay/unifiedorder‘; // 这里的参数顺序一定要按下面的,不然可能就一直报商户号此功能未授权等错误 $parameters = array( ‘appid‘ => $this->appid, // 小程序ID ‘body‘ => $body, //支付标题 ‘mch_id‘ => $this->mch_id, // 商户号 ‘nonce_str‘ => $this->createNoncestr(), // 随机字符串 ‘notify_url‘ => $this->notify_url, //‘https://shop.gdpress.cn/syw_jingzhun/index.php/Api/xiaochengxu/notify_url_api‘, // 通知地址 确保外网能正常访问 ‘openid‘ => $openid, // 用户id ‘out_trade_no‘=> $this->out_trade_no(), // 商户订单号 ‘spbill_create_ip‘ => Yii::$app->request->userIP, // 终端IP ,这是YII2框架的写法 ‘total_fee‘ => floatval($pay * 100), //支付金额 单位 分 ‘trade_type‘ => ‘JSAPI‘ // 交易类型 ); //统一下单签名 $parameters[‘sign‘] = $this->getSign($parameters); $xmlData = $this->arrayToXml($parameters); $return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60)); return $return; } //微信小程序支付接口 调用 public function actionWxpay() { $body=‘小程序支付测试‘; $openid=‘‘;//付款者openid $pay=‘0.01‘;//支付金额 //统一下单接口 $unifiedorder = $this->unifiedorder($body,$openid,$pay); // 统一下单出错,参数出错等原因 if($unifiedorder[‘return_code‘] == ‘FAIL‘) { return Json::encode([‘code‘=>400,‘msg‘=>‘支付失败‘,‘data‘=>$unifiedorder[‘return_msg‘]]); } // 对统一下单返回得参数进行处理 $parameters = array( ‘appId‘ => $this->appid, // 小程序ID ‘timeStamp‘ => ‘‘ . time() . ‘‘, // 时间戳 ‘nonceStr‘ => $this->createNoncestr(), // 随机串 ‘package‘ => ‘prepay_id=‘ . $unifiedorder[‘prepay_id‘], // 数据包 ‘signType‘ => ‘MD5‘ // 签名方式 ); // 小程序发起支付签名 $parameters[‘paySign‘] = $this->getSign($parameters); return Json::encode([‘code‘=>200,‘msg‘=>‘支付成功‘,‘data‘=>$parameters]); }
支付成功回调:
*微信支付的 异步通知 *回调地址*/ public function actionNoticefy() { $xml = file_get_contents("php://input"); //将服务器返回的XML数据转化为数组 $data = $this->xmlToArray($xml); // 判断签名是否正确 判断支付状态 if (($data[‘return_code‘] == ‘SUCCESS‘)) {//支付成功 $result = $data; //获取服务器返回的数据 $out_trade_no = $data[‘out_trade_no‘]; // 订单单号 $openid = $data[‘openid‘]; // 付款人openID $total_fee = floatval(($data[‘total_fee‘])/100); // 付款金额 $transaction_id = $data[‘transaction_id‘]; // 微信支付流水号 $time_end = $data[‘time_end‘]; // 处理时间 //查找订单 $order=ActivityOrder::find()->where([‘out_trade_no‘=>$out_trade_no])->one(); if ($order) {// 订单存在 $result=true; }else{// 订单不存在,则创建订单 $activityOrder=new ActivityOrder(); $activityOrder->out_trade_no=$out_trade_no; $activityOrder->openid=$openid; $activityOrder->activity_id=48; $activityOrder->status=1; $activityOrder->total_fee=$total_fee; $activityOrder->transaction_id=$transaction_id; $activityOrder->time_end=$time_end; $activityOrder->userIP=Yii::$app->request->userIP; $activityOrder->create_time=time(); if ($activityOrder->save()){ $result=true; }else{ $result = false; } } }else {//支付失败 $result = false; } // 返回状态给微信服务器 if ($result) { $str=‘<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>‘; }else{ $str=‘<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>‘; } return $str; }
注:本支付基于Yii2框架编写,若用其他框架,请自行改掉名称等Yii2专有函数。