Thinkphp整合微信支付功能


Posted in PHP onDecember 14, 2016

先上效果图:我要告诉你我这一篇文章写的是微信支付之中的(普通商户而非服务商商户的统一下单JSPI)微信支付:

Thinkphp整合微信支付功能Thinkphp整合微信支付功能Thinkphp整合微信支付功能Thinkphp整合微信支付功能Thinkphp整合微信支付功能

其实自己整合SDK失败了,用了一个博客博主整合的代码,在这里写一下笔记:

前面准备:

1、微信公众号:

独特的appid、appscrect、接口权限之中设置可以获取用户ID信息权限的域名(每个用户对于不同公众都会有一个特有ID,通过这个ID获取用户微信账号基本信息、详情看微信开发者文档)、在微信支付按钮出设置微信支付授权目录(写到发起请求的控制器那一层)、设置开发者微信账号为测试白名单(用微信开发者工具的时候需要)

2、微信支付平台:

商户平台登陆账号、支付密钥(随时可以自行设置,只能有一个)、

3、整合进去thinkphp之中逻辑:

前端微信支付按钮设置点击调用支付发起控制器方法、

控制器运行,引用微信支付类、获取用户openid、获取订单数据、拼接出所有普通商户预支付jsp需要的数据,display出那个自定义的支付页面、

在支付页面点击支付、调用微信提供的jspi发起支付的scripet函数发起支付、

