PHP小程序支付功能完整版【基于thinkPHP】


Posted in PHP onMarch 26, 2019

本文实例讲述了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));
    return $sign;
}
/**
* 支付回调
* @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 相关文章推荐
用PHP实现验证码功能
Oct 09 PHP
十天学会php之第五天
Oct 09 PHP
php str_pad 函数用法简介
Jul 11 PHP
PHP之生成GIF动画的实现方法
Jun 07 PHP
PHP连接MSSQL时nvarchar字段长度被截断为255的解决方法
Dec 25 PHP
ThinkPHP3.2.2的插件控制器功能
Mar 05 PHP
PHP中的switch语句的用法实例详解
Oct 21 PHP
解读PHP的Yii框架中请求与响应的处理流程
Mar 17 PHP
php查询操作实现投票功能
May 09 PHP
PHP多进程编程之僵尸进程问题的理解
Oct 15 PHP
PHP ajax+jQuery 实现批量删除功能实例代码小结
Dec 06 PHP
详解php伪造Referer请求反盗链资源
Jan 24 PHP
PHP实现微信退款的方法示例
Mar 26 #PHP
PHP设计模式之单例模式定义与用法分析
Mar 26 #PHP
php+mysql开发中的经验与常识小结
Mar 25 #PHP
PHP设计模式之抽象工厂模式实例分析
Mar 25 #PHP
PHP设计模式之简单工厂和工厂模式实例分析
Mar 25 #PHP
PHP实现无限极分类的两种方式示例【递归和引用方式】
Mar 25 #PHP
详解PHP神奇又有用的Trait
Mar 25 #PHP
You might like
php在项目中寻找代码的坏味道(综艺命名)
2012/07/19 PHP
Netbeans 8.2与PHP相关的新特性介绍
2016/10/08 PHP
yii插入数据库防并发的简单代码
2017/05/27 PHP
js的event详解。
2006/09/06 Javascript
用js解决数字不能换行问题
2010/08/10 Javascript
js解析与序列化json数据(三)json的解析探讨
2013/02/01 Javascript
jQuery实现感应鼠标动画效果自动伸长的输入框实例
2015/02/24 Javascript
JavaScript对Cookie进行读写操作实例
2015/07/25 Javascript
JavaScript文本框脚本编写的注意事项
2016/01/25 Javascript
Bootstrap框架结合jQuery仿百度换肤功能实例解析
2016/09/17 Javascript
JS实现获取来自百度,Google,soso,sogou关键词的方法
2016/12/21 Javascript
jQuery pagination分页示例详解
2018/10/23 jQuery
微信小程序登录对接Django后端实现JWT方式验证登录详解
2019/07/29 Javascript
微信内置浏览器图片查看器的代码实例
2019/10/08 Javascript
JavaScript快速调试的两个技巧
2020/11/04 Javascript
删除目录下相同文件的python代码(逐级优化)
2012/05/25 Python
Python中DJANGO简单测试实例
2015/05/11 Python
python显示生日是星期几的方法
2015/05/27 Python
Python制作钉钉加密/解密工具
2016/12/07 Python
python中datetime模块中strftime/strptime函数的使用
2018/07/03 Python
python框架中flask知识点总结
2018/08/17 Python
python 基于TCP协议的套接字编程详解
2019/06/29 Python
python opencv 图像边框(填充)添加及图像混合的实现方法(末尾实现类似幻灯片渐变的效果)
2020/03/09 Python
html5实现完美兼容各大浏览器的播放器
2014/12/26 HTML / CSS
排序都有哪几种方法?请列举。用JAVA实现一个快速排序
2014/02/16 面试题
致跳远运动员广播稿
2014/02/11 职场文书
教师自我鉴定范文
2014/03/20 职场文书
购房意向书范本
2014/04/01 职场文书
实习生工作证明范本
2014/09/14 职场文书
司法工作人员群众路线对照检查材料思想汇报
2014/09/30 职场文书
2014年乡镇卫生院工作总结
2014/11/24 职场文书
2019年暑期法院实习报告
2019/12/18 职场文书
Golang之sync.Pool使用详解
2021/05/06 Golang
Python 实现绘制子图及子图刻度的变换等问题
2021/05/31 Python
Html5获取用户当前位置的几种方式
2022/01/18 HTML / CSS
VUE之图片Base64编码使用ElementUI组件上传
2022/04/09 Vue.js