前期准备:
1.开通了微信支付,并且小程序绑定了微信支付;
2.准备好小程序的appid,微信支付的商户号,支付秘钥。
商户系统和微信支付系统主要交互:
1、小程序内调用登录接口,获取到用户的openid
此步骤在小程序内完成,也很简单,方法见:【小程序登录API】
2、调用商户服务器支付统一下单接口,进行预支付
- /**
- * 预支付请求接口(POST)
- * @param string $openid openid
- * @param string $body 商品简单描述
- * @param string $order_sn 订单编号
- * @param string $total_fee 金额
- * @return json的数据
- */
- public function prepay(){
- $config = $this->config;
- $openid = I('post.openid');
- $body = I('post.body');
- $order_sn = I('post.order_sn');
- $total_fee = I('post.total_fee');
- //统一下单参数构造
- $unifiedorder = array(
- 'appid' => $config['appid'],
- 'mch_id' => $config['pay_mchid'],
- 'nonce_str' => self::getNonceStr(),
- 'body' => $body,
- 'out_trade_no' => $order_sn,
- 'total_fee' => $total_fee * 100,
- 'spbill_create_ip' => get_client_ip(),
- 'notify_url' => 'https://'.$_SERVER['HTTP_HOST'].'/Api/Wxpay/notify',
- 'trade_type' => 'JSAPI',
- 'openid' => $openid
- );
- $unifiedorder['sign'] = self::makeSign($unifiedorder);
- //请求数据
- $xmldata = self::array2xml($unifiedorder);
- $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
- $res = self::curl_post_ssl($url, $xmldata);
- if(!$res){
- self::return_err("Can't connect the server");
- }
- // 这句file_put_contents是用来查看服务器返回的结果 测试完可以删除了
- //file_put_contents(APP_ROOT.'/Statics/log1.txt',$res,FILE_APPEND);
- $content = self::xml2array($res);
- if(strval($content['result_code']) == 'FAIL'){
- self::return_err(strval($content['err_code_des']));
- }
- if(strval($content['return_code']) == 'FAIL'){
- self::return_err(strval($content['return_msg']));
- }
- self::return_data(array('data'=>$content));
- //$this->ajaxReturn($content);
- }
- /**
- * 进行支付接口(POST)
- * @param string $prepay_id 预支付ID(调用prepay()方法之后的返回数据中获取)
- * @return json的数据
- */
- public function pay(){
- $config = $this->config;
- $prepay_id = I('post.prepay_id');
- $data = array(
- 'appId' => $config['appid'],
- 'timeStamp' => time(),
- 'nonceStr' => self::getNonceStr(),
- 'package' => 'prepay_id='.$prepay_id,
- 'signType' => 'MD5'
- );
- $data['paySign'] = self::makeSign($data);
- $this->ajaxReturn($data);
- }
小程序端代码:
- wx.requestPayment({
- 'timeStamp': '',
- 'nonceStr': '',
- 'package': '',
- 'signType': 'MD5',
- 'paySign': '',
- 'success':function(res){
- },
- 'fail':function(res){
- }
- })
- //微信支付回调验证
- public function notify(){
- $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
- // 这句file_put_contents是用来查看服务器返回的XML数据 测试完可以删除了
- //file_put_contents(APP_ROOT.'/Statics/log2.txt',$res,FILE_APPEND);
- //将服务器返回的XML数据转化为数组
- $data = self::xml2array($xml);
- // 保存微信服务器返回的签名sign
- $data_sign = $data['sign'];
- // sign不参与签名算法
- unset($data['sign']);
- $sign = self::makeSign($data);
- // 判断签名是否正确 判断支付状态
- if ( ($sign===$data_sign) && ($data['return_code']=='SUCCESS') && ($data['result_code']=='SUCCESS') ) {
- $result = $data;
- //获取服务器返回的数据
- $order_sn = $data['out_trade_no']; //订单单号
- $openid = $data['openid']; //付款人openID
- $total_fee = $data['total_fee']; //付款金额
- $transaction_id = $data['transaction_id']; //微信支付流水号
- //更新数据库
- $this->updateDB($order_sn,$openid,$total_fee,$transaction_id);
- }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>';
- }
- echo $str;
- return $result;
- }
小程序端完整代码如下:
- /**
- * 支付函数
- * @param {[type]} _payInfo [description]
- * @return {[type]} [description]
- */
- pay:function(_payInfo,success,fail){
- var payInfo = {
- body:'',
- total_fee:0,
- order_sn:''
- }
- Object.assign(payInfo, _payInfo);
- if(payInfo.body.length==0){
- wx.showToast({
- title:'支付信息描述错误'
- })
- return false;
- }
- if(payInfo.total_fee==0){
- wx.showToast({
- title:'支付金额不能0'
- })
- return false;
- }
- if(payInfo.order_sn.length==0){
- wx.showToast({
- title:'订单号不能为空'
- })
- return false;
- }
- var This = this;
- This.getOpenid(function(openid){
- payInfo.openid=openid;
- This.request({
- url:'api/pay/prepay',
- data:payInfo,
- success:function(res){
- var data = res.data;
- console.log(data);
- if(!data.status){
- wx.showToast({
- title:data['errmsg']
- })
- return false;
- }
- This.request({
- url:'api/pay/pay',
- data:{prepay_id:data.data.data.prepay_id},
- success:function(_payResult){
- var payResult = _payResult.data;
- console.log(payResult);
- wx.requestPayment({
- 'timeStamp': payResult.timeStamp.toString(),
- 'nonceStr': payResult.nonceStr,
- 'package': payResult.package,
- 'signType': payResult.signType,
- 'paySign': payResult.paySign,
- 'success': function (succ) {
- success&&success(succ);
- },
- 'fail': function (err) {
- fail&&fail(err);
- },
- 'complete': function (comp) {
- }
- })
- }
- })
- }
- })
- })
- }