最近做小程序涉及到微信支付,连微信支付都没有做过的我无从下手,在网上搜索到了几篇帖子也没看明白,没办法只好照着某一篇(来源:微信小程序中实现微信支付 和 小程序支付,详细过程)硬着头皮先写了,最后经过几次调试终获成功,所以我对支付做一个总结,分享出来方便他人。

一,准备小程序id,小程序密钥,商户号,商户密钥,需要openid(微信登录后获得,调用https://api.weixin.qq.com/sns/jscode2session)

二,接口开发

接口有3个:预支付,支付,回调,php代码在后面

(一)预支付:(1)获取参数:openid,商品信息,金额;(2)设定回调接口地址,自己生成订单号,可将订单号与openid和商品信息一并写入mysql,等支付完成后在修改状态;(3)把所有字段汇集起来做签名一起提交给统一下单地址(https://api.mch.weixin.qq.com/pay/unifiedorder),成功的话会返回prepay_id,将prepay_id输出(给 支付接口)。

统一下单需要的参数:

<xml>
<appid>小程序id</appid>
<body>商品信息,比如商品名称</body>
<mch_id>商户号</mch_id>
<nonce_str>随机字符串,仅用于加密</nonce_str>
<notify_url>回调接口地址</notify_url>
<openid>openid,即用户id</openid>
<out_trade_no>订单号,自己生成</out_trade_no>
<spbill_create_ip>服务器ip</spbill_create_ip>
<total_fee>金额,单位分</total_fee>
<trade_type>交易类型,默认JSAPI</trade_type>
<sign>以上所有字段的签名</sign>
</xml>

统一下单返回数据:

<xml><return_code>状态码,SUCCESS|FAIL</return_code>
<return_msg>状态信息</return_msg>
<appid>小程序id</appid>
<mch_id>商户号</mch_id>
<nonce_str>微信生成的随机字符串</nonce_str>
<sign>签名</sign>
<result_code>同return_code?</result_code>
<prepay_id>预支付id,重要</prepay_id>
<trade_type>交易类型,默认JSAPI</trade_type>
</xml>

(二)支付:支付接口很简单,获取prepay_id后计算签名返回即可,小程序拿到签名后会发起真正的支付。此时会提醒用户输入密码,如下图:

(三)回调:当支付成功时,微信会调用此接口。可以实现自己业务逻辑,比如订单完成后修改状态。

接口输入xml数据:

<xml><appid>小程序id</appid>
<bank_type>银行类型,CFT</bank_type>
<cash_fee>金额</cash_fee>
<fee_type>金额类型,CNY</fee_type>
<is_subscribe><![CDATA[N]]></is_subscribe>
<mch_id>商户号</mch_id>
<nonce_str>随机字符串,自己生成发给微信的</nonce_str>
<openid>openid</openid>
<out_trade_no>订单号</out_trade_no>
<result_code>状态码,SUCCESS|FAIL</result_code>
<return_code>状态码,SUCCESS|FAIL</return_code>
<sign>签名</sign>
<time_end>支付完成时间</time_end>
<total_fee>金额</total_fee>
<trade_type><![CDATA[JSAPI]]></trade_type>
<transaction_id>微信交易号</transaction_id>
</xml>

验证签名正确后,处理自己业务流程。

如果返给微信的数据不是SUCCESS的话,微信会间隔一段时间后再次请求(15秒后,15秒后,30秒后,3分钟后,30分钟后,30分钟后,30分钟后,30分钟后,1小时后,。。。)

三,小程序端调用流程

小程序流程不懂,流程可参考文档 微信小程序中实现微信支付 在提交prepay_id时需要从字符串中截取出来。

四,php代码

(1)预支付prepay.php:

/*** 预支付请求接口(POST)* @param string $openid   openid* @param string $body    商品简单描述* @param string $total_fee 金额,单位分* @return  json的数据*/
require_once("config.php"); // config.php记录了小程序id,密钥,商户号及密钥
require_once("utils.php");  // 一些功能函数$openid = Request('openid');
$body = Request('body'); // 商品信息,比如title
$total_fee = RequestInt('total_fee', 1); // 金额flog("prepay openid:$openid total_fee:$total_fee ");$nonce_str =    nonce_str(); //随机字符串
$notify_url =   "https://你的域名/notify.php"; // 回调地址
$out_trade_no = trade_no();      //商户订单号,随机生成
$spbill_create_ip = '你的ip';  // 服务器ip
$trade_type = 'JSAPI';//交易类型 默认// 订单发起时,可将信息存入mysql
$sql = "insert into table";
...
flog("prepay:$sql");//这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
$post['appid'] = $appid;
$post['body'] = $body;
$post['mch_id'] = $mch_id;
$post['nonce_str'] = $nonce_str;//随机字符串
$post['notify_url'] = $notify_url;
$post['openid'] = $openid;
$post['out_trade_no'] = $out_trade_no;
$post['spbill_create_ip'] = $spbill_create_ip;//终端的ip
$post['total_fee'] = $total_fee;
$post['trade_type'] = $trade_type;
$sign = sign($post);//签名$post_xml = '<xml>
<appid>'.$appid.'</appid>
<body>'.$body.'</body>
<mch_id>'.$mch_id.'</mch_id>
<nonce_str>'.$nonce_str.'</nonce_str>
<notify_url>'.$notify_url.'</notify_url>
<openid>'.$openid.'</openid>
<out_trade_no>'.$out_trade_no.'</out_trade_no>
<spbill_create_ip>'.$spbill_create_ip.'</spbill_create_ip>
<total_fee>'.$total_fee.'</total_fee>
<trade_type>'.$trade_type.'</trade_type>
<sign>'.$sign.'</sign>
</xml> ';
/*
$arr = xml($post_xml);//全要大写
print_r($arr);
exit();
*///统一接口prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$xml = http_request($url,$post_xml);
flog("prepay: get xml: $xml");$arr = xml2arr($xml);
if ($arr['return_code'] == 'SUCCESS' && $arr['return_code'] == 'SUCCESS') {$time = time();$tmp=array();//临时数组用于签名$tmp['appId'] = $appid;$tmp['nonceStr'] = $nonce_str;$tmp['package'] = 'prepay_id='.$arr['prepay_id'];$tmp['signType'] = 'MD5';$tmp['timeStamp'] = "$time";$data['error'] = 0;$data['timeStamp'] = "$time";//时间戳$data['nonceStr'] = $nonce_str;//随机字符串$data['signType'] = 'MD5';//签名算法,暂支持 MD5$data['package'] = 'prepay_id='.$arr['prepay_id'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*$data['paySign'] = sign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;$data['out_trade_no'] = $out_trade_no;
} else {$data['error'] = 1;$data['msg'] = $arr['return_msg'];$data['wxcode'] = $arr['return_code'];
}flog("prepay ok:".json_encode($data));echo json_encode($data); //小程序需要的数据 返回前端

(2)支付pay.php

/*** 进行支付接口(POST)* @param string $prepay_id 预支付ID(调用prepay()方法之后的返回数据中获取)* @return  json的数据*/require_once("config.php");
require_once("utils.php");$prepay_id = Request('prepay_id');$data = array('appId'   => $appid,'nonceStr'  => nonce_str(),'package' => 'prepay_id='.$prepay_id,'signType'  => 'MD5','timeStamp' => time()
);$data['paySign'] = sign($data);flog("pay:".json_encode($data));
echo json_encode($data);

(3)回调notify.php

require_once("config.php");
require_once("utils.php");$xml = file_get_contents("php://input"); // 获取输入//$xml = $GLOBALS['HTTP_RAW_POST_DATA'];flog("notify: get xml:$xml");//将服务器返回的XML数据转化为数组$data = xml2arr($xml);// 保存微信服务器返回的签名sign$data_sign = $data['sign'];// sign不参与签名算法unset($data['sign']);$sign = sign($data);flog("notify sign:$sign");// 判断签名是否正确  判断支付状态if (($sign===$data_sign) && ($data['return_code']=='SUCCESS') && ($data['return_code']=='SUCCESS') ) {$result = $data;//获取服务器返回的数据$order_sn = $data['out_trade_no'];      //订单单号$openid = $data['openid'];          //付款人openID$total_fee = $data['total_fee'];      //付款金额$transaction_id = $data['transaction_id'];  //微信支付流水号//可根据订单号更新数据库$sql = "update table set where";...// TODO: 支付完成后,业务流程需处理} else {$result = false;}// 返回状态给微信服务器if ($result) {$str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';} else {$str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';}flog("notify result:$str");echo $str; // 返回给微信//return $result; // 这一步没必要

(4)utils.php

  // Author: ruc_skl@163.com (Kunlong She)// Created Time:2018-08-20 11:29:24
function RequestInt($str, $default = 0) {if (isset($_REQUEST[$str])) {return intval($_REQUEST[$str]);} else {return $default;}
}function Request($str) {if (isset($_REQUEST[$str])) {$rst = str_replace("'", "''", $_REQUEST[$str]);$rst = str_replace("\\", "\\\\", $rst);return $rst;} else {return "";}
}function Str($str) {if (empty($str)) {return "";} else {return $str;}
}function flog($str) {$fp = fopen("/tmp/a.log", "a+");$date = date("Y-m-d H:i:s");fprintf($fp, "$date $str\n");fclose($fp);
}// 随机字符串,仅用于签名
function nonce_str(){$result = '';$str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';for ($i=0;$i<32;$i++){$result .= $str[rand(0,48)];}return $result;
}// 订单号 随机字符串
// 随便怎么实现,尽量保证唯一,可以根据它来确定订单状态
function trade_no() {$result = date("YmdHis", time());$str = "0123456789";for ($i=0;$i<4;$i++) {$result .= $str[rand(0,9)];}return $result;
}//curl
function http_request($url, $data = null, $headers=array())
{$curl = curl_init();if( count($headers) >= 1 ){curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);}curl_setopt($curl, CURLOPT_URL, $url);curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);if (!empty($data)){curl_setopt($curl, CURLOPT_POST, 1);curl_setopt($curl, CURLOPT_POSTFIELDS, $data);}curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);$output = curl_exec($curl);curl_close($curl);return $output;
}//签名函数,未排序,传入数据需要对key按字母序排好,否则签名不正确
function sign($data){$stringA = '';foreach ($data as $key=>$value){if(!$value) continue;if($stringA) $stringA .= '&'.$key."=".$value;else $stringA = $key."=".$value;}$wx_key = '你的key';//申请支付后有给予一个商户账号和密码,登陆后自己设置key$stringSignTemp = $stringA.'&key='.$wx_key;//申请支付后有给予一个商户账号和密码,登陆后自己设置key return strtoupper(md5($stringSignTemp));
}//获取xml,注意key统一转成了小写
function xml2arr($xml){$p = xml_parser_create();xml_parse_into_struct($p, $xml, $vals, $index);xml_parser_free($p);$data = "";foreach ($index as $key=>$value) {if($key == 'xml' || $key == 'XML') continue;$tag = $vals[$value[0]]['tag'];$value = $vals[$value[0]]['value'];$data[strtolower($tag)] = $value;}return $data;
}

