微信小程序支付PHP实例

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/supergao222/article/details/77844651

概述

支付主要分这几个步骤:

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.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 = '<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.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)
  }

})  
展开阅读全文

没有更多推荐了,返回首页