php实现小程序支付完整版


Posted in PHP onOctober 09, 2018

本文实例为大家分享了php实现小程序支付的具体代码,供大家参考,具体内容如下

环境: tp3.2  + 小程序 微信支付功能开通

Step1:  下载PHP 支付SDK(下载地址)  放到Library\Vendor下,取名Wxpay           

修改WxPay.Config.php 里的appid appsecret key MCHID

Step2: 小程序 js 代码:

var url = getApp().globalData.httpServer + 'api/buy/pay';
    var userId = getApp().globalData.userId;
    var totalMoney = this.data.totalMoney;
    var cart = this.data.goods;
    var param = {
      cart: JSON.stringify(cart),
      cartamount: totalMoney,
      userid: userId,
      payment: this.data.payment,
      addressid: defaultAddress.id
    };
    var that = this;
    util.http(url, param, function (ret) {
      if (ret.data.code == 1) {
        if (that.data.payment == 'balance') { // 余额支付
          that.afterPaySuccess(ret.data.data);
        } else {                // 微信支付
          wx.requestPayment({
            timeStamp: ret.data.data.timeStamp,
            nonceStr: ret.data.data.nonceStr,
            package: ret.data.data.package,
            signType: ret.data.data.signType,
            paySign: ret.data.data.paySign,
            'success': function (res) {
              that.afterPaySuccess(ret.data.data.orderid);
            },
            'fail': function (res) {
              console.log(res);
            }
          })          
 
 
        }
 
      } else {
        util.showTip(ret.data.msg, '提交订单失败');        
      }
    });
/**
 * 网络请求
 */
function http(url, params, callback) {
  wx.request({
    url: url,
    data: params,
    success: function (res) {
      callback(res);
    },
 
    fail: function (err) {
      console.log(err);
    }
  });
}

Step3: 接口代码:

public function pay()
  {
    $cart = I('cart', '', 'trim');
    $cartAmount = I('cartamount');
    $addressId = I('addressid', 0, 'intval');
    $payment = I('payment', '', 'trim');
    $userId = $this->userid;
 
    $cart = json_decode($cart, true);
    if (empty($cart)) {
      $result['msg'] = '购物车获取失败';
      $result['code'] = 0;
      $this->ajaxReturn($result);
    }
 
    $totalMoney = 0;
    foreach ($cart as $goods) {
      $money = $goods['price'];  // price
      $selectCount = $goods['selectcount'];  // price
      $itemAmount = number_format($money * $selectCount, 2, '.', '');
      $totalMoney += $itemAmount;
    }
    // 检查总金额是否一致
    if ($totalMoney != $cartAmount) {
      $result['msg'] = '总金额不匹配:' . $totalMoney;
      $result['code'] = 0;
      $this->ajaxReturn($result);
    }
 
    // 获取用户地址
    $address = M('MemberAddress')->where('userid=' . $userId . " and id=" . $addressId)->find();
    if (empty($address)) {
      $result['msg'] = '用户地址不存在';
      $result['code'] = 0;
      $this->ajaxReturn($result);
    }
 
    // 用户信息
    $user = M('Member')->where("id=" . $userId)->find();
    if ($payment == 'balance') {
      if ($user['amount'] < $cartAmount) {
        $result['msg'] = '余额不足';
        $result['code'] = 0;
        $this->ajaxReturn($result);
      }
    }
 
    // 生成订单
    $order['ordersn'] = $this->genOrdersn($user['id']);
    $order['price'] = $cartAmount;
    $order['addressid'] = $address['id'];
    $order['addressinfo'] = serialize($address); //json_encode($address);
    $order['longitude'] = $address['longitude'];
    $order['latitude'] = $address['latitude'];
    $order['addtime'] = time();
    $order['status'] = 0;
    $order['userid'] = $user['id'];
    $order['paytype'] = $payment;
    $order['paysn'] = '';
    $order['paytime'] = time();
    $orderId = M("Order")->add($order);
    if ($orderId == 0) {
      $result['msg'] = '创建订单失败';
      $result['code'] = 0;
      $this->ajaxReturn($result);
    }
    foreach ($cart as $goods) {
      $orderGoods['orderid'] = $orderId;
      $orderGoods['goodsid'] = $goods['id'];
      $orderGoods['title'] = $goods['title'];
      $orderGoods['price'] = $goods['price'];
      $orderGoods['attr'] = $goods['attr'];
      $orderGoods['pic'] = $goods['pic'];
      $orderGoods['num'] = $goods['selectcount'];
      M("OrderGoods")->add($orderGoods);
    }
 
    if ($payment == 'balance') {
      // 余额支付
      $this->balancePay($cartAmount, $user['wxopenid'], $orderId);
    } else if ($payment == 'weixin') {
      // 微信支付
      $this->weixinPay($cartAmount, $user['wxopenid'], $orderId, $order['ordersn']);
    }
  }
