PHP微信H5支付开发实例


Posted in PHP onJuly 25, 2018

最近由于业务所需,对接了微信H5支付,然而微信支付对这块并没有现成的demo可用,所以就必须自己老老实实对照开发文档去写咯!但这对于刚接触的童鞋来说,坑多多少少还是有的,所以寻思着把自己的经验分享出来,毕竟现成的用的还是多巴适的嘛!

好了,官方文档的那一套就不多说了,详情见官方文档。

在这里,我主要分成了三个文件:WxPay.Config.php(支付配置文件)、Weixin.class.php(支付类)以及PayMentController.class.php(支付文件)。

首先,WxPay.Config.php配置文件主要包含了商户appId、商户号、商家key、异步回调URL、支付场景信息,如下:

class WxPayConfig
{
  public static $appid = '微信支付的公众号appid';
  public static $mchid = '微信支付分配的商户号';
  public static $key = '微信商户自己设置的安全key';
  public static $notify_url = '商户侧接收微信支付异步通知的URL';
  public static $scene_info = '{"h5_info":{"type":"Wap","wap_url":" 发起微信H5支付H5的URL","wap_name":"支付"}}'; 
}

然后,封装Weixin.class.php支付类,主要调用统一下单Api,这里不多说了,直接上代码:

<?php
require_once "lib/WxPay.Config.php";
class Weixin
{
     /**
   * 微信H5下单付款
   *   @order 付款信息
     *   @bodys 付款内容
   * */
     function getCode($order,$bodys){
          $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//微信传参地址
          //1.获取调用统一下单接口所需必备参数
    $appid =WxPayConfig::$appid;//微信公众号appid
    $mch_id = WxPayConfig::$mchid;//微信支付商户号
    $key = WxPayConfig::$key;//自己设置的微信商家key
    $out_trade_no = $order['order_sn'];//平台内部订单号
    $nonce_str=MD5($out_trade_no);//随机字符串
    $body = $bodys;//付款内容
    $total_fee = $order['order_amount']*100;//付款金额,单位为分
    $spbill_create_ip = getIP(); //获得用户设备IP
    $attach = 'weixinh5';//附加数据(自定义,在支付通知中原样返回)
    $notify_url = WxPayConfig::$notify_url; //异步回调地址,需外网可以直接访问
    $trade_type = 'MWEB';//交易类型,微信H5支付时固定为MWEB
    $scene_info =WxPayConfig::$scene_info;//场景信息
          //2.将参数按照key=value的格式,并按照参数名ASCII字典序排序生成字符串
    $signA ="appid=$appid&attach=$attach&body=$body&mch_id=$mch_id&nonce_str=$nonce_str¬ify_url=$notify_url&out_trade_no=$out_trade_no&scene_info=$scene_info&spbill_create_ip=$spbill_create_ip&total_fee=$total_fee&trade_type=$trade_type";
    //3.拼接字符串
          $strSignTmp = $signA."&key=$key";
          //4.MD5加密后转换成大写
    $sign = strtoupper(MD5($strSignTmp));
          //5.拼接成所需XML格式
    $post_data = "<xml> 
            <appid>$appid</appid> 
            <attach>$attach</attach> 
            <body>$body</body> 
            <mch_id>$mch_id</mch_id> 
            <nonce_str>$nonce_str</nonce_str> 
            <notify_url>$notify_url</notify_url> 
            <out_trade_no>$out_trade_no</out_trade_no> 
            <spbill_create_ip>$spbill_create_ip</spbill_create_ip> 
            <total_fee>$total_fee</total_fee> 
            <trade_type>$trade_type</trade_type>
            <scene_info>$scene_info</scene_info>
            <sign>$sign</sign> 
          </xml>";
          //6.以POST方式向微信传参,并取得微信返回的支付参数
    $dataxml = httpRequest($url,'POST',$post_data);
    $objectxml = (array)simplexml_load_string($dataxml, 'SimpleXMLElement', LIBXML_NOCDATA); //将微信返回的XML转换成数组
    return $objectxml;
  }
}

