实现思路

  • 生成一个二维码,加入要处理的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实现一个二维码同时支持支付宝和微信支付的更多相关文章

  1. 公司开发的APP,如何生成一个二维码,供客户下载使用

    1.其实和简单,因为一般的用户使用扫一扫,大多数都是用微信自带的扫一扫工具 而,微信打开的二维码页面,会自动屏蔽apk文件,所以显然把apk的url生成一个二维码,让用户扫一扫就能直接下载,这样是行不 ...

  2. 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码

    详解C#泛型(二)   一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...

  3. 二维码合成,将苹果和安卓(ios和android)合成一个二维码,让用户扫描一个二维码就可以分别下载苹果和安卓的应用

    因为公司推广的原因,没有合适的将苹果和安卓(ios和android)合成一个二维码的工具. 因为这个不难,主要是根据浏览器的UA进行判断,所以就自己开发了一个网站 网站名称叫:好推二维码  https ...

  4. 用Arduino制作一个二维码显示器

    先上图 场景是这样的, 这几天给CS系统做一个微信支付的功能,  但是生成的二维码是在前台的电脑上..不可能让用户跑到前台的电脑上去扫描...然后拿出了N年前买的Arduino 做了一个二维码显示器. ...

  5. 一个二维码如何自动识别是安卓(Android)还是苹果(IOS)

    思考问题: 通常,我们开发一个APP,有Android版本.IOS版本. 但是只有一个二维码?怎么办呢? 怎么让IOS用户扫描二维码下载IOS版本,Android用户扫描二维码下载到Android版本 ...

  6. 用一个二维码做下载地址,自动区分是 ios 还是 android

    用一个二维码做下载地址,自动区分是 ios 还是 android, 甚至区分 iphone  和 ipad. <html> <head> <meta http-equiv ...

  7. 用lua nginx module搭建一个二维码

    用lua nginx module搭建一个二维码(qr code)生成器 作者 vinoca 發布於 2014年10月31日 如果有VPS,或者开源的路由器,安装一个nginx,添加lua-nginx ...

  8. 安卓app和苹果app共用一个二维码

    应项目要求,现在安卓app和苹果app共用一个二维码,对外提供下载: <html> <head> <meta http-equiv="Content-Type& ...

  9. react页面内嵌微信二维码 和 自定义样式 以及 微信网页共用unionId问题

    在react页面内嵌“微信二维码”,实现PC端通过微信扫码进行登录.首先去微信开放平台注册一个账号,创建一个网站应用,提交网站备案审核,获取appid和appsecret:其他开发流程根据微信文档来进 ...

随机推荐

  1. LOJ104 普通平衡树

    题目描述 这是一道模板题. 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入  x 数: 删除  x 数(若有多个相同的数,因只删除一个): 查询  x 数的排名(若 ...

  2. Linux环境Hadoop安装配置

    Linux环境Hadoop安装配置 1. 准备工作 (1)linux配置IP(NAT模式) (2)linux关闭防火墙 (3)设置主机名 (4)设置映射 (5)设置免密登录 2. 安装jdk (1)上 ...

  3. redis学习教程四《管理、备份、客户端连接》

    redis学习教程四<管理.备份.客户端连接>  一:Redis服务器命令 Redis服务器命令 下表列出了与Redis服务器相关的一些基本命令. 序号 命令 说明 1 BGREWRITE ...

  4. 深复制VS浅复制(MemberwiseClone方法介绍)

    MemberwiseClone方法,属于命名空间System,存在于程序集 mscorlib.dll中.返回值是System.Object.其含义是:创建一个当前object对象的浅表副本. MSDN ...

  5. P1108 低价购买(DP)

    题目描述 "低价购买"这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:"低价购买:再低价购买".每次你购买一支股 ...

  6. python连接mysql数据库,并进行添加、查找数据

    1.删除MySQL数据表中的记录 DELETE FROM table_name WHERE condition; python操作mysql1数据库 import pymysql # 连接mysql数 ...

  7. Musical Theme POJ - 1743 后缀数组

    A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the ...

  8. boomworks 1999~2009

    大众软件 PC定时执行专家 4.0 (PCTaskTimer) - 功能强大.简单易用的定时执行软件.具有功能多.体积小.消耗资源少的特点. 超级网际搜索(SuperSearch) - 免费.快速.高 ...

  9. 线程池原理讲解——ThreadPoolExecutor

    [这是前几天的存货,留着没发表,今天又复习一遍,润化了部分内容,继续干] 说线程池前,先简单回顾一下线程的状态吧: 1.线程状态转换 线程的五种状态,及其转换关系: 2.线程创建方式 三种:两个接口一 ...

  10. hlt instruction with IF=0

    mov AH, 2DH ;写时间. mov DH, 0 ;此时为0秒. int 21H ;写入系统. 遇到了这个问题. 原因是以及在保护模式了.保护模式下中断机制发生了很大的变化,原来的中断向量表被I ...