微信小程序支付PHP实例

概述

支付主要分这几个步骤:

Created with Raphaël 2.1.0 小程序 小程序 公众平台 公众平台 服务器 服务器 1. 调用wx.login()获得获取ticket 2. 返回ticket 3. 带着ticket,向服务器请求用户OpenID 4. 调用jscode2session API,获取用户OpenID 5. 成功返回,结果中带有OpenID 6. 返回OpenID 7. 发起支付,获得prepayID 8. 调用unifiedorder API下单,得到prepayID 9. 成功返回,结果中带有prepayID 10. 返回prepayID 11. 调用wx.requestPayment()完成实际支付

详细步骤

准备工作

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



<view class="container">
    <button type="primary" bindtap="setLoading">支付button>
view>

wx.login获取ticket

// index.js

var 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.js

var 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.js

var 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'],
];

// 按照要求计算sign

ksort($params);
$sequence = '';
foreach ($params as $key => $value) {
  $sequence .= "$key=$value&";
}

$sequence = $sequence . "key=商户密钥";
$params['sign'] = strtoupper(md5($sequence));

// 给微信发出的请求,整个参数是个XML

$xml = '' . PHP_EOL;
foreach ($params as $key => $value) {
  $xml .= "<$key>$value" . PHP_EOL;
}
$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('/<\!\[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.js

var 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)
  }

})  

你可能感兴趣的:(php,开发经验)