最后,PayMentController.class.php支付文件,支付文件接收前端发起支付的请求并处理后,调用Weixin.class.php支付类并接受结果后返回给前端(此处分享已经去掉接口验证等系列代码逻辑):

public function getPay(){
     //1.引入支付类文件
     include_once "plugins/Payment/weixin/Weixin.class.php";
     $payment = new \Weixin();
     $order_id = I('order_id');
     //2.判断参数是否为空
     if (!empty($order_id)){
          //3.根据订单id查询订单是否存在
          $order = M('Order')->where(array('id'=>$order_id))->find();
          if ($order){//订单存在
              //4.判断该笔订单是否已经支付,如已支付则返回支付失败并给出相应提示
              if ($order['pay_status'] == '1'){
                   exit(json_encode(array('status'=>'205','msg'=>'该订单已支付,请勿重复提交!')));
              }
              $bodys = '订单:'.$order['order_sn'] . '支付';
              //5.调用支付类中封装的支付方法并对应传参
              $result = $payment->getCode($order,$bodys);
              //6.当return_code和result_code均为SUCCESS,代表下单成功,将支付参数返回
              if($result['return_code'] == 'SUCCESS'){
                   if($result['result_code'] == 'SUCCESS'){
                        exit(json_encode(array('status'=>'0','msg'=>'下单成功,请支付!','result'=>$result['mweb_url'])));
                   }elseif($result['result_code'] == 'FAIL'){
                        exit(json_encode(array('status'=>'-201','msg'=>$result['err_code_des'])));
                   }
              }else{
        exit(json_encode(array('status'=>'-1','msg'=>'未知错误,请稍后重试!')));
                  }
          }else{
              //报错:数据不存在
              exit(json_encode(array('status'=>'-200','msg'=>'订单不存在,请核实后再提交!')));
          }
     }else{
          //报错:缺少参数
          exit(json_encode(array('status'=>'-204','msg'=>'参数缺失,请核实!')));
     }
}

前端在接收到支付URL后执行即可唤醒微信支付。

附一:获取用户终端设备ip方法

function getIP(){      
    if (getenv("HTTP_CLIENT_IP"))
       $ip = getenv("HTTP_CLIENT_IP");
    else if(getenv("HTTP_X_FORWARDED_FOR"))
        $ip = getenv("HTTP_X_FORWARDED_FOR");
    else if(getenv("REMOTE_ADDR"))
       $ip = getenv("REMOTE_ADDR");
    else $ip = "Unknow";
    return $ip;
}

######附二:CURL请求方法

/**
   * CURL请求
   * @param $url 请求url地址
   * @param $method 请求方法 get post
   * @param null $postfields post数据数组
   * @param array $headers 请求header信息
   * @param bool|false $debug 调试开启 默认false
   * @return mixed
   */
  function httpRequest($url, $method, $postfields = null, $headers = array(), $debug = false) {
    $method = strtoupper($method);
    $ci = curl_init();
    /* Curl settings */
    curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
    curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间,如果设置为0,则无限等待 */
    curl_setopt($ci, CURLOPT_TIMEOUT, 7); /* 设置cURL允许执行的最长秒数 */
    curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
    switch ($method) {
      case "POST":
        curl_setopt($ci, CURLOPT_POST, true);
        if (!empty($postfields)) {
          $tmpdatastr = is_array($postfields) ? http_build_query($postfields) : $postfields;
          curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
        }
        break;
      default:
        curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
        break;
    }
    $ssl = preg_match('/^https:\/\//i',$url) ? TRUE : FALSE;
    curl_setopt($ci, CURLOPT_URL, $url);
    if($ssl){
      curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
      curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
    }
    curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
    curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ci, CURLINFO_HEADER_OUT, true);
    $response = curl_exec($ci);
    $requestinfo = curl_getinfo($ci);
    if ($debug) {
      echo "=====post data======\r\n";
      var_dump($postfields);
      echo "=====info===== \r\n";
      print_r($requestinfo);
      echo "=====response=====\r\n";
      print_r($response);
    }
    curl_close($ci);
    return $response;
}

