PHP实现一个二维码同时支持支付宝和微信支付
实现思路
- 生成一个二维码,加入要处理的url连接
- 在用户扫完码后,在对应的脚本中,判断扫码终端,调用相应的支付
- 若能够扫码之后能唤起相应app,支付宝要用手机网站支付方式,微信要使用jsapi支付方式
效果展示

提示: 因为项目即将上线,所以上面的支付二维码连接被我替换了(注意在生成二维码时加入的连接,要带上http协议)


实现步骤
生成二维码
//我的url指向了checkTerrace方法
$url = self::ADMIN_URL . 'params=' . $params;
//ADMIN_URL是生成二维码的url,请替换成自己
处理用户扫码操作(checkTerrace方法)
public function checkTerrace()
{
$pay_type = $this->getPayType(); //该方法使用来判断用户扫码终端的
$params = $this->request->get('params'); //生成二维码url带的参数(看个人需求,我的项目需要额外参数)
$params = $this->desDecode($params); //这里是因为我对参数进行了desc加密,看个人需求
if ($pay_type === 'alipay') { //如果用户是通过支付宝扫码,进行支付宝相关操作
if ($params === false) {
echo "系统错误!,请稍后重试";
exit;
}
$res = $this->createOrder($pay_type, $params);
if (!$res) {
echo "系统错误,请稍后重试";
exit;
}
$this->aliPay($res);
} elseif ($pay_type === 'wechat') { //如果用户是通过微信扫码,进行微信相关操作
if ($params === false) {
echo "系统错误,请稍后重试";
exit;
}
$prepare = $this->wechat($pay_type, $params);
$this->assign('json', $prepare);
return $this->display('wpay.html');
} elseif ($pay_type === false) {
echo "请使用支付宝或微信进行扫码";
exit;
}
}
判断扫码终端
/**
* 判断扫码终端
*
* @return string|boolean
* @date 2021-02-04
*/
private function getPayType()
{
if (strstr($_SERVER['HTTP_USER_AGENT'], 'AlipayClient')) {
return "alipay";
} elseif (strstr($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')) {
return "wechat";
} else {
return false;
}
}
生成订单
/**
* 生成订单
*
* @param string $pay_type
* @param json $params
* @return void
* @date 2021-02-04
*/
//这个逻辑就不贴代码了
private function createOrder($pay_type, $params)
{
/*生成订单相关逻辑代码*/
}
支付宝支付
/**
* 唤起支付宝app
*
* @param array $api_params
* @return void
* @date 2021-02-04
*/
private function aliPay($api_params)
{
$config = [
'notify_url' => '异步回调地址',
'is_open_certificate' => true
];
$domain = urlencode($api_params['domain']);
$api = [
'out_trade_no' => $api_params['trade_no'],
'total_amount' => '0.01',
'subject' => '商品标题',
'passback_params' => $domain
];
$pay = new Pay($config);
$res = $pay->driver('alipay')->gateway('wap')->pay($api); //调用支付宝手机网站支付
echo $res;
}
微信支付
/**
* 唤起微信app
*
* @return void
* @date 2021-02-04
*/
public function wechat($pay_type, $params)
{
$opend_id = $this->getOpenId(); //处理微信jsapi支付之前,要先获取用户的openID
if (!$opend_id) {
echo "微信授权失败...";
exit;
}
$api_params = $this->createOrder($pay_type, $params); //用户openID获取成功后才进行订单生产操作
if (!$api_params) {
echo "系统错误,请稍后重试";
exit;
}
$config = ['notify_url' => '微信异步回调地址'];
$api = [
'body' => '我是标题',
'out_trade_no' => $api_params['trade_no'],
'total_fee' => 1,
'openid' => $opend_id,
'attach' => $api_params['domain']
];
$pay = new Pay($config);
$res = $pay->driver('wechat')->gateway('mp')->pay($api); //调用微信jsapi支付
return $res;
}
静默获取openID
/**
* 获取用户的openid
*
* @return void
* @date 2021-02-04
*/
public function getOpenId()
{
if (isset($_SESSION['open_id']) && $_SESSION['open_id']) {
return $_SESSION['open_id'];
}
if (!$this->request->get('code')) {
$redirect_uri = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; //这里授权后微信跳转的地址,要写在订单处理处,否则会造成因为程序跳转到微信授权页面,导致脚本逻辑终止
$redirect_uri = urlencode($redirect_uri);
$url = $this->codeUrl . 'redirect_uri=' . $redirect_uri . '&appid=' . $this->appId . '&scope=snsapi_base&response_type=code&state=STATE#wechat_redirect'; //使用用户静默授权模式(因为我不需要获取用户信息所有就没采用用户手段授权模式)
header("location:{$url}"); //跳转到微信授权页面
} else {
$openidurl = $this->openidUrl . 'appid=' . $this->appId . '&secret=' . $this->appSecret . '&code=' . $this->request->get('code') . '&grant_type=authorization_code';
$data = Http::get($openidurl);
$data = json_decode($data, true);
if ($data['openid']) {
$_SESSION['open_id'] = $data['openid']; //获取到的用户openID存储到session中
} else {
$_SESSION['open_id'] = false;
}
return $_SESSION['open_id'];
}
}
前端轮询判断监听订单支付状态
$(function() {
$("#code").qrcode({
//jQuery生成二维码
width: 165, //宽度
height: 167, //高度
text: $('input[name="url"]').val()
});
var startTime = Date.parse(new Date())/1000;
//设置定时器
var poll_request = setInterval( function() {
$.ajax({
url: '/company/StoreSetting/checkStatus',
data:{time:startTime},
dataType:'json',
type:'get',
success:function(res) {
if (res.code == 400) {
var result = clearTimer(poll_request, startTime);
if (result) {
var html = `<img src="/Static/images/paybg.png">`+
`<div class="notify" id="notify">`+
`<img src="/Static/images/pay_time_out.png" alt="">`+
`<span class="pay_tip">点击重新获取</span>`+
`</div>`;
$('.qrcode-img').empty();
$('.qrcode-img').append(html);
}
} else if(res.code == 500) {
var html = `<img src="/Static/images/paybg.png">`+
`<div class="notify">`+
`<img src="/Static/images/pay_error.png" alt="">`+
`<span class="pay_tip">已扫码<br>请在手机端操作</span>`+
`</div>`;
$('.qrcode-img').empty();
$('.qrcode-img').append(html);
clearTimer(poll_request, startTime);
} else if(res.code == 200) {
clearInterval(poll_request)
layer.msg("支付成功", {icon:6}, function() {
window.location.reload()
})
// layer.msg("支付成功", {icon:6}, function() {
// })
}
}
})
}, 2000);
})
function clearTimer(index, startTime) {
if (((Date.parse(new Date())/1000) - startTime) > 60) {
clearInterval(index)
return 'reload';
}
return false;
}
//刷新二维码
$('.qrcode-img').on("click", '#notify', function() {
$('.qrcode-img').empty()
$("#code").qrcode({
width: 165, //宽度
height: 167, //高度
text: $('input[name="url"]').val()
});
var startTime = Date.parse(new Date())/1000;
var poll_request = setInterval( function() {
$.ajax({
url: '/company/StoreSetting/checkStatus',
data:{time:startTime},
dataType:'json',
type:'get',
success:function(res) {
if (res.code == 400) {
var result = clearTimer(poll_request, startTime);
if (result) {
var html = `<img src="/Static/images/paybg.png">`+
`<div class="notify" id="notify">`+
`<img src="/Static/images/pay_time_out.png" alt="">`+
`<span class="pay_tip">点击重新获取</span>`+
`</div>`;
$('.qrcode-img').empty();
$('.qrcode-img').append(html);
}
} else if(res.code == 500) {
var html = `<img src="/Static/images/paybg.png">`+
`<div class="notify">`+
`<img src="/Static/images/pay_error.png" alt="">`+
`<span class="pay_tip">已扫码<br>请在手机端操作</span>`+
`</div>`;
$('.qrcode-img').empty();
$('.qrcode-img').append(html);
clearTimer(poll_request, startTime);
} else if(res.code == 200) {
clearInterval(poll_request)
layer.msg("支付成功", {icon:6}, function() {
window.location.reload()
})
// layer.msg("支付成功", {icon:6}, function() {
// })
}
}
})
}, 2000);
})
前端效果:
- 用户进入支付页面但是一直为扫码,超过一定时间

- 用户扫码后一直未进行支付,超过一定时间

只是给大家提供了一个思路,希望能够对需要的人有些帮助
PHP实现一个二维码同时支持支付宝和微信支付的更多相关文章
- 公司开发的APP,如何生成一个二维码,供客户下载使用
1.其实和简单,因为一般的用户使用扫一扫,大多数都是用微信自带的扫一扫工具 而,微信打开的二维码页面,会自动屏蔽apk文件,所以显然把apk的url生成一个二维码,让用户扫一扫就能直接下载,这样是行不 ...
- 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码
详解C#泛型(二) 一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...
- 二维码合成,将苹果和安卓(ios和android)合成一个二维码,让用户扫描一个二维码就可以分别下载苹果和安卓的应用
因为公司推广的原因,没有合适的将苹果和安卓(ios和android)合成一个二维码的工具. 因为这个不难,主要是根据浏览器的UA进行判断,所以就自己开发了一个网站 网站名称叫:好推二维码 https ...
- 用Arduino制作一个二维码显示器
先上图 场景是这样的, 这几天给CS系统做一个微信支付的功能, 但是生成的二维码是在前台的电脑上..不可能让用户跑到前台的电脑上去扫描...然后拿出了N年前买的Arduino 做了一个二维码显示器. ...
- 一个二维码如何自动识别是安卓(Android)还是苹果(IOS)
思考问题: 通常,我们开发一个APP,有Android版本.IOS版本. 但是只有一个二维码?怎么办呢? 怎么让IOS用户扫描二维码下载IOS版本,Android用户扫描二维码下载到Android版本 ...
- 用一个二维码做下载地址,自动区分是 ios 还是 android
用一个二维码做下载地址,自动区分是 ios 还是 android, 甚至区分 iphone 和 ipad. <html> <head> <meta http-equiv ...
- 用lua nginx module搭建一个二维码
用lua nginx module搭建一个二维码(qr code)生成器 作者 vinoca 發布於 2014年10月31日 如果有VPS,或者开源的路由器,安装一个nginx,添加lua-nginx ...
- 安卓app和苹果app共用一个二维码
应项目要求,现在安卓app和苹果app共用一个二维码,对外提供下载: <html> <head> <meta http-equiv="Content-Type& ...
- react页面内嵌微信二维码 和 自定义样式 以及 微信网页共用unionId问题
在react页面内嵌“微信二维码”,实现PC端通过微信扫码进行登录.首先去微信开放平台注册一个账号,创建一个网站应用,提交网站备案审核,获取appid和appsecret:其他开发流程根据微信文档来进 ...
随机推荐
- 踹树(Trie 字典树)
Trie 字典树 ~~ 比 KMP 简单多了,无脑子选手学不会KMP,不会结论题~~ 自己懒得造图了OI WIKI 真棒 字典树大概长这么个亚子 呕吼真棒 就是将读进去的字符串根据当前的字符是什么和所 ...
- BootstrapValidator验证规则、BootStrap表格:列参数
BootstrapValidator验证规则 需引用组件 <script src="~/Scripts/jquery-1.10.2.js"></script> ...
- 《我想进大厂》之Zookeeper夺命连环9问
谈谈你对Zookeeper的理解? Zookeeper是一个开源的分布式协调服务,由雅虎公司创建,由于最初雅虎公司的内部研究小组的项目大多以动物的名字命名,所以后来就以Zookeeper(动物管理员) ...
- Java——单例模式、多线程
单例模式 单例模式练习 单例模式的分类 懒汉式 懒汉式相关练习 饿汉式 饿汉式相关练习 线程安全 使用双重检测机制实现线程安全的懒汉式 使用静态内部类实现线程安全的单例模式 多线程 多线程的三种方式 ...
- 3.centos 7执行service iptables save报错问题
1.报错 [root@localhost ~]# service iptables save The service command supports only basic LSB actions ( ...
- Cisco的互联网络操作系统IOS和安全设备管理器SDM__CDP
1.CDP定时器和保持信息时间:通过show cdp 命令查看 show cdp neighbors命令提供下列信息:device ID(设备ID).local interface(本地接口).hol ...
- Java并发包源码学习系列:阻塞队列实现之LinkedTransferQueue源码解析
目录 LinkedTransferQueue概述 TransferQueue 类图结构及重要字段 Node节点 前置:xfer方法的定义 队列操作三大类 插入元素put.add.offer 获取元素t ...
- Flink-v1.12官方网站翻译-P006-Intro to the DataStream API
DataStream API介绍 本次培训的重点是广泛地介绍DataStream API,使你能够开始编写流媒体应用程序. 哪些数据可以流化? Flink的DataStream APIs for Ja ...
- Java排序算法(四)希尔排序1
希尔排序交换法:分组+冒泡排序组合 一.测试类SortTest import java.util.Arrays; public class SortTest { private static fina ...
- 2019牛客暑期多校训练营(第八场)B-Beauty Values(期望线性性)
>传送门< 题意:思路:期望的线性性(可加性),比赛的时候写的代码超级无敌长,不过值得欣慰的是一发AC了,官方的题解写的还不错~ 我们可以把每种数字对答案的贡献分开来计算,即枚举每个数字, ...