/**
   * 微信支付
   * @author 大脸猫脸大
   * @param $cart
   * @param $cartAmount
   * @param $address
   * @param $user
   */
  private function weixinPay($cartAmount, $openId, $orderId, $orderSn)
  {
 
    import("Vendor.Wxpay.lib.WxPay#Api", "", ".php");
    //订单号
    $money = $cartAmount * 100;
    $openid = $openId;
    $input = new \WxPayUnifiedOrder();
    $input->SetBody("迪克-商品");
    $input->SetOut_trade_no("$orderSn");
    $input->SetTotal_fee("$money");
    $input->SetNotify_url("https://" . $_SERVER['HTTP_HOST'] . "/api/buy/payNotify");
    $input->SetTrade_type("JSAPI");
    $input->SetOpenid($openid);
    $unifiedOrder = \WxPayApi::unifiedOrder($input);
 
    if ($unifiedOrder['result_code'] == 'SUCCESS' && $unifiedOrder['return_code'] == 'SUCCESS') {
      $time = time();
      $data['timeStamp'] = "$time";              //时间戳
      $data['nonceStr'] = $unifiedOrder['nonce_str'];     //随机字符串
      $data['signType'] = 'MD5';                //签名算法,暂支持 MD5
      $data['package'] = 'prepay_id=' . $unifiedOrder['prepay_id'];  //统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
      $data['paySign'] = $this->genPaySign($unifiedOrder, $time);// 之前以为是$unifiedOrder['sign']; 后来发现是调用的这种方法. 签名方案参见微信公众号支付帮助文档;
 
      $data['out_trade_no'] = $orderSn; 
      $data['orderid'] = $orderId; 
      $return['code'] = 1; 
      $return['data'] = $data; 
    } else { 
        Log::write(var_export($unifiedOrder, true), Log::ERR, '', C('LOG_PATH')."wx_pay_".date('y_m_d').'.log'); 
        $return['code'] = 0; 
        $return['msg'] = '微信支付失败';// $unifiedOrder['RETURN_MSG']; 
    } 
    $this->ajaxReturn($return); 
}
/* 生成支付签名*/
private function genPaySign($unifiedOrder, $time)
{
  $appId = \WxPayConfig::APPID;
  $nonceStr = $unifiedOrder['nonce_str'];
  $package = 'prepay_id=' . $unifiedOrder['prepay_id'];
  $signType = "MD5";
  $timeStamp = $time;
  $key = \WxPayConfig::KEY;

  $sign = md5(sprintf("appId=%s&nonceStr=%s&package=%s&signType=%s&timeStamp=%s&key=%s", $appId, $nonceStr, $package, $signType, $timeStamp, $key));
}
/**
   * 支付回调
   * @author:大脸猫脸大
   */
  public function payNotify()
  {
    import("Vendor.Wxpay.lib.WxPay#Data", "", ".php");
    $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
    $val = \WxPayResults::Init($xml);
 
    if ($val['result_code'] == 'SUCCESS' && $val['return_code'] == 'SUCCESS') {
 
      $orderSn = $val['out_trade_no'];
      $transactionId = $val['transaction_id'];
      $data = array('paytype' => 'weixin', 'status' => '1', 'paytime' => time(), 'paysn' => $transactionId);
 
      M("Order")->where("ordersn='$orderSn'")->setField($data);
      exit('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>');
    }else {
      Log::write(var_export($val, true), Log::ERR, '', C('LOG_PATH')."wx_pay_notify_".date('y_m_d').'.log');
      exit('<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>');
    }
}

payNotify 回调方法里一定要注意返回

<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>