支付完成以后页面会重定向到(在自定义支付页面的script函数里设置的跳转目录{:U('controller/function)}),并且异步(静默)设置的异步处理订单逻辑(记录支付时间啦、标记为已经支付啦、标记是微信支付啦)之类的、

代码:

我的订单页面的微信支付按钮:

<a href="{:U('Wxpay/js_api_start',array('order_key_num'=>$v['order_key_num]))}"> 微信支付</a>

发起支付控制器Wxpay:

<?php
namespace Home\Controller;
use Think\Controller;
//微信支付类
class WxpayController extends Controller {
 //获取access_token过程中的跳转uri,通过跳转将code传入jsapi支付页面
 public function js_api_start(){
  if(!empty($_GET['order_key_num'])){
   // session(array('pay_now_id'=>$_GET['order_key_num'],'expire'=>3600));
   S('pay_now_id',$_GET['order_key_num'],3600);
  }
  vendor('Weixinpay.WxPayPubHelper');
  //使用jsapi接口
  $jsApi = new \JsApi_pub();
  //=========步骤1:网页授权获取用户openid============
  //通过code获得openid
   if($_GET['code'] == ''){
   //跳转
    $redirect_uri = 'https://当前域名+模块+控制器+方法';
    $url = 'https://open.weixin.qq.com/connect/oauth2/authorize
    ?appid=公众号特有IDredirect_uri='.$redirect_uri.'&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect';
    header("Location: $url");
    exit();
   }else{
   //获取openid
   $url = 'https://api.weixin.qq.com/sns/oauth2/access_token
   ?appid=公众号ID&secret=公众号scrept&code='.$_GET['code'].'&grant_type=authorization_code'; 
   $openid_arr = json_decode(file_get_contents($url),true);
  }
  $openid=$openid_arr['openid'];
  $pay_now_id = S('pay_now_id');
  if($pay_now_id){
   $id=$pay_now_id;
   $o = D('order_info');
   $order_info = $o->where('order_id = %d',$id)->find();
   if(empty($order_info['paycode'])){
    $order_info['paycode'] = 'weixin';
   }
   if($order_info['is_pay']){
    $this->error('当前订单已经支付');
   }
  }else{
   $this->error("不存在当前订单编号!");
  }
   $res = array(
   'order_sn' => $order_info['order_sn'],
   'order_amount' => $order_info['pay_money']
   );
  //=========步骤2:使用统一支付接口,获取prepay_id============
  //使用统一支付接口
  $unifiedOrder = new \UnifiedOrder_pub();
  //设置统一支付接口参数
  //设置必填参数
  //appid已填,商户无需重复填写
  //mch_id已填,商户无需重复填写
  //noncestr已填,商户无需重复填写
  //spbill_create_ip已填,商户无需重复填写
  //sign已填,商户无需重复填写
  $total_fee = $order_info['pay_money']*100;
  // $total_fee = $res['order_amount'];
  //$total_fee = 1;
  // var_dump($order_info['pay_money']);die;
  $body = "订单支付";
  $unifiedOrder->setParameter("openid", "$openid");//用户标识
  $unifiedOrder->setParameter("body", '商品采购');//商品描述
  //自定义订单号,此处仅作举例
  $unifiedOrder->setParameter("out_trade_no", $order_info['order_sn']);//商户订单号 
  $unifiedOrder->setParameter("total_fee", $total_fee);//总金额
  //$unifiedOrder->setParameter("attach", "order_sn={$res['order_sn']}");//附加数据 
  $unifiedOrder->setParameter("notify_url", \WxPayConf_pub::NOTIFY_URL);//通知地址 
  $unifiedOrder->setParameter("trade_type", "JSAPI");//交易类型
  //非必填参数,商户可根据实际情况选填
  //$unifiedOrder->setParameter("sub_mch_id","XXXX");//子商户号 
  //$unifiedOrder->setParameter("device_info","XXXX");//设备号 
  //$unifiedOrder->setParameter("attach","XXXX");//附加数据 
  //$unifiedOrder->setParameter("time_start","XXXX");//交易起始时间
  //$unifiedOrder->setParameter("time_expire","XXXX");//交易结束时间 
  //$unifiedOrder->setParameter("goods_tag","XXXX");//商品标记 
  //$unifiedOrder->setParameter("openid","XXXX");//用户标识
  //$unifiedOrder->setParameter("product_id","XXXX");//商品ID
  $prepay_id = $unifiedOrder->getPrepayId();
  // var_dump($prepay_id);die;
  //=========步骤3:使用jsapi调起支付============
  $jsApi->setPrepayId($prepay_id);
  $jsApiParameters = $jsApi->getParameters();
  $wxconf = json_decode($jsApiParameters, true);
  if ($wxconf['package'] == 'prepay_id=') {
   $this->error('当前订单存在异常!');
  }
  $this->assign('res', $res);
  $this->assign('jsApiParameters', $jsApiParameters);
  $this->display('jsapi');
 }
 //异步通知url,商户根据实际开发过程设定
 public function notify_url() {
  vendor('Weixinpay.WxPayPubHelper');
  //使用通用通知接口
  $notify = new \Notify_pub();
  //存储微信的回调
  $xml = $GLOBALS['HTTP_RAW_POST_DATA']; 
  $notify->saveData($xml);
  //验证签名,并回应微信。
  //对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,
  //微信会通过一定的策略(如30分钟共8次)定期重新发起通知,
  //尽可能提高通知的成功率,但微信不保证通知最终能成功。
  if($notify->checkSign() == FALSE){
   $notify->setReturnParameter("return_code", "FAIL");//返回状态码
   $notify->setReturnParameter("return_msg", "签名失败");//返回信息
  }else{
   $notify->setReturnParameter("return_code", "SUCCESS");//设置返回码
  }
  $returnXml = $notify->returnXml();
  //==商户根据实际情况设置相应的处理流程,此处仅作举例=======
  //以log文件形式记录回调信息
  //$log_name = "notify_url.log";//log文件路径
  //$this->log_result($log_name, "【接收到的notify通知】:\n".$xml."\n");
  $parameter = $notify->xmlToArray($xml);
  //$this->log_result($log_name, "【接收到的notify通知】:\n".$parameter."\n");
  if($notify->checkSign() == TRUE){
   if ($notify->data["return_code"] == "FAIL") {
    //此处应该更新一下订单状态,商户自行增删操作
    //$this->log_result($log_name, "【通信出错】:\n".$xml."\n");
    //更新订单数据【通信出错】设为无效订单
    echo 'error';
   }
   else if($notify->data["result_code"] == "FAIL"){
    //此处应该更新一下订单状态,商户自行增删操作
    //$this->log_result($log_name, "【业务出错】:\n".$xml."\n");
    //更新订单数据【通信出错】设为无效订单
    echo 'error';
   }
   else{
    //$this->log_result($log_name, "【支付成功】:\n".$xml."\n");
    //我这里用到一个process方法,成功返回数据后处理,返回地数据具体可以参考微信的文档
    if ($this->process($parameter)) {
     //处理成功后输出success,微信就不会再下发请求了
     echo 'success';
    }else {
     //没有处理成功,微信会间隔的发送请求
     echo 'error';
    }
   }
  }
 }
 //订单处理
 private function process($parameter) {
  //此处应该更新一下订单状态,商户自行增删操作
  /*
  * 返回的数据最少有以下几个
  * $parameter = array(
   'out_trade_no' => xxx,//商户订单号
   'total_fee' => XXXX,//支付金额
   'openid' => XXxxx,//付款的用户ID
  );
  */
  $data = array(
      'order_sn'=>$parameter['out_trade_no'],
      'des'=>('订单交易:'.$parameter['out_trade_no']),
      'money'=>$parameter['total_fee'],
     );
  orderhandlestarysdgdss($data);//这是一个common方法,他会将该订单状态设置为已支付之类的
  return true;
 }
}
?>

发起支付后拼接预支付数据参数(参数列表看微信普通商户开发者文档——微信支付——统一下单)display的页面:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" name="viewport" />
<meta name="format-detection" content="telephone=no"/> 
<title>下</title>
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
<meta name="keyword" content="">
<meta name="description" content="">
<script type="text/javascript">
var order_sn = "{$res['order_sn']}";
//调用微信JS api 支付
function jsApiCall(){
 WeixinJSBridge.invoke(
  'getBrandWCPayRequest',
  <?php echo $jsApiParameters; ?>,
  function(res){
   //如果支付成功
   if (res.err_msg == 'get_brand_wcpay_request:ok') {
    //支付成功后跳转的地址
    location.href = "{:U('Home/User/my_order')}";
   }else if (res.err_msg == 'get_brand_wcpay_request:cancel') {
    alert('请尽快完成支付哦!');
   }else if (res.err_msg == 'get_brand_wcpay_request:fail') {
    alert('支付失败');
   }else {
    alert('意外错误');
   }
   //WeixinJSBridge.log(res.err_msg);
   //alert(res.err_code+res.err_desc+res.err_msg);
   /*if (res.err_msg == 'get_brand_wcpay_request:ok') {
    alert('支付成功');
   }else {
    alert('取消支付');
   }*/
  }
 );
}
function callpay(){
 if (typeof WeixinJSBridge == "undefined"){
  if( document.addEventListener ){
   document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
  }else if (document.attachEvent){
   document.attachEvent('WeixinJSBridgeReady', jsApiCall); 
   document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
  }
 }else{
  jsApiCall();
 }
}
</script>
<style>
*{font-family:'微软雅黑','Microsoft YaHei';}
body #head{position:relative;z-index:99999999999999;padding:0 10px;}
body .zh-head{padding:0 0 0 0;height:auto;}
.zh-head-conter{position:relative;height:40px;}
.zh-logo{position:absolute;left:50%;top:0;margin:0 0 0 -60px;float:none;width:auto;}
.zh-logo a{display:block;}
.zh-logo img{width:120px;height:40px;display:block;}
.heads_fix .zh-logo{}
#head{position:fixed!important;left:0;top:0;right:0;z-index:99999;background:#fff;border-bottom:1px solid #ddd;}
.zh-logo{height:40px;}
.flowpay{margin-top:25%;}
.flowpay dt{text-align:center;}
.flowpay strong.price{font-size:40px;}
.wxLogo{text-align:center;}
.wxLogo img{}
.flowpay dd{margin:0;padding:20px 0 10px 0;}
.flowpay dd input{margin:0 auto;padding:0;width:90%;height:45px;line-height:45px;border:0;border-radius:4px;background:#0CBC0A;color:#fff;font-size:17px;display:block;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;}
</style>
</head>
<body>
<!--头部开始-->
<div class="flowpay">
 <dl>
  <dt>
   <p class="wxLogo"><img src="__PUBLIC__/home/images/1479953699138120.png" alt=""></p>
   本次订单需支付:¥<strong class="price">{$res['order_amount']}</strong> 元
  </dt>
  <dd>
   <input type="button" id="hhhhhh" onclick="callpay()" value="立即支付" />
  </dd>
 </dl>
</div>
<!--尾结束-->
</body>
</html>

然后就是类文件啦:

Thinkphp整合微信支付功能

那个cacert是证书存放目录;证书不一定需要的;

vendor文件夹在我的文件里面找找就可以。

以上所述是小编给大家介绍的Thinkphp整合微信支付功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

PHP 相关文章推荐
用PHP 4.2书写安全的脚本
Oct 09 PHP
一个PHP日历程序
Dec 06 PHP
一个PHP分页类的代码
May 18 PHP
PHP无刷新上传文件实现代码
Sep 19 PHP
PHP中使用asort进行中文排序失效的问题处理
Aug 18 PHP
php生成图片验证码-附五种验证码
Aug 19 PHP
学习PHP Cookie处理函数
Aug 09 PHP
PHP实现电商订单自动确认收货redis队列
May 17 PHP
PHP7 mongoDB扩展使用的方法分享
May 02 PHP
laravel 判断查询数据库返回值的例子
Oct 11 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
Feb 23 PHP
php设计模式之组合模式实例详解【星际争霸游戏案例】
Mar 27 PHP
php判断是否连接上网络的方法实例详解
Dec 14 #PHP
基于php实现的验证码小程序
Dec 13 #PHP
php 微信开发获取用户信息如何实现
Dec 13 #PHP
php断点续传之文件分割合并详解
Dec 13 #PHP
php json_encode与json_decode详解及实例
Dec 13 #PHP
php页面跳转session cookie丢失导致不能登录等问题的解决方法
Dec 12 #PHP
php一个文件搞定微信jssdk配置
Dec 12 #PHP
You might like
php 图片加水印与上传图片加水印php类
2010/05/12 PHP
一些php项目中比较通用的php自建函数的详解
2013/06/06 PHP
PHP使用CURL_MULTI实现多线程采集的例子
2014/07/29 PHP
php获取CSS文件中图片地址并下载到本地的方法
2014/12/02 PHP
jQuery 锚点跳转滚动条平滑滚动一句话代码
2010/04/30 Javascript
asp.net网站开发中用jquery实现滚动浏览器滚动条加载数据(类似于腾讯微博)
2012/03/14 Javascript
javascript 使用 NodeList需要注意的问题
2013/03/04 Javascript
裁剪字符串trim()自定义改进版
2013/04/10 Javascript
javascript中2个感叹号的用法实例详解
2014/09/04 Javascript
AngularJS国际化详解及示例代码
2016/08/18 Javascript
jstl中判断list中是否包含某个值的简单方法
2016/10/14 Javascript
JavaScript常见的五种数组去重的方式
2016/12/15 Javascript
快速掌握jQuery插件开发
2017/01/19 Javascript
ECMAScript6 新特性范例大全
2017/03/24 Javascript
基于vue.js 2.x的虚拟滚动条的示例代码
2018/01/23 Javascript
简单了解Javscript中兄弟ifream的方法调用
2019/06/17 Javascript
小程序实现左滑删除效果
2019/07/25 Javascript
vue中根据时间戳判断对应的时间(今天 昨天 前天)
2019/12/20 Javascript
JS Array.from()将伪数组转换成数组的方法示例
2020/03/23 Javascript
NestJs使用Mongoose对MongoDB操作的方法
2021/02/22 Javascript
[36:41]完美世界DOTA2联赛循环赛FTD vs Magma第一场 10月30日
2020/10/31 DOTA
从局部变量和全局变量开始全面解析Python中变量的作用域
2016/06/16 Python
python安装本地whl的实例步骤
2019/10/12 Python
基于pytorch 预训练的词向量用法详解
2020/01/06 Python
Luxplus荷兰:以会员价购买美容产品等,独家优惠
2019/08/30 全球购物
英国在线药房和在线医生:LloydsPharmacy
2019/10/21 全球购物
九年级物理教学反思
2014/01/29 职场文书
家长评语和期望
2014/02/10 职场文书
网络技术专业推荐信
2014/02/20 职场文书
2015年师德师风自我评价范文
2015/03/05 职场文书
开展警示教育活动总结
2015/05/09 职场文书
生死牛玉儒观后感
2015/06/11 职场文书
2016元旦主持人经典开场白台词
2015/12/03 职场文书
nginx location优先级的深入讲解
2021/03/31 Servers
变长双向rnn的正确使用姿势教学
2021/05/31 Python
git stash(储藏)的用法总结
2022/06/25 Servers