PHP的微信支付接口使用方法讲解


Posted in PHP onMarch 08, 2019

在开发之中经常会使用到支付的功能,现在常用的两种支付方式是支付宝和微信。相对而言,支付宝的文档较为健全,并且配置和调用方式方式比较简单,这里就不过多的描述。

首先去微信官网网站下去下载服务端的demo:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

这里虽然是官网提供的公众号支付的demo,虽然微信支付的预下单等都可以在前端进行实现,不过官方还是建议在服务端进行处理。下载后,将其中的demo引入你的项目就好,注意的是如果是公众号的支付用到的类文件WxPay.JsApiPay.php在文件中example目录下。

接下来我们就可以进行引用了并实现。以thinkphp框架下进行调用为例(以下案例包括移动端以及公众号支付以及公众号获取openid等功能)。以下代码为了能够更容易理解,将一些类中的方法提取了出来,写的有点乱,请见谅。

/* 微信APP下支付预下单 */
  public function wxAppOrder(){
    //TODO:首先获取订单详情,例如传递过来订单号或订单id,获取订单的详情信息,例如将取出的数据存放入$user_order_info数组,订单中包含的商品在$user_order_product_info之中。
    /* 向微信发起请求 */
    vendor('WxpayAPI.lib.WxPay','','.Api.php');
    vendor('WxpayAPI.lib.WxPay','','.Data.php');//生成数据
    //统一下单输入对象
    $order_info= new WxPayUnifiedOrder();
    $order_info->SetOut_trade_no($user_order_info['orderNo']);//商品订单号
    $body=$user_order_product_info['productName'];
    //   $body=iconv('UTF-8', 'ISO-8859-1', $user_order_product_info['productName']);
    $order_info->SetBody($body);//商品描述
    $order_info->SetTrade_type('CNY');//人民币
    $order_info->SetTotal_fee(intval($user_order_info['sumPrice']*100));//总金额,以分为单位
    $order_info->SetTrade_type('APP');//交易类型
    $order_info->SetAppid(C('wxAPPID'));
    $order_info->SetMch_id(C('wxMCHID'));
    $order_info->SetNotify_url('你的回调地址');
    $order_info->SetSign();
    //进行统一支付
    $wxpay=new WxPayApi();
    $order_result=$wxpay->unifiedOrder($order_info);//统一下单
    if ($order_result['return_code']=='FAIL') {
      $arr=array(
          'resultCode'=>'99',
          'resultDesc'=>$order_result['return_msg'],
          'resultObj'=>array(''=>''),
      );
      echo JSON($arr);
      exit();
    }
    if ($order_result['result_code']=='SUCCESS') {
    //预下单成功后,重新签名返回给移动端
      $wxpay_result=new WxPayResults();
      $timestamp=time();
      $wxpay_result->SetData('appid', $order_result['appid']);
      $wxpay_result->SetData('partnerid', $order_result['mch_id']);
      $wxpay_result->SetData('prepayid', $order_result['prepay_id']);
      $wxpay_result->SetData('timestamp', $timestamp);
      $wxpay_result->SetData('noncestr', $order_result['nonce_str']);
      $wxpay_result->SetData('package', 'Sign=WXPay');
      // $wxpay_result->SetData('key', C('wxKEY'));
      //上方注释的代码是再签名中必要的一步,只是这个包含在了微信demo的类中,如果像该项目中既有app支付,又有公众号支付,最好是注释类中代码,并自己写入
      $resign_result=$wxpay_result->SetSign();
      //处理返回数据
      $result=array(
          'appid'=>$order_result['appid'],//appid
          'partnerid'=>$order_result['mch_id'],//商户号
          'prepayid'=>$order_result['prepay_id'],//与支付id
          'package'=>'Sign=WXPay',
          'noncestr'=>$order_result['nonce_str'],
          'timestamp'=>$timestamp,
          'sign'=>$resign_result,
      );
      $arr=array(
          'resultCode'=>'00',
          'resultDesc'=>'成功',
          'resultObj'=>$result,
      );
      echo JSON($arr);
      exit();
    }else{
      $arr=array(
          'resultCode'=>'99',
          'resultDesc'=>'失败',
          'resultObj'=>$order_result,
      );
      echo JSON($arr);
      exit();
    }
  }
  /* 微信支付回调函数 */
  public function wxpayNotify(){
    vendor('WxpayAPI.lib.Logwx','','.Log.php');//在回调中最好是引入日志进行记录,在这里因为Log类与thinkphp中的log类重复,需要进行处理
    $handle=new CLogFileHandler('./Public/wxlog.txt');
    $log=Logwx::Init($handle);
    $xml = $GLOBALS['HTTP_RAW_POST_DATA'];//获取数据
    vendor('WxpayAPI.lib.WxPay','','.Api.php');
    vendor('WxpayAPI.lib.WxPay','','.Data.php');
    $wxpay=new WxPayApi();
    $notify=new WxPayNotifyReply();
    $result=WxPayResults::Init($xml);//获取数据并转换为数组
    if ($result['return_code']=='SUCCESS' && $result['result_code']=='SUCCESS') {//此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断
      //TODO:进行数据库操作的业务逻辑处理,假设其成功与否的数据为$res
      if ($res) {
        $log->INFO('订单:'.$result['out_trade_no'].'支付成功');
        $notify->SetReturn_code('SUCCESS');
        $notify->SetReturn_msg('OK');
        $notify->SetSign();
      }else{
        $log->ERROR('微信支付失败');
        $notify->SetReturn_code('FAIL');
        $notify->SetReturn_msg('客户服务器错误');
      }
    }else{
      $log->ERROR('微信回调返回错误');
      $notify->SetReturn_code('FAIL');
      $notify->SetReturn_msg('微信支付失败');
    }
    //返回微信端
    $wxpay->replyNotify($notify->ToXml());
  }
  /* 微信公众账号下单
   * 获取code等信息
  * 跳转至获取信息
  *  */
  public function wxPubOrder(){
    //此流程中
    $orderId=$_GET['orderId'];
    //注意:此处如果想要回调成功,需要在微信公众平台设置回调域名
//   print_r('Location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.C('wxAPPID').'&redirect_uri='.'http://你的域名/Pay/getOpenid/orderId/'.$orderId.'&response_type=code&scope=snsapi_base&state=123#wechat_redirect');
//   exit();
    header('Location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.'*******'.'&redirect_uri='.urlencode('http://*****/Pay/getOpenid/orderId/'.$orderId).'&response_type=code&scope=snsapi_base&state=123#wechat_redirect');
    exit();
  }
  /* 微信获取openid,跳转到微信同意下单接口 */
  public function getOpenid(){
    //code
    $code=$_GET['code'];
    $state=$_GET['state'];
    $orderId=$_GET['orderId'];
    $appid='******';
    $appsecret='******';
    //获取openid
    $get_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code';
    $ch = curl_init();
    curl_setopt($ch,CURLOPT_URL,$get_token_url);
    curl_setopt($ch,CURLOPT_HEADER,0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    $res = curl_exec($ch);
    curl_close($ch);
    $json_obj = json_decode($res,true);
    $openId=$json_obj['openid'];
//   跳转到预下单
    // echo $openId;exit();
    $url='http://******/html5/#/pay/'.$orderId.'openid='.$openId;
    header('Location:'.$url);
  }
  /* 微信公众账号统一下单 */
  public function wxOrder(){
    $orderId=$_GET['orderId'];
    $openId=$_GET['openId'];
    if (empty($orderId)||empty($openId)) {
      $arr=array(
          'resultCode'=>'66',
          'resultDesc'=>'缺少参数',
          'resultObj'=>array(),
      );
      echo JSON($arr);
      exit();
    }
    //TODO:获取订单和订单商品信息,分别存储在$user_order_info中和$user_order_good_info中
    if (empty($user_order_info)) {
      $arr=array(
          'resultCode'=>'99',
          'resultDesc'=>'不存在该订单',
          'resultObj'=>array(),
      );
      echo JSON($arr);
      exit();
    }
    /* 向微信发起请求 */
    vendor('WxpayAPI.lib.WxPay','','.Api.php');
    vendor('WxpayAPI.lib.WxPay','','.Data.php');//生成数据
    //   vendor('WxpayAPI.lib.WxPay','','.JsApiPay.php');
    //统一下单输入对象
    $order_info= new WxPayUnifiedOrder();
    $wxpay=new WxPayApi();
    $order_info->SetMch_id('***');//商户号
    $order_info->SetAppid('****');//微信号APPID//wx70a40dfa2711c4fe
    $order_info->SetOut_trade_no($user_order_info['orderNo']);//商品订单号
    $order_info->SetBody($user_order_good_info['productName']);//商品描述
    $order_info->SetTrade_type('CNY');//人民币
    $order_info->SetTotal_fee(intval($user_order_info['sumPrice']*100));//总金额,以分为单位
    $order_info->SetTrade_type('JSAPI');//交易类型
    $order_info->SetNonce_str($wxpay->getNonceStr(32));
    $order_info->SetSpbill_create_ip('1.1.1.1');
    //   $order_info->SetOpenid($user_info['openId']);
    $order_info->SetOpenid($openId);
    //TODO:
    $order_info->SetNotify_url('http://****/Pay/wxpayNotify');
    $order_info->SetSign();//设置签名
    //进行统一支付
    $order_result=$wxpay->unifiedOrder($order_info);//统一下单
    //同意下单后再加
    if ($order_result['return_code']=='FAIL') {
      $arr=array(
          'resultCode'=>'99',
          'resultDesc'=>$order_result['return_code'].':'.$order_result['return_msg'],
          'resultObj'=>array(),
      );
      echo JSON($arr);
      exit();
    }
    if ($order_result['result_code']=='SUCCESS') {
      $jsapi = new WxPayJsApiPay();
      $jsapi->SetAppid($order_result["appid"]);
      $timeStamp = time();
      $jsapi->SetTimeStamp("$timeStamp");
      $jsapi->SetNonceStr(WxPayApi::getNonceStr());
      $jsapi->SetPackage("prepay_id=" . $order_result['prepay_id']);
      $jsapi->SetSignType("MD5");
      $jsapi->SetPaySign($jsapi->MakeSign());
      $order_result = $jsapi->GetValues();
      //     print_r($order_result);exit();
      $arr=array(
          'resultCode'=>'00',
          'resultDesc'=>'成功',
          'resultObj'=>$order_result,
      );
      echo JSON($arr);
      exit();
    }else{
      $arr=array(
          'resultCode'=>'99',
          'resultDesc'=>'失败',
          'resultObj'=>$order_result,
      );
      echo JSON($arr);
      exit();
    }  
  }

这就是一个支付的流程,在这之中会遇到很多问题,在此给出一个大多数会遇到的问题的解决方法的大概思路:

  • 1、APP统一下单后数据返回给前端,前端调用报签名错误:首先验证自己的秘钥信息是否正确,要注意移动端和公众号的是不同的,而类拿着key又去重新签名,可以将微信官方提供的demo中的直接内部调用配置文件那里注释掉
  • 2、在公众号获取openid的时候,显示跨域:这个解决参考YII2框架中对于\yii::$app->response->header,中的remove方法,将报头去掉即可。
  • 3、对于微信支付的配置,包括公众号支付配置白名单、测试目录啥的就不过多说了,请自行搜索资料

过程中肯定还遇到很多问题,这里不一一写了,如果还有问题可以在评论中留言,大家一起讨论学习,共同进步。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。如果你想了解更多相关内容请查看下面相关链接

PHP 相关文章推荐
如何将一个表单同时提交到两个地方处理
Oct 09 PHP
常用的php ADODB使用方法集锦
Mar 25 PHP
详解php的魔术方法__get()和__set()使用介绍
Sep 19 PHP
PHP文件缓存类示例分享
Jan 30 PHP
php中preg_match的isU代表什么意思
Oct 01 PHP
是 WordPress 让 PHP 更流行了 而不是框架
Feb 03 PHP
实例讲解PHP设计模式编程中的简单工厂模式
Feb 29 PHP
Zend Framework自定义Helper类相关注意事项总结
Mar 14 PHP
Laravel重写用户登录简单示例
Oct 08 PHP
yii2中dropDownList实现二级和三级联动写法
Apr 26 PHP
thinkPHP框架实现生成条形码的方法示例
Jun 06 PHP
laravel实现于语言包的完美切换方法
Sep 29 PHP
PHP实现会员账号单唯一登录的方法分析
Mar 07 #PHP
PHP模糊查询技术实例分析【附源码下载】
Mar 07 #PHP
原生PHP实现导出csv格式Excel文件的方法示例【附源码下载】
Mar 07 #PHP
PHP生成二维码与识别二维码的方法详解【附源码下载】
Mar 07 #PHP
PHP使用PDO操作sqlite数据库应用案例
Mar 07 #PHP
php使用fullcalendar日历插件详解
Mar 06 #PHP
PHP封装XML和JSON格式数据接口操作示例
Mar 06 #PHP
You might like
PHP 图像尺寸调整代码
2010/05/26 PHP
php 操作调试的方法
2012/07/12 PHP
通过PHP current函数获取未知字符键名数组第一个元素的值
2013/06/24 PHP
理清PHP在Linxu下执行时的文件权限方法
2017/06/07 PHP
ECMAScript 基础知识
2007/06/29 Javascript
10款非常有用的 Ajax 插件分享
2012/03/14 Javascript
jQuery的ready方法详解
2014/11/27 Javascript
JavaScript设置body高度为浏览器高度的方法
2015/02/09 Javascript
JS实现双击屏幕滚动效果代码
2015/10/28 Javascript
15个值得开发人员关注的jQuery开发技巧和心得总结【经典收藏】
2016/05/25 Javascript
js实现可旋转的立方体模型
2016/10/16 Javascript
基于jQuery实现Tabs选项卡自定义插件
2016/11/21 Javascript
JavaScript实现定时页面跳转功能示例
2017/02/14 Javascript
详解vue-cli 快速搭建单页应用之遇到的问题及解决办法
2018/03/01 Javascript
vue中nextTick用法实例
2019/09/11 Javascript
微信小程序返回箭头跳转到指定页面实例解析
2019/10/08 Javascript
[02:44]完美大师赛主赛事淘汰赛第二日观众采访
2017/11/24 DOTA
django自定义Field实现一个字段存储以逗号分隔的字符串
2014/04/27 Python
python使用nntp读取新闻组内容的方法
2015/05/08 Python
Python面向对象编程基础解析(一)
2017/10/26 Python
Python爬虫实例扒取2345天气预报
2018/03/04 Python
对Python3 * 和 ** 运算符详解
2019/02/16 Python
Django中使用Whoosh进行全文检索的方法
2019/03/31 Python
python3 反射的四种基本方法解析
2019/08/26 Python
Python FFT合成波形的实例
2019/12/04 Python
python异常处理try except过程解析
2020/02/03 Python
pycharm如何使用anaconda中的各种包(操作步骤)
2020/07/31 Python
安装pyinstaller遇到的各种问题(小结)
2020/11/20 Python
颇特女士:NET-A-PORTER(直邮中国)
2020/07/11 全球购物
浙大网新C/C++面试解惑
2015/05/27 面试题
ktv收银员岗位职责
2013/12/16 职场文书
药学专业学生的自我评价分享
2014/02/06 职场文书
重阳节活动总结
2014/08/27 职场文书
小学生感恩老师演讲稿
2014/08/28 职场文书
2015年毕业生自荐信范文
2015/03/24 职场文书
基于Redis结合SpringBoot的秒杀案例详解
2021/10/05 Redis