如果不处理,你会发现payNotify  会被执行很多次参见:官方文档

总结一下:

注意二点,1.签名的问题 2. 回调方法的返回处理。

欢迎大家指正。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
通过对服务器端特性的配置加强php的安全
Oct 09 PHP
使用无限生命期Session的方法
Oct 09 PHP
php获取目录所有文件并将结果保存到数组(实例)
Oct 25 PHP
使用Curl进行抓取远程内容时url中文编码问题示例探讨
Oct 29 PHP
php遍历目录输出目录及其下的所有文件示例
Jan 27 PHP
PHP自动生成表单代码分享
Jun 19 PHP
PHP curl模拟登录带验证码的网站
Nov 30 PHP
反射调用private方法实践(php、java)
Dec 21 PHP
PHP函数引用返回的实例详解
Sep 11 PHP
php发送http请求的常用方法分析
Nov 08 PHP
详解PHP字符串替换str_replace()函数四种用法
Oct 13 PHP
php+mysql实现的无限分类方法类定义与使用示例
May 27 PHP
php实现微信企业付款到个人零钱功能
Oct 09 #PHP
php实现构建排除当前元素的乘积数组方法
Oct 06 #PHP
php微信公众号开发之微信企业付款给个人
Oct 04 #PHP
PHP获取当前系统时间的方法小结
Oct 03 #PHP
PHP格式化显示时间date()函数代码
Oct 03 #PHP
php实现微信企业转账功能
Oct 02 #PHP
PHP实现微信退款功能
Oct 02 #PHP
You might like
Yii入门教程之Yii安装及hello world
2014/11/25 PHP
javascript html 静态页面传参数
2009/04/10 Javascript
jquery刷新页面的实现代码(局部及全页面刷新)
2011/07/11 Javascript
jQuery代码优化 选择符篇
2011/11/01 Javascript
JavaScript和CSS通过expression实现Table居中显示
2013/06/28 Javascript
jquery放大镜效果超漂亮噢
2013/11/15 Javascript
javascript替换已有元素replaceChild()使用介绍
2014/04/03 Javascript
浅谈 jQuery 事件源码定位问题
2014/06/18 Javascript
浅谈JavaScript函数节流
2014/12/09 Javascript
jQuery中addClass()方法用法实例
2015/01/05 Javascript
简单介绍JavaScript中字符串创建的基本方法
2015/07/07 Javascript
JavaScript学习小结(7)之JS RegExp
2015/11/29 Javascript
解决angular的$http.post()提交数据时后台接收不到参数值问题的方法
2015/12/10 Javascript
js获取本机操作系统类型的两种方法
2015/12/19 Javascript
基于jQuery实现交互体验社会化分享代码附源码下载
2016/01/04 Javascript
js实现上一页下一页的效果【附代码】
2016/03/10 Javascript
laypage分页控件使用实例详解
2016/05/19 Javascript
jQuery多级联动下拉插件chained用法示例
2016/08/20 Javascript
js实现网页的两个input标签内的数值加减(示例代码)
2017/08/15 Javascript
解决在vue+webpack开发中出现两个或多个菜单公用一个组件问题
2017/11/28 Javascript
解决layer.open弹出框不能获取input框的值为空的问题
2019/09/10 Javascript
JavaScript实现轮播图效果代码实例
2019/09/28 Javascript
Python中多线程thread与threading的实现方法
2014/08/18 Python
python实现批量下载新浪博客的方法
2015/06/15 Python
django 单表操作实例详解
2019/07/30 Python
关于pytorch多GPU训练实例与性能对比分析
2019/08/19 Python
python集合删除多种方法详解
2020/02/10 Python
Django接收照片储存文件的实例代码
2020/03/07 Python
利用python绘制数据曲线图的实现
2020/04/09 Python
丝芙兰加拿大官方网站:SEPHORA加拿大
2018/11/20 全球购物
办公室前台岗位职责范本
2013/12/10 职场文书
丧事主持词大全
2014/04/02 职场文书
校庆活动策划方案
2014/06/05 职场文书
商务专员岗位职责范本
2014/06/29 职场文书
2014年班长个人工作总结
2014/11/14 职场文书
CSS实现九宫格布局(自适应)的示例代码
2022/02/12 HTML / CSS