五,一些问题

(1)代码根据网上提供的改编而来,如果需要thinkphp上运行,要么csdn上找一份源码,要么依照这个改写

(2)回调函数是给微信调用的,里面可以不写return(thinkphp中有return),签名验证成功后可以写业务逻辑,可通过订单号处理,预支付写入订单号,回调修改订单号完成订单及后续处理。

(3)小程序id修改后,小程序与接口都需要修改,数据库中的openid需要重新登录,否则appid与openid不匹配。

(4)签名函数需要商户key

。。。

微信小程序实现支付接口相关推荐

  1. 微信小程序调用支付接口支付(tp5、小程序)

    微信小程序调用支付接口支付 今天记录一下学习的小程序调用微信支付接口 一.先理清一下调起微信支付的整个流程. 1.就是先调用微信的支付统一下单api获取到prepay_id 2.然后后端再将这个pre ...

  2. java微信小程序调用支付接口

    简介:微信小程序支付这里的坑还是有的,所以提醒各位在编写的一定要注意!!! 1.首先呢,你需要准备openid,appid,还有申请微信支付后要设置一个32位的密钥,需要先生成一个sign,得到pre ...

  3. 微信小程序调用支付接口返回订单号

    一.获取支付参数准备调用支付api wx.request({ url: 'http://localhost:8010/pay/createOrder', //上线的话必须是https,没有appId的 ...

  4. 微信小程序篇(微信小程序的支付)

    微信小程序的支付和微信公众号的支付是类似的,对比起来还比公众号支付简单了一些,我们只需要调用微信的统一下单接口获取prepay_id之后我们在调用微信的支付即可. 今天我们来封装一般node的支付接口 ...

  5. ios微信小程序虚拟支付解决办法

    ios微信小程序虚拟支付整理介绍 目前iOS端暂不支持虚拟支付,微信小程序虚拟支付仅涉及到ios端,安卓端不受影响. 小程序支付规范 https://developers.weixin.qq.com/ ...

  6. 微信小程序快递java_java调用微信小程序统一下单接口

    java调用微信小程序统一下单接口 今天项目中对接微信支付这一块,记录一下 这是对接微信支付的开发文档地址 微信支付流程 流程分析: 我们可以看到,前端人员只用给我们一个code,我们通过code去获 ...

  7. 微信小程序配置支付(附完整代码)

    微信小程序配置支付 1. 微信支付官网配置项 2. 代码配置(登录.获取openId.拉起支付等) 3. 云开发示例 1. 微信支付官网配置项 初次接入,商户号管理是没有数据的,需要申请接入. 如果是 ...

  8. 微信小程序 iOS支付

    微信小程序运营支付规范 微信官方针对有虚拟支付功能的小程序下发了整改通知.截至5月8号,平台将对账号屏蔽iOS系统的支付接口调用.我去查了<<微信小程序运营规则>>,如上图.发 ...

  9. 微信小程序服务器支付sdk,微信小程序之支付后如何调用SDK的异步通知

    微信小程序之支付后如何调用SDK的异步通知 发布时间:2021-07-05 10:47:33 来源:亿速云 阅读:57 作者:小新 这篇文章主要介绍微信小程序之支付后如何调用SDK的异步通知,文中介绍 ...

最新文章

  1. 捷报!又一名HIV感染者被治愈,干细胞移植再次立功
  2. Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)
  3. Javascript设计模式之——代理模式
  4. GitHub 的替代品(国内版)
  5. git无法上传大文件
  6. m()在php中的意思,计算器上的mc m+ m- mr是什么意思?
  7. lsb_release -a 查询Linux系统版本
  8. 受控文本生成任务简述
  9. 从信号转换角度研究血压(波形)预测的相关论文
  10. 数据库—并发调度的可串行性
  11. 博图编写温度程序_数字式温度控制器程序设计
  12. 使用C语言自定义函数计算三角形周长
  13. ESX4.1虚拟机识别U盘
  14. 高数_第5章常微分方程_二阶线性微分方程解的结构
  15. 软件测试面试题及答案 这个可以免费白嫖的题库不要错过了
  16. return--返回值
  17. 网络安全-网站后台的寻找+网页JS文件信息收集
  18. ucsd大学音乐计算机,音乐留学│综合名校UCSD音乐制作专业详解!
  19. 农行2021计算机专业面试题,【面经】2021 中国农业银行 笔试编程题
  20. window -Ubuntu 双系统切换

热门文章

  1. 洛谷 4828 Nagisa loves Tomoya 题解
  2. python爬取前程无忧_【Python】爬虫框架PySpider爬取前程无忧职位
  3. 其实你不懂网游的心(中)--网络游戏是洪水猛兽?
  4. 360推出无广告极速版,用户会买账吗?
  5. JavaScript原声的数组操作函数归纳
  6. Hadoop运行模式
  7. 基于 FPGA Vivado 的74系列IP封装(附源工程)
  8. 3ds Max 2016在界面上一点击鼠标右键就报状态集错误
  9. python实现运动模糊图像_python opencv生成模糊图像
  10. html下拉框属性js,Html下拉框Js对象属性方法总结