微信小程序实现支付接口
最近做小程序涉及到微信支付,连微信支付都没有做过的我无从下手,在网上搜索到了几篇帖子也没看明白,没办法只好照着某一篇(来源:微信小程序中实现微信支付 和 小程序支付,详细过程)硬着头皮先写了,最后经过几次调试终获成功,所以我对支付做一个总结,分享出来方便他人。
一,准备小程序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
。。。
微信小程序实现支付接口相关推荐
- 微信小程序调用支付接口支付(tp5、小程序)
微信小程序调用支付接口支付 今天记录一下学习的小程序调用微信支付接口 一.先理清一下调起微信支付的整个流程. 1.就是先调用微信的支付统一下单api获取到prepay_id 2.然后后端再将这个pre ...
- java微信小程序调用支付接口
简介:微信小程序支付这里的坑还是有的,所以提醒各位在编写的一定要注意!!! 1.首先呢,你需要准备openid,appid,还有申请微信支付后要设置一个32位的密钥,需要先生成一个sign,得到pre ...
- 微信小程序调用支付接口返回订单号
一.获取支付参数准备调用支付api wx.request({ url: 'http://localhost:8010/pay/createOrder', //上线的话必须是https,没有appId的 ...
- 微信小程序篇(微信小程序的支付)
微信小程序的支付和微信公众号的支付是类似的,对比起来还比公众号支付简单了一些,我们只需要调用微信的统一下单接口获取prepay_id之后我们在调用微信的支付即可. 今天我们来封装一般node的支付接口 ...
- ios微信小程序虚拟支付解决办法
ios微信小程序虚拟支付整理介绍 目前iOS端暂不支持虚拟支付,微信小程序虚拟支付仅涉及到ios端,安卓端不受影响. 小程序支付规范 https://developers.weixin.qq.com/ ...
- 微信小程序快递java_java调用微信小程序统一下单接口
java调用微信小程序统一下单接口 今天项目中对接微信支付这一块,记录一下 这是对接微信支付的开发文档地址 微信支付流程 流程分析: 我们可以看到,前端人员只用给我们一个code,我们通过code去获 ...
- 微信小程序配置支付(附完整代码)
微信小程序配置支付 1. 微信支付官网配置项 2. 代码配置(登录.获取openId.拉起支付等) 3. 云开发示例 1. 微信支付官网配置项 初次接入,商户号管理是没有数据的,需要申请接入. 如果是 ...
- 微信小程序 iOS支付
微信小程序运营支付规范 微信官方针对有虚拟支付功能的小程序下发了整改通知.截至5月8号,平台将对账号屏蔽iOS系统的支付接口调用.我去查了<<微信小程序运营规则>>,如上图.发 ...
- 微信小程序服务器支付sdk,微信小程序之支付后如何调用SDK的异步通知
微信小程序之支付后如何调用SDK的异步通知 发布时间:2021-07-05 10:47:33 来源:亿速云 阅读:57 作者:小新 这篇文章主要介绍微信小程序之支付后如何调用SDK的异步通知,文中介绍 ...
最新文章
- 捷报!又一名HIV感染者被治愈,干细胞移植再次立功
- Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)
- Javascript设计模式之——代理模式
- GitHub 的替代品(国内版)
- git无法上传大文件
- m()在php中的意思,计算器上的mc m+ m- mr是什么意思?
- lsb_release -a 查询Linux系统版本
- 受控文本生成任务简述
- 从信号转换角度研究血压(波形)预测的相关论文
- 数据库—并发调度的可串行性
- 博图编写温度程序_数字式温度控制器程序设计
- 使用C语言自定义函数计算三角形周长
- ESX4.1虚拟机识别U盘
- 高数_第5章常微分方程_二阶线性微分方程解的结构
- 软件测试面试题及答案 这个可以免费白嫖的题库不要错过了
- return--返回值
- 网络安全-网站后台的寻找+网页JS文件信息收集
- ucsd大学音乐计算机,音乐留学│综合名校UCSD音乐制作专业详解!
- 农行2021计算机专业面试题,【面经】2021 中国农业银行 笔试编程题
- window -Ubuntu 双系统切换