好了,一点点菜鸟心得,有不当之处欢迎留言指证交流,一起成长!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
第八节 访问方式 [8]
Oct 09 PHP
解决163/sohu/sina不能够收到PHP MAIL函数发出邮件的问题
Mar 13 PHP
discuz程序的PHP加密函数原理分析
Aug 05 PHP
php排序算法(冒泡排序,快速排序)
Oct 09 PHP
Zend studio文件注释模板设置方法
Sep 29 PHP
php小技巧之过滤ascii控制字符
May 14 PHP
关于PHP开发的9条建议
Jul 27 PHP
Yii中srbac权限扩展模块工作原理与用法分析
Jul 14 PHP
PHP实现断点续传乱序合并文件的方法
Sep 06 PHP
php实现文章评论系统
Feb 18 PHP
Yii框架学习笔记之session与cookie简单操作示例
Apr 30 PHP
laravel-admin select框默认选中的方法
Oct 03 PHP
php app支付宝回调(异步通知)详解
Jul 25 #PHP
php支付宝APP支付功能
Jul 29 #PHP
PHP多个图片压缩成ZIP的方法
Aug 18 #PHP
PHP上传文件及图片到七牛的方法
Jul 25 #PHP
详解PHP版本兼容之openssl调用参数
Jul 25 #PHP
PHP实现的多维数组去重操作示例
Jul 21 #PHP
php实现生成PDF文件的方法示例【基于FPDF类库】
Jul 21 #PHP
You might like
PHP基本语法总结
2014/09/06 PHP
php生成年月日下载列表的方法
2015/04/24 PHP
非常全面的php日期时间运算汇总
2015/11/04 PHP
Yii框架的路由配置方法分析
2019/09/09 PHP
JS 统计时间
2021/03/09 Javascript
JS无限树状列表实现代码
2011/01/11 Javascript
ToolTips JQEURY插件之简洁小提示框效果
2011/11/19 Javascript
文字不间断滚动(上下左右)实例代码
2013/04/21 Javascript
javascript的数组和常用函数详解
2014/05/09 Javascript
Javascript学习笔记之 函数篇(一) : 函数声明和函数表达式
2014/06/24 Javascript
JavaScript Sort 的一个错误用法示例
2015/03/20 Javascript
js判断手机端(Android手机还是iPhone手机)
2015/07/22 Javascript
js实现表单Radio切换效果的方法
2015/08/17 Javascript
jQuery实现的给图片点赞+1动画效果(附在线演示及demo源码下载)
2015/12/31 Javascript
在JavaScript中模拟类(class)及类的继承关系
2016/05/20 Javascript
JS中如何实现Laravel的route函数详解
2017/02/12 Javascript
解决webpack打包速度慢的解决办法汇总
2017/07/06 Javascript
vue树形结构获取键值的方法示例
2018/06/21 Javascript
微信小程序下拉刷新PullDownRefresh的使用方法
2018/11/29 Javascript
原生js添加一个或多个类名的方法分析
2019/07/30 Javascript
ant design vue中表格指定格式渲染方式
2020/10/28 Javascript
Vue指令实现OutClick的示例
2020/11/16 Javascript
[48:31]完美世界DOTA2联赛PWL S3 DLG vs Phoenix 第二场 12.17
2020/12/19 DOTA
python解析命令行参数的三种方法详解
2019/11/29 Python
在Keras中实现保存和加载权重及模型结构
2020/06/15 Python
美国诺德斯特龙百货官网:Nordstrom
2016/08/23 全球购物
亚瑟士美国官网:ASICS美国
2017/02/01 全球购物
Ivory Isle Designs美国/加拿大:婚礼和活动文具公司
2018/08/21 全球购物
酒店总经理欢迎词
2014/01/15 职场文书
小学优秀班干部事迹材料
2014/05/25 职场文书
领导班子四风表现材料
2014/08/23 职场文书
医院财务人员岗位职责
2015/04/14 职场文书
2015年销售部工作总结范文
2015/04/27 职场文书
安娜卡列尼娜观后感
2015/06/11 职场文书
投诉书格式范本
2015/07/02 职场文书
使用Pytorch训练two-head网络的操作
2021/05/28 Python