微信开发 ━━ 微信商户v3微信小程序支付方式开发之php篇
最近开发了小程序版的微信支付,遇到的情况与之前
h5
略有不同。
其流程大致为:前端wx.login()
获得code
,后端通过code
获取openid
并利用openid
生成预支编号prepay_id
,前端wx.requestPayment()
利用prepay_id
执行支付。
因为之前已写过二期native
和h5
的开发,所以本篇直接按照流程来写一写小程序支付的开发。
参考前两篇:
微信开发 ━━ 微信商户v3微信支付H5方式开发之php篇
微信开发 ━━ 微信商户v3微信支付Navive方式开发之php篇
一、获取code(前端)
小程序支付所用openid
只能由后端利用前端提供的code
向微信索取。
//前端界面,一般登录时获取wx.login({provider: 'weixin',success: (res) => {const code = res.code;}});
二、获取openid(后端)
将code
传入服务端,服务端向微信索取openid
,这里用php
举例。
//1.准备好数据$appid = 'wxaaabbbcccddd';//微信小程序appid$secret = '123456789abcdefghijklmn';//微信小程序secret$code = $_POST['code'];//接收code参数,换取用户唯一标识//2.获取openid$openid = getUserOpenid($appid, $secret, $code); //返回openidfunction getUserOpenid($appid, $secret, $code){$url = "https://api.weixin.qq.com/sns/jscode2session?"."grant_type=authorization_code&appid=$appid&secret=$secret&js_code=$code";$res = httpRequest($url); //httpRequest()参考第三步中函数//取出openid$data = json_decode($res);$openid = $data['openid'];return $openid;}
三、获取预支编号 - 生成签名 - 返回支付参数(后端)
这一步主要目的就是把金额等信息加密后提交给微信,生成一个等待支付的id号(预支编号:prepay_id
)。
其中的加密签名标准需要严格符合要求。
//1.准备好所有数据$openid = 'ab1234567890abcdefghijklmn';//用户openid,前一步获取的$appid = 'wxaaabbbcccddd';//微信小程序appid$mchid= '123456789abcdefghijklmn';//商户id$xlid = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';//证书序列号$apiclient_key = 'apiclient_key.pem';//证书签名,官网下载,存放于服务器本地,注意路径$time = time(); //时间戳$orderid = 'orderid_1234567890abcdefghijklmn';//订单编号$noncestr = $orderid;//微信支付里是唯一id,可以将订单编号存于此处$ordertotal = 123.45*100;//支付宝以元为单位,微信以分为单位$url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi';//生成预支序号所提交路径$urlarr = parse_url($url); //路径拆解为:[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/jsapi]//2.格式化信息$data = array();$data['appid'] = $appid;$data['mchid'] = $mchid;$data['description'] = '我的商品大又壮';//商品描述$data['out_trade_no'] = $orderid;//订单编号$data['notify_url'] = "http://www.csdn.net/notify.html";//回调接口,可以为空$data['amount']['total'] = (integer)$ordertotal;//金额 单位 分$data['scene_info']['payer_client_ip'] = '0.0.0.0';//场景:ip$data['payer']['openid'] =$openid;//openid$jsonData = json_encode($data); //变为json格式//3.签名一:后端获取prepay_id时所需的参数,通过header提交//包含了微信指定地址、时间戳、唯一编号和具体内容$str = "POST"."\n".$urlarr['path']."\n".$time."\n".$noncestr."\n".$jsonData."\n";$signHead = getSign($str);//4.头部信息//包含了商户信息、证书序列号、唯一编号、时间戳、签名//注意:这里只能使用$mchid,不能使用$data['mchid'],否则php会提示格式错误$token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"',$mchid,$xlid,$noncestr,$time,$signHead);$header = array('Content-Type:application/json; charset=UTF-8','Accept:application/json','User-Agent:*/*','Authorization:WECHATPAY2-SHA256-RSA2048 '.$token); //4.下单//向微信接口地址提交json格式的$data和header的头部信息,得到预支编号$res = httpRequest($url,$jsonData,$header);//取出prepay_id$data = json_decode($res);$prepayID = $data['prepay_id'];//5、签名二:前端支付时所需的参数//包含了、时间戳、微信指定地址、唯一编号和预支序号,//注意:格式为prepay_id=aabbcc$prepay = 'prepay_id='.$prepayID;//小程序appId + 时间戳 + 随机字符串 + 订单详情扩展字符串$str = $appid."\n".$time."\n".$noncestr."\n".$prepay."\n";$signPay = getSign($str);//6.支付//生成返回值提供给前端return array('paySign' => $signPay; 'nonceStr' => $noncestr;'timeStamp' => $time; 'package' => $prepay; );//7.涉及方法/** * http请求 * @param string $url 请求接口的url,需要url编码 * @param string $data 请求时传递的数据,GET时为null * @param string $header 请求时传递的头部数据 * @return 返回请求接口返回的数据 */ function httpRequest($url='',$data='',$header=''){$curl = curl_init(); // 启动一个CURL会话curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在,如果出错则修改为0,默认为1curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Refererif(!empty($data)){curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包}curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回 if(!empty($header)){curl_setopt($curl, CURLOPT_HTTPHEADER, $header);//$header以array格式}$response = curl_exec($curl); // 执行操作if (curl_errno($curl)){echo 'Error:'.curl_error($curl);//捕抓异常}curl_close($curl); // 关闭CURL会话return $response; // 返回数据,json格式}/** * 生成签名 * @param string $content 需要结合的内容 * @return 返回请求接口返回的数据 */ function getSign($content){$binary_signature = "";$key = file_get_contents($apiclient_key);//证书$algo = "SHA256";//将上传内容与api证书结合生成签名openssl_sign($content, $binary_signature, $privateKey, $algo);return base64_encode($binary_signature);}
- 第一次签名将订单号含在其中;
- 第二次签名将预支编号含在其中;
四、支付(前端)
前端将回传的预支编号和签名等参数提交给微信,即可实现支付。
<button @click="click">点击支付</button>
用wx.requestPayment
打开支付界面
function click(){//pay的值为服务端回传的数据wx.requestPayment({ timeStamp: pay.timeStamp, nonceStr: pay.nonceStr, package: pay.package, paySign: pay.paySign, signType: 'RSA', success (res) {}, fail (res) {}})}
知识点:
-
微信官方:
微信官方文档:小程序开发指南
JSAPI下单
UnionID 机制说明
调用wx.requestPayment(OBJECT)发起微信支付
微信支付 WeChatPay OpenAPI SDK
微信公众平台支付接口调试工具
小程序登录、用户信息相关接口调整说明
wx.getUserProfile不能和wx.login一起使用?
JSAPI支付返回: JSAPI缺少参数total_fee
auth.code2Session 获取openid -
微信相关:
微信小程序 wx.getUserProfile 使用示例 (替代wx.getUserInfo)
{“errcode“:48001,“errmsg“:“api unauthorized}
微信公众号开发 获取openid时报错40163:code been used问题的解决
微信开发中 openID 与 unionID 的区别
那些年微信支付踩过的坑:调用支付JSAPI缺少参数:total_fee -
PHP:
php curl_setopt函数怎么用?curl_setopt用法详解
PHP根据code获取openid
php获取openid
PHP sprintf() 函数
curl设置CURLOPT_HTTPHEADER请求头 -
uniapp:
uniapp开发的小程序中调用微信支付
uni.login(OBJECT) uni.getUserProfile(OBJECT)