微信小程序支付PHP实例

来源:互联网 发布:好想告诉你 知乎 编辑:程序博客网 时间:2024/06/01 12:59

概述

支付主要分这几个步骤:

Created with Raphaël 2.1.0小程序小程序公众平台公众平台服务器服务器1. 调用wx.login()获得获取ticket2. 返回ticket3. 带着ticket,向服务器请求用户OpenID4. 调用jscode2session API,获取用户OpenID5. 成功返回,结果中带有OpenID6. 返回OpenID7. 发起支付,获得prepayID8. 调用unifiedorder API下单,得到prepayID9. 成功返回,结果中带有prepayID10. 返回prepayID11. 调用wx.requestPayment()完成实际支付

详细步骤

准备工作

毫无疑问,首先肯定得在页面上有个支付的按钮 :-),按钮绑定事件。

<!--index.wxml--><view class="container">    <button type="primary" bindtap="setLoading">支付</button></view>

wx.login获取ticket

// index.jsvar app = getApp()Page({  setLoading: function() {    var that = this    wx.login({      success: function(res) {        // 成功的话会返回:        // {errMsg: "login:ok", code: "获取用户OpenID的ticket"}        that.getOpenId(res.code)      }    })  }})

获得OpenID

小程序得到ticket后,不能自己获得用户OpenID(微信规定的),因此通过服务器代理

// index.jsvar app = getApp()Page({  setLoading: function() { ... }  getOpenId: function(jsCode) {    var that = this    wx.request({      url: 'https://myserver.com/login.php',      data: {        js_code: jsCode // wx.login()时得到的ticket      },      success: function (res) {        that.getPrePayId(res.data.openid)      }    })  },  getPrePayId: function() { // 后面讲到 }})

服务器端代码(PHP):

// login.php$params = [  'appid' => '小程序的appid',  'secret' => '小程序的secret',  'js_code' => $_GET['js_code'], // 小程序传来的ticket  'grant_type' => 'authorization_code',];$ch = curl_init();curl_setopt($ch, CURLOPT_URL, 'https://api.weixin.qq.com/sns/jscode2session');curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, $params);$output = curl_exec($ch);if (false === $output) {  echo 'CURL Error:' . curl_error($ch);}echo $output;

$output返回的是个JSON:

{     "session_key":"abcdefg",     "expires_in":7200, // 7200秒后失效,小程序要重新通过ticket获得一次OpenID     "openid":"abc123" // 用户的OpenID}

统一下单

得到OpenID后,再次请求服务器,让服务器代理调用统一下单接口:

// index.jsvar app = getApp()Page({  setLoading: function() { ... },  getOpenId: function() { ... },  getPrePayId: function(openId) {    var that = this    wx.request({      url: 'https://myserver.com/pay.php',      data: {        openid: openId      },      success: function(res) {        that.pay(res.data)      }    })  },  pay: function() { // 后面讲到 }})  

服务端代码:

$params = [  'appid' => '小程序的appid',  'mch_id' => '商户id',  // 随机串,32字符以内  'nonce_str' => (string) mt_rand(10000, 99999),   // 商品名  'body' => '鞋子',   // 订单号,自定义,32字符以内。多次支付时如果重复的话,微信会返回“重复下单”  'out_trade_no' => '20170823001' . time(),  // 订单费用,单位:分  'total_fee' => 1,  'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],  // 支付成功后的回调地址,服务端不一定真得有这个地址  'notify_url' => 'https://myserver.com/notify.php',  'trade_type' => 'JSAPI',  // 小程序传来的OpenID  'openid' => $_GET['openid'],];// 按照要求计算signksort($params);$sequence = '';foreach ($params as $key => $value) {  $sequence .= "$key=$value&";}$sequence = $sequence . "key=商户密钥";$params['sign'] = strtoupper(md5($sequence));// 给微信发出的请求,整个参数是个XML$xml = '<xml>' . PHP_EOL;foreach ($params as $key => $value) {  $xml .= "<$key>$value</$key>" . PHP_EOL;}$xml .= '</xml>';$ch = curl_init();curl_setopt($ch, CURLOPT_URL, 'https://api.mch.weixin.qq.com/pay/unifiedorder');curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_POST, 1);curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);$output = curl_exec($ch);if (false === $output) {  echo 'CURL Error:' . curl_error($ch);}// 下单成功的话,微信返回个XML,里面包含prepayID,提取出来if (0 === preg_match('/<prepay_id><\!\[CDATA\[(\w+)\]\]><\/prepay_id>/', $output, $match)) {  echo $output;  exit(0);}// 这里不是给小程序返回个prepayID,而是返回一个包含其他字段的JSON// 这个JSON小程序自己也可以生成,放在服务端生成是出于两个考虑:// // 1. 小程序的appid不用写在小程序的代码里,appid、secret信息全部由服务器管理,比较安全// 2. 计算paySign需要用到md5,小程序端使用的是JavaScript,没有内置的md5函数,放在服务端计算md5比较方便$prepayId = $match[1];$response= [  'appId' => '小程序appid',  // 随机串,32个字符以内  'nonceStr' => (string) mt_rand(10000, 99999),  // 微信规定  'package' => 'prepay_id=' . $prepayId,  'signType' => 'MD5',  // 时间戳,注意得是字符串形式的  'timeStamp' => (string) time(),];$sequence = '';foreach ($response as $key => $value) {  $sequence .= "$key=$value&";}$response['paySign'] = strtoupper(md5("{$sequence}key=商户密钥"));echo json_encode($response);

wx.requestPayment() 支付

最后,小程序发起实际的支付,界面上会弹出支付窗口

// index.jsvar app = getApp()Page({  setLoading: function() { ... },  getOpenId: function() { ... },  getPrePayId: function() { ... },  // data是服务端返回的JSON  // 加上success、fail回调后,正好符合wx.requestPayment()参数的格式  pay: function(data) {    data.success = function(res) {      // 用户支付成功后的代码    }    data.fail = function(res) {      // 用户支付失败后的代码    }    wx.requestPayment(data)  }})