获取openid参考微信授权登录
微信小程序MD5加密(支持中文):http://zhizun.lanzouy.com/inF7G00vonmb

pay.js

import util from '../../utils/util.js'
const md5 = require('../../utils/md5.js');
Page({
  /**
   * 页面的初始数据
   */
  data: {
    id: ''
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function () {

  },
  submit(){
    this.setData({id: 1})  
    this.unitedPayRequest('openid')
  },
   /*统一支付接口*/
   unitedPayRequest: function(openid){
    var that = this;
    //统一支付签名
    var appid = '';//appid必填
    var body = '';//商品名必填
    var mch_id = '';//商户号必填
    var key = ''; //商户key必填,在商户后台获得
    var out_trade_no = '';//自定义订单号必填
    var nonce_str = util.randomString();//随机字符串,不长于32位。  
    var total_fee = parseInt(0.01 * 100); //价格,这是一分钱
    var notify_url = 'http://localhost/notify_url.php';//通知地址必填
    var trade_type = "JSAPI";

    var unifiedPayment = 'appid=' + appid + '&body=' + body + '&mch_id=' + mch_id + '&nonce_str=' + nonce_str + '&notify_url=' + notify_url + '&openid=' + openid + '&out_trade_no=' + out_trade_no + '&total_fee=' + total_fee + '&trade_type=' + trade_type + '&key=' + key;
    console.log("unifiedPayment", unifiedPayment);
    var sign = md5.md5(unifiedPayment).toUpperCase();
    console.log("签名md5", sign);

    //封装统一支付xml参数
    var formData = "<xml>";
    formData += "<appid>" + appid + "</appid>";
    formData += "<body>" + body + "</body>";
    formData += "<mch_id>" + mch_id + "</mch_id>";
    formData += "<nonce_str>" + nonce_str + "</nonce_str>";
    formData += "<notify_url>" + notify_url + "</notify_url>";
    formData += "<openid>" + openid + "</openid>";
    formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>";
    formData += "<total_fee>" + total_fee + "</total_fee>";
    formData += "<trade_type>" + trade_type + "</trade_type>";
    formData += "<sign>" + sign + "</sign>";
    formData += "</xml>";
    console.log("formData", formData);
    //统一支付
    wx.request({
      url: 'http://api.mch.weixin.qq.com/pay/unifiedorder', 
      method: 'POST',
      head: 'application/x-www-form-urlencoded',
      data: formData, //设置请求的 header
      success: function (res) {
        console.log("返回商户", res.data);
        var result_code = util.getXMLNodeValue('result_code', res.data.toString("utf-8"));
        var resultCode = result_code.split('[')[2].split(']')[0];
        if (resultCode == 'FAIL') {
          var err_code_des = util.getXMLNodeValue('err_code_des', res.data.toString("utf-8"));
          var errDes = err_code_des.split('[')[2].split(']')[0];
          wx.showToast({
            title: errDes,
            icon: 'none'
          })
        } else {
          //发起支付
          var prepay_id = util.getXMLNodeValue('prepay_id', res.data.toString("utf-8"));
          var tmp = prepay_id.split('[');
          var tmp1 = tmp[2].split(']');
          //签名  
          var timeStamp = util.timeStamp();
          var nonceStr = util.randomString();
          var stringSignTemp = "appId=" + appid + "&nonceStr=" + nonceStr + "&package=prepay_id=" + tmp1[0] + "&signType=MD5&timeStamp=" + timeStamp + "&key=" + key;
          console.log("签名字符串", stringSignTemp);
          var sign = md5.md5(stringSignTemp).toUpperCase();
          console.log("签名", sign);
          var param = { "timeStamp": timeStamp, "package": 'prepay_id=' + tmp1[0], "paySign": sign, "signType": "MD5", "nonceStr": nonceStr }
          console.log("param小程序支付接口参数", param);
          that.processPay(param);
        }
      },
    })
  },
 
  /* 小程序支付 */
  processPay: function (param) {
      var thia = this;
    wx.requestPayment({
      timeStamp: param.timeStamp,
      nonceStr: param.nonceStr,
      package: param.package,
      signType: param.signType,
      paySign: param.paySign,
      success: function (res) {
        console.log("wx.requestPayment返回信息",res);
        wx.showToast({
            title: '支付成功',
            icon: 'success'
        })
        setTimeout(function(){
            wx.navigateTo({
            url: '../storyDetails/storyDetails?id='+thia.data.id,
            })
        },1500)
      },
      fail: function () {
        console.log("支付失败");
        wx.showToast({
            title: '支付失败',
            icon: 'error'
        })
        setTimeout(function(){
            wx.navigateTo({
            url: '../storyDetails/storyDetails?id='+thia.data.id,
            })
        },1500)
      },
      complete: function () {
        console.log("支付完成");
      }
    })
  }
})

util.js

/* 时间戳产生函数   */
function timeStamp() {
  return parseInt(new Date().getTime() / 1000) + ''
}

/* 随机数 */
function randomString() {
  var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789';    
  var maxPos = chars.length;
  var pwd = '';
  for (var i = 0; i < 32; i++) {
    pwd += chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return pwd;
}

/* 获取XML节点信息 */
function getXMLNodeValue(node_name, xml) {
  var tmp = xml.split("<" + node_name + ">")
  var _tmp = tmp[1].split("</" + node_name + ">")
  return _tmp[0]
}

module.exports = {
  randomString: randomString,
  timeStamp: timeStamp,
  getXMLNodeValue: getXMLNodeValue
}

notify_url.php

<?php
require 'common.php';
$param = xml_array(file_get_contents('php://input'));
// file_put_contents('1.txt',file_get_contents('php://input'));
if(!empty($param)){
    $appid = $param['appid'];
    $mch_id = $param['mch_id'];
    $nonce_str = $param['nonce_str'];
    $out_trade_no = $param['out_trade_no'];
    $key = $config['payKey'];

    $md5Arr = $param;
    unset($md5Arr['sign']);
    $md5Param = urldecode(http_build_query(arg_sort($md5Arr))).'&key='.$key;
    // echo $md5Param;
    $sign = md5($md5Param);
    if(strtolower($sign) != strtolower($param['sign'])){
        exit(array_xml(['return_code' => 'FAIL','return_msg' => '签名验证失败']));
    }
    
    $arrToXml = ['appid' => $appid,'mch_id' => $mch_id,'nonce_str' => $nonce_str,'out_trade_no' => $out_trade_no];
    $sign2 = urldecode(http_build_query(arg_sort($arrToXml))).'&key='.$key;
    $arrToXml['sign'] = md5($sign2);
    $xml = array_xml($arrToXml);
    $xml = get_curl("http://api.mch.weixin.qq.com/pay/orderquery",$xml);
    $arr = xml_array($xml);
    if($arr['return_code'] == 'SUCCESS' && $arr['result_code'] == 'SUCCESS' && $arr['trade_state'] == 'SUCCESS'){
        $row = getOne("select id,money,status from order_list where order_number='{$out_trade_no}'");
        if($row['status'] == 0 && $row['money'] == round(($arr['total_fee']/100),2)){
            update('order_list',['status' => 1,'pay_time' => time()],'id='.$row['id']);
        }
        echo array_xml(['return_code' => 'SUCCESS']);
    }else{
        echo array_xml(['return_code' => 'FAIL','return_msg' => '验证失败']);
    }
}else{
    echo array_xml(['return_code' => 'FAIL','return_msg' => '请发起xml请求']);
}
// 以下测试用
/* $xml = file_get_contents('1.txt');
 echo get_curl('http://域名/notify_url.php',$xml);*/

common.php

function get_curl($url, $post = '', $cookie = '', $referer = '', $proxy = '', $header = 0, $userAgent = '', $httpheader = [])
{
    $curl = curl_init();
    // 配置curl中的http协议->可配置的荐可以查PHP手册中的curl_  
    curl_setopt($curl, CURLOPT_URL, $url);
    if ($post) {
        // POST数据
        curl_setopt($curl, CURLOPT_POST, 1);
        // 把post的变量加上
        if (is_array($post)) {
            curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post));
        } else {
            curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
        }
        if ($arr = @json_decode($post, true)) {
            if (is_array($arr)) {
                $httpheader[] = 'Content-Type: application/json; charset=utf-8';
                $httpheader[] = 'Content-Length: ' . strlen($post);
            }
        }
    }
    if ($referer) {
        $httpheader[] = 'Referer: ' . $referer; //模拟来路
        $httpheader[] = 'Origin: ' . $referer;
    } else {
        $httpheader[] = 'Referer: ' . $url; //模拟来路
        $httpheader[] = 'Origin: ' . $url;
    }
    if ($cookie) {
        $httpheader[] = 'Cookie: ' . $cookie; //模拟cookie
    }
    if ($proxy) {
        $proxy = explode(':', $proxy);
        if (!empty($proxy[1])) {
            curl_setopt($curl, CURLOPT_PROXY, $proxy[0]); //代理服务器地址
            curl_setopt($curl, CURLOPT_PROXYPORT, $proxy[1]); //代理服务器端口
        }
        $httpheader[] = 'X-FORWARDED-FOR: ' . $proxy[0]; //模拟ip
        $httpheader[] = 'CLIENT-IP: ' . $proxy[0]; //模拟ip
    } else {
        $httpheader[] = 'X-FORWARDED-FOR: ' . $_SERVER['REMOTE_ADDR']; //模拟ip
        $httpheader[] = 'CLIENT-IP: ' . $_SERVER['REMOTE_ADDR']; //模拟ip
    }
    if ($header) {
        curl_setopt($curl, CURLOPT_HEADER, TRUE); //获取响应头信息
    }
    if ($userAgent) {
        $httpheader[] = 'User-Agent: ' . $userAgent; //模拟用户浏览器信息 
    } else {
        $httpheader[] = 'User-Agent: ' . (!empty($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36');
    }
    $httpheader[] = 'Host: ' . @parse_url($url)['host'];
    curl_setopt($curl, CURLOPT_HTTPHEADER, $httpheader); //模拟请求头
    curl_setopt($curl, CURLOPT_TIMEOUT, 10); //只需要设置一个秒的数量就可以  
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //返回字符串,而非直接输出到屏幕上
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); //跟踪爬取重定向页面
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($curl, CURLOPT_ENCODING, ''); //解决网页乱码问题
    // 执行这个请求  
    $ret = curl_exec($curl);
    if ($header) {
        $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
        $header = substr($ret, 0, $headerSize);
        $body = substr($ret, $headerSize);
        $ret = array();
        $ret['header'] = $header;
        $ret['body'] = $body;
    }
    curl_close($curl);
    return $ret;
}

// xml转数组
function xml_array($xml)
{
    //禁止引用外部xml实体 
    libxml_disable_entity_loader(true);
    $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
    $val = json_decode(json_encode($xmlstring), true);
    return $val;
}

// 数组转xml
function array_xml($arr)
{
    $xml = "<xml>";
    foreach ($arr as $key => $val) {
        if (is_array($val)) {
            $xml .= "<" . $key . ">" . array_xml($val) . "</" . $key . ">";
        } else {
            $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
        }
    }
    $xml .= "</xml>";
    return $xml;
}

// 对数组排序
function arg_sort($para) {
    ksort($para);
    reset($para);
    return $para;
}