uniapp+thinkphp5实现微信支付(JSAPI支付)
前言
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返回预支付订单号的接口,目前微信支付所有场景均使用这一接口。下面介绍的是其中JSAPI的支付实现流程与uniapp唤起微信支付流程
流程实现(后端)(PHP)
- 创建Wechatpay.php文件,放到指定文件目录下(我是放到了extend目录)
<?php
class Wechatpay{
/**
* 模拟提交参数,支持https提交 可用于各类api请求
* @param string $url : 提交的地址
* @param array $data :POST数组
* @param string $method : POST/GET,默认GET方式
* @return mixed
*/
function curl_https($url, $xml='', $useCert=false){
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch,CURLOPT_URL, $url);
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if(stripos($url,"https://")!==FALSE){
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
}else{
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
}
if($useCert == true){
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT,"");
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY,"");
}
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
//echo $error;
}
}
/**
*
* 拼接签名字符串
* @param array $urlObj
*
* @return 返回已经拼接好的字符串
*/
function ToUrlParams($urlObj)
{
$buff = "";
foreach ($urlObj as $k => $v)
{
if($k != "sign"){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
//数组转XML
function arrayToXml($arr)
{
$xml = "<xml>";
foreach ($arr as $key=>$val)
{ if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
//将XML转为array
function xmlToArray($xml)
{
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$values = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $values;
}
/**
* 获取随机字符串
* @return mixed
*/
function getRandString($len=12,$str='ABCDEFGHIJKLMNOPQRSTUVWYXZabcdefghijklmnopqrstuvwyxz1234567890'){
$strlen=strlen($str)-1;
$string='';
for ($i=0; $i < $len; $i++) {
$r=rand(1,$strlen);
$string=$string.$str[$r];
}
return $string;
}
}
2.定义公共变量
private $config = array(
'appid' => "wxa******", /*微信小程序的appid*/
'appid_app' => "wx******", /*微信开放平台上的应用id*/
'mch_id' => "*******", /*微信申请成功之后邮件中的商户id*/
'api_key' => "*************", /*在微信商户平台上自己设定的api密钥 32位*/
'notify_url' => 'https://***', /*支付回调地址,确保可以访问*/
);
3.支付接口
public function JSPay($busid,$price,$code,$type,$attach){
$businessInfo=$this->BusinessModel->find($busid);
Loader::import('wechatpay.Wechatpay', EXTEND_PATH,".php");
$wechatpay = new \Wechatpay();
$url='https://api.mch.weixin.qq.com/pay/unifiedorder';
$parameters=array(
'appid'=>$this->config["appid"],//appID
'mch_id'=>$this->config['mch_id'],//商户号
'openid'=>$businessInfo['openid'],//用户openid
'nonce_str'=>$wechatpay->getRandString(30),//随机字符串
'body'=>'购买商品',//商品描述
'out_trade_no'=>$code,//商户订单号
'total_fee'=>$price*100,//总金额 单位 分
// 'total_fee'=>1,//总金额 单位 分
'spbill_create_ip'=>$this->get_client_ip(),//终端IP
'notify_url'=>$this->config["notify_url"],//通知地址
'trade_type'=>'JSAPI',//交易类型
'sign_type'=>"MD5",
'attach'=>$attach
);
//参数名ASCII码从小到大排序
ksort($parameters);
//统一下单签名
$String = $wechatpay->ToUrlParams($parameters);
//签名步骤二:在string后加入KEY
$String = $String."&key=".$this->config['api_key']; // key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
//签名步骤三:MD5加密 (一次签名)
$time=time();
$parameters['sign']=strtoupper(md5($String));
$xmlData=$wechatpay->arrayToXml($parameters);
$return=$wechatpay->xmlToArray($wechatpay->curl_https($url,$xmlData));
if($return["return_code"]=="SUCCESS" && $return["result_code"]=="SUCCESS"){
// 从预支付接口返回的参数中取得 prepay_id
$prepay_id = $return['prepay_id'];
// 构造二次签名的参数
$signParams = array(
'appId' => $this->config["appid"],
'timeStamp' => (string)$time, // 时间戳需与统一下单时的时间戳保持一致
'nonceStr' => $wechatpay->getRandString(30), // 随机字符串
'package' => 'prepay_id=' . $prepay_id, // 统一下单接口返回的 prepay_id
'signType' => 'MD5'
);
// 将参数按照参数名 ASCII 码从小到大排序
ksort($signParams);
// 拼接成字符串
$signString = $wechatpay->ToUrlParams($signParams);
// 在字符串末尾加上商户密钥
$signString = $signString . "&key=" . $this->config['api_key'];
// 对签名字符串进行 MD5 加密并转大写 (二次签名)
$sign = strtoupper(md5($signString));
// 将签名加入返回给小程序的参数中
$signParams['paySign'] = $sign;
// 返回二次签名后的参数给小程序端
$this->result($signParams,'1','二次签名成功!','json');
}else{
echo json_encode(array("status"=>false,"msg"=>$return));
}
}
/*
获取当前服务器的IP
*/
public function get_client_ip(){
if ($_SERVER['REMOTE_ADDR']) {
$cip = $_SERVER['REMOTE_ADDR'];
} elseif (getenv("REMOTE_ADDR")) {
$cip = getenv("REMOTE_ADDR");
} elseif (getenv("HTTP_CLIENT_IP")) {
$cip = getenv("HTTP_CLIENT_IP");
} else {
$cip = "unknown";
}
return $cip;
}
- 支付回调
//微信支付回调接口
public function wxpaynotify(){
$xml = file_get_contents('php://input');
Loader::import('wechatpay.Wechatpay', EXTEND_PATH,".php");
$wechatpay = new \Wechatpay();
//将服务器返回的XML数据转化为数组
$data = $wechatpay->xmlToArray($xml);
// 保存微信服务器返回的签名sign
$data_sign = $data['sign'];
// sign不参与签名算法
unset($data['sign']);
$sign = $wechatpay->ToUrlParams($data);
$payData=$sign;
$sign=strtoupper(md5($sign."&key=".$this->config["api_key"]));
// 判断签名是否正确 判断支付状态
if ( ($sign===$data_sign) && ($data['result_code']=='SUCCESS') ) {
//支付成功
//其他操作
$result = true;
}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>';
}
echo $str;
}
流程实现(前端)(uniApp)
// 调用 wx.requestPayment 方法发起支付请求
wx.requestPayment({
appId: response.appid,
timeStamp: String(response.timeStamp),
nonceStr: response.nonceStr,
package: response.package,
signType: response.signType,
paySign: response.paySign,
success(res) {
// 支付成功的处理逻辑
console.log('支付成功', res);
uni.showToast({
title: '支付成功!',
icon: 'none',
duration: 1000
})
},
fail(res) {
// 支付失败的处理逻辑
console.log('支付失败', res);
uni.showToast({
title: '已取消支付',
icon: 'none',
duration: 2000
})
}
});
uniapp+thinkphp5实现微信支付(JSAPI支付)的更多相关文章
- Thinkphp5整合微信扫码支付开发实例
ThinkPHP框架是比较多人用的,曾经做过的一个Thinkphp5整合微信扫码支付开发实例,分享出来大家一起学习 打开首页生成订单,并显示支付二维码 public function index() ...
- ThinkPHP中实现微信支付(jsapi支付)流程
https://blog.csdn.net/sinat_35861727/article/details/72783988 之前写过一篇文章讲了 PHP实现微信支付(jsapi支付)流程 ,详见文章: ...
- Core3.1 微信v3 JSAPI支付 退款
1.前言 上一篇写了<Core3.1 微信v3 JSAPI支付>,这个属于v3的接口规则,现在研究了下退款的接口我写的时候它属于v2接口规则文档.但凡微信支付文档里面写清楚点我也不会在这里 ...
- 微信支付JSAPI支付
1.介绍 JSAPI支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付.应用场景有: ◆ 用户在微信公众账号内进入商家公众号,打开某 ...
- Core3.1 微信v3 JSAPI支付
1.前言 "小魏呀,这个微信支付还要多久?","快了快了老板,就等着最后一步了...","搞快点哈,就等着上线呢","...... ...
- 微信h5支付/jsapi支付/小程序支付
一. 介绍------------------------------------------------------------------ 微信支付官方开发文档: https://pay.wei ...
- thinkphp5.0 微信扫码支付模式二
仅供个人参考,方便大家. 一.1)https://pay.weixin.qq.com/index.php/core/home/login 复制此地址 打开微信商户平台. 2)下载安全操作证书(最好在 ...
- 微信支付-JSAPI支付V3-查询退款
接口地址 接口链接:https://api.mch.weixin.qq.com/pay/refundquery 是否需要证书 不需要. 请求参数 字段名 变量名 必填 类型 示例值 描述 公众账号ID ...
- 微信JSApi支付~集成到MVC环境后的最后一个坑(网上没有这种解决方案)
返回目录 大叔第一人 之前写了关于微信的坑<微信JSApi支付~坑和如何填坑>,今天将微信的jsapi支付封装到了MVC环境里,当然也出现了一些新的坑,如支付参数应该是Json对象而不是J ...
- asp.net微信jsapi支付
1.前台页面: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"><head ru ...
随机推荐
- SQL语法之:连表查询:union all
1.准备 两条sql查询出来的字段数必须一致 表1 字段: 数据: 表2 字段: 数据: 2.使用 1.两张表结构完全一样,查询字段顺序也一样 select ID,NAME,SEX,AGE,NAME2 ...
- Vue的Vue-ls使用
Vue插件,用于从Vue上下文中使用本地Storage,会话Storage和内存Storage 1. 安装 NPM npm install vue-ls --save YARN yarn add vu ...
- 一键自动化博客发布工具,用过的人都说好(infoq篇)
infoq的博客发布界面也是非常简洁的.首页就只有基本的标题,内容和封面图片,所以infoq的实现也相对比较简单. 一起来看看吧. 前提条件 前提条件当然是先下载 blog-auto-publishi ...
- pod(六):初始化容器Init Containers
目录 一.系统环境 二.前言 三.初始化容器Init Containers 3.1 何为初始化容器Init Containers 3.2 Init Containers与普通容器的不同之处 3.3 I ...
- 京东面试:SpringBoot同时可以处理多少请求?
Spring Boot 作为 Java 开发中必备的框架,它为开发者提供了高效且易用的开发工具,所以和它相关的面试题自然也很重要,咱们今天就来看这道经典的面试题:SpringBoot同时可以处理多少个 ...
- WPF在ListView中绑定Command命令的写法
假定:ViewModel中有一个数据源叫Persons,有一个命令叫DoCommand,通过System.Windows.Interactivity触发器绑定鼠标MouseUp事件,当UI端绑定了Da ...
- 如何在Windows上一键部署PaddleOCR的WebAPI服务
PaddleOCR旨在打造一套丰富.领先.且实用的OCR工具库,助力开发者训练出更好的模型,并应用落地. 官方开源项目地址:PaddlePaddle/PaddleOCR: Awesome multi ...
- 7.13晚考试总结(NOIP模拟14)[队长快跑·影魔·抛硬币]
樱花满地集于我心,楪舞纷飞祈愿相随 前言 终于没有令人头疼的数学了,总感觉这次考试的题目比较良心. 尤其是对于部分分的明细就非常到位(不像上一场的凭感觉给出部分分). 这就令我这种靠部分分暴力的菜鸡选 ...
- js 留言板(带删除功能)
本文所用的知识点:创建节点和添加节点 创建节点:document.createElement('li') 添加节点 node(父亲节点).appendChild(child) child:子节 ...
- js 实现密码框的查看和隐藏
大江东去,浪淘尽,千古风流人物.故垒西边,人道是,三国周郎赤壁.乱石穿空,惊涛拍岸,卷起千堆雪.江山如画,一时多少豪杰.遥想公瑾当年,小乔初嫁了,雄姿英发.羽扇纶巾,谈笑间,樯橹灰飞烟灭.故国神游,多 ...