罗田县升平网络工作室,一家专业从事网站建设的工作室

资讯论坛

 找回密码
 加入论坛

快捷登录

回帖中禁止出现的内容,违者将被直接永久禁止访问,删除ID处理 :1.违反法律法规 ,包括但不限于出现带有政治、色情、暴恐信息等内容;2.恶意攻击内容,包括但不限于:恶意攻击党和政府、辱骂跟帖者、攻击主题发布者、不服从论坛管理、挑衅管理者、挑战版规等;3.广告、推广内容,尤其出现带有病毒、恶意代码、广告链接等内容,包括但不限于:QQ号、文字QQ号、微信号、手机号、文字手机号、第三方网址、单位公司名称、网站名称等;4.回帖贴出该主题隐藏资源链接或其它主题隐藏资源链接的行为。
查看: 840|回复: 0

PHP完成微信小程序在线支付功能

[复制链接]
发表于 2020-5-3 10:34:48 | 显示全部楼层 |阅读模式
PHP完成微信小程序在线支付功能


微信支付现在用到的地方越来越多,从公众号支付,扫码支付一直到现在的小程序支付等等六种快捷支付方式,公司要求开发小程序商城,就只能我上手处理接口支付问题了,使用最常规的第三方模式,第三方帮特约商户申请商户号并为他进行支付开发,第三方本身不经手资金,支付成功后资金直接进入特约商户商户号。

废话不多说直接上代码。

小程序访问地址:payfee.php 如果使用 TP 框架处理后台的话,写成方法即可

  1. include 'WeixinPay.php';
  2. $appid=''; //小程序appid
  3. $openid= $_POST['id'];
  4. $mch_id=''; //微信支付商户支付号
  5. $key=''; //Api密钥
  6. $out_trade_no = $mch_id. time();
  7. $total_fee = $_POST['fee'];
  8. if (empty($total_fee)) { //押金
  9.     $body = "充值押金";
  10.     $total_fee = floatval(99*100);
  11. } else {
  12.      $body = "充值余额";
  13.      $total_fee = floatval($total_fee*100);
  14. }
  15. $weixinpay = new WeixinPay($appid,$openid,$mch_id,$key,$out_trade_no,$body,$total_fee);
  16. $return=$weixinpay->pay();

  17. echo json_encode($return);
复制代码

WeixinPay.php 微信小程序支付类 所有微信小程序需要的参数都已经写入


  1. /*
  2. * 小程序微信支付
  3. */
  4. class WeixinPay {

  5.     protected $appid;
  6.     protected $mch_id;
  7.     protected $key;
  8.     protected $openid;
  9.     protected $out_trade_no;
  10.     protected $body;
  11.     protected $total_fee;
  12.     function __construct($appid, $openid, $mch_id, $key,$out_trade_no,$body,$total_fee) {
  13.         $this->appid = $appid;
  14.         $this->openid = $openid;
  15.         $this->mch_id = $mch_id;
  16.         $this->key = $key;
  17.         $this->out_trade_no = $out_trade_no;
  18.         $this->body = $body;
  19.         $this->total_fee = $total_fee;
  20.     }
  21.     public function pay() {
  22.         //统一下单接口
  23.         $return = $this->weixinapp();
  24.         return $return;
  25.     }


  26.     //统一下单接口
  27.     private function unifiedorder() {
  28.         $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
  29.         $parameters = array(
  30.             'appid' => $this->appid, //小程序ID
  31.             'mch_id' => $this->mch_id, //商户号
  32.             'nonce_str' => $this->createNoncestr(), //随机字符串
  33. //            'body' => 'test', //商品描述
  34.             'body' => $this->body,
  35. //            'out_trade_no' => '2018013106125348', //商户订单号
  36.             'out_trade_no'=> $this->out_trade_no,
  37. //            'total_fee' => floatval(0.01 * 100), //总金额 单位 分
  38.             'total_fee' => $this->total_fee,
  39.            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], //终端IP
  40.             // 'spbill_create_ip' => '192.168.0.161', //终端IP
  41.             'notify_url' => 'https://www.weixin.qq.com/wxpay/notify.php', //通知地址  确保外网能正常访问
  42.             'openid' => $this->openid, //用户id
  43.             'trade_type' => 'JSAPI'//交易类型
  44.         );
  45.         //统一下单签名
  46.         $parameters['sign'] = $this->getSign($parameters);
  47.         $xmlData = $this->arrayToXml($parameters);
  48.         $return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60));
  49.         return $return;
  50.     }


  51.     private static function postXmlCurl($xml, $url, $second = 30)
  52.     {
  53.         $ch = curl_init();
  54.         //设置超时
  55.         curl_setopt($ch, CURLOPT_TIMEOUT, $second);
  56.         curl_setopt($ch, CURLOPT_URL, $url);
  57.         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  58.         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
  59.         //设置header
  60.         curl_setopt($ch, CURLOPT_HEADER, FALSE);
  61.         //要求结果为字符串且输出到屏幕上
  62.         curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
  63.         //post提交方式
  64.         curl_setopt($ch, CURLOPT_POST, TRUE);
  65.         curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
  66.         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
  67.         curl_setopt($ch, CURLOPT_TIMEOUT, 40);
  68.         set_time_limit(0);
  69.         //运行curl
  70.         $data = curl_exec($ch);
  71.         //返回结果
  72.         if ($data) {
  73.             curl_close($ch);
  74.             return $data;
  75.         } else {
  76.             $error = curl_errno($ch);
  77.             curl_close($ch);
  78.             throw new WxPayException("curl出错,错误码:$error");
  79.         }
  80.     }
  81.    
  82.    
  83.    
  84.     //数组转换成xml
  85.     private function arrayToXml($arr) {
  86.         $xml = "<xml>";
  87.         foreach ($arr as $key => $val) {
  88.             if (is_array($val)) {
  89.                 $xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
  90.             } else {
  91.                 $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
  92.             }
  93.         }
  94.         $xml .= "</xml>";
  95.         return $xml;
  96.     }


  97.     //xml转换成数组
  98.     private function xmlToArray($xml) {
  99.         //禁止引用外部xml实体
  100.         libxml_disable_entity_loader(true);
  101.         $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
  102.         $val = json_decode(json_encode($xmlstring), true);
  103.         return $val;
  104.     }


  105.     //微信小程序接口
  106.     private function weixinapp() {
  107.         //统一下单接口
  108.         $unifiedorder = $this->unifiedorder();
  109. //        print_r($unifiedorder);
  110.         $parameters = array(
  111.             'appId' => $this->appid, //小程序ID
  112.             'timeStamp' => '' . time() . '', //时间戳
  113.             'nonceStr' => $this->createNoncestr(), //随机串
  114.             'package' => 'prepay_id=' . $unifiedorder['prepay_id'], //数据包
  115.             'signType' => 'MD5'//签名方式
  116.         );
  117.         //签名
  118.         $parameters['paySign'] = $this->getSign($parameters);
  119.         return $parameters;
  120.     }


  121.     //作用:产生随机字符串,不长于32位
  122.     private function createNoncestr($length = 32) {
  123.         $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  124.         $str = "";
  125.         for ($i = 0; $i < $length; $i++) {
  126.                 $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  127.         }
  128.         return $str;
  129.      }

  130.     //作用:生成签名
  131.      private function getSign($Obj) {
  132.         foreach ($Obj as $k => $v) {
  133.             $Parameters[$k] = $v;
  134.         }
  135.         //签名步骤一:按字典序排序参数
  136.         ksort($Parameters);
  137.         $String = $this->formatBizQueryParaMap($Parameters, false);
  138.         //签名步骤二:在string后加入KEY
  139.         $String = $String . "&key=" . $this->key;
  140.         //签名步骤三:MD5加密
  141.         $String = md5($String);
  142.         //签名步骤四:所有字符转为大写
  143.         $result_ = strtoupper($String);
  144.         return $result_;
  145.     }


  146.     ///作用:格式化参数,签名过程需要使用
  147.     private function formatBizQueryParaMap($paraMap, $urlencode) {
  148.         $buff = "";
  149.         ksort($paraMap);
  150.         foreach ($paraMap as $k => $v) {
  151.             if ($urlencode) {
  152.                 $v = urlencode($v);
  153.             }
  154.             $buff .= $k . "=" . $v . "&";
  155.         }
  156.         $reqPar = '';
  157.         if (strlen($buff) > 0) {
  158.             $reqPar = substr($buff, 0, strlen($buff) - 1);
  159.         }
  160.         return $reqPar;
  161.     }


  162. }
  163. 小程序页面请求处理:

  164.     wx.request({
  165.       url: 'https://yourhost.com/wxpay/payfee.php',//改成你自己的链接
  166.       data:{
  167.         id: app.globalData.openid,//获取用户openid
  168.         fee:100 //商品价格
  169.       },
  170.       header: {
  171.         'Content-Type': 'application/x-www-form-urlencoded'
  172.       },
  173.       method: 'POST',
  174.       success: function (res) {
  175.         console.log(res.data);
  176.         console.log('调起支付');
  177.         wx.requestPayment({
  178.           'timeStamp': res.data.timeStamp,
  179.           'nonceStr': res.data.nonceStr,
  180.           'package': res.data.package,
  181.           'signType': 'MD5',
  182.           'paySign': res.data.paySign,
  183.           'success': function (res) {
  184.             console.log('success');
  185.             wx.showToast({
  186.               title: '支付成功',
  187.               icon: 'success',
  188.               duration: 3000
  189.             });
  190.           },
  191.           'fail': function (res) {
  192.             console.log(res);
  193.           },
  194.           'complete': function (res) {
  195.             console.log('complete');
  196.           }
  197.         });
  198.       },
  199.       fail: function (res) {
  200.         console.log(res.data)
  201.       }
  202.     });
复制代码

回调 URL:notify.php

  1. $postXml = $GLOBALS["HTTP_RAW_POST_DATA"]; //接收微信参数
  2. // 接受不到参数可以使用file_get_contents("php://input"); PHP高版本中$GLOBALS好像已经被废弃了
  3. if (empty($postXml)) {
  4.     return false;
  5. }

  6. //将xml格式转换成数组
  7. function xmlToArray($xml) {
  8.     //禁止引用外部xml实体
  9.     libxml_disable_entity_loader(true);
  10.     $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
  11.     $val = json_decode(json_encode($xmlstring), true);
  12.     return $val;
  13. }
  14. $attr = xmlToArray($postXml);
  15. $total_fee = $attr['total_fee'];
  16. $open_id = $attr['openid'];
  17. $out_trade_no = $attr['out_trade_no'];
  18. $time = $attr['time_end'];
复制代码

代码都是我已经测试好可以支付成功的,希望能帮助到有需要的人~

2018 年 2 月 3 日 15:08:52 补充:

  1. 在异步回调取值的时候,异步回调一直在调用,弄得我数据一直重复的存入数据库,这个问题官方文档也有说明

  2. 支付完成后,微信会把相关支付结果和用户信息发送给商户,商户需要接收处理,并返回应答。

  3. 对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为 15/15/30/180/1800/1800/1800/1800/3600,单位:秒)

  4. 注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。

  5. 推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
复制代码


So:在微信的异步通知后,也需要给微信服务器,返回一个信息,只不过微信的所有数据格式都是 xml 的,所以我们在返回一个数据给微信即可。

  1. echo exit('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>');
复制代码

相关文档:
【微信支付】普通商户接入文档
【微信支付】微信小程序支付开发者文档

打赏鼓励一下!
回复

使用道具 举报

回帖中禁止出现的内容,违者将被直接永久禁止访问,删除ID处理 :1.违反法律法规 ,包括但不限于出现带有政治、色情、暴恐信息等内容;2.恶意攻击内容,包括但不限于:恶意攻击党和政府、辱骂跟帖者、攻击主题发布者、不服从论坛管理、挑衅管理者、挑战版规等;3.广告、推广内容,尤其出现带有病毒、恶意代码、广告链接等内容,包括但不限于:QQ号、文字QQ号、微信号、手机号、文字手机号、第三方网址、单位公司名称、网站名称等;4.回帖贴出该主题隐藏资源链接或其它主题隐藏资源链接的行为。

浏览排行

(38463)2019-11-5 公共云钱包资金盘骗局揭秘: 网络传销+原始股骗局合体!

(22233)2019-12-20 12月17日 邓智天法院直播庭审疑问全解答!

(20722)2019-12-1 环保币GEC资金盘骗局最新消息: 即将崩盘!

(17244)2019-11-9 巨胸肥臀大长腿,嫩模糯美子真人COS不知火舞福利污图

(15868)2018-12-24 罗田县人民法院公布【第五批失信被执行人名单】 ...

(14972)2019-11-3 曝光!PTFX已经崩盘跑路,投资者血流成河!

(13018)2019-8-7 湖北电力网上缴费,支付宝绑定户号的初始密码是什么?

(12480)2018-10-17 罗田县人民政府“12345”市民服务热线服务指南

(11170)2019-12-11 公安定性了, 趣码是非法传销! 趣码怎么退回365元?

(11081)2019-12-15 满足你对女同事的幻想 风骚秘书阿朱销魂眼神勾魂摄魄

最新发表

[升平网络工作室]2025-8-23 [2025-08-23]罗田天气预报

[升平网络工作室]2025-8-23 西藏自治区成立60周年庆祝大会隆重举行 习近平出席大会

[升平网络工作室]2025-8-23 县委委员会召开查摆问题整改整治情况汇报会

[爱查小程序]2025-8-22 [爱查]在线听音乐操作说明

[升平网络工作室]2025-8-22 [2025-08-22]罗田天气预报

[升平网络工作室]2025-8-22 习近平率中央代表团抵达拉萨出席西藏自治区成立60周年庆祝活动

[升平网络工作室]2025-8-22 县关工委联合经济开发区开展“情系学子”助学活动 助力职工子女圆梦大学

[升平网络工作室]2025-8-21 2025年罗田县卫健系统赴高校公开招聘事业单位工作人员拟聘用人员公示公告

[升平网络工作室]2025-8-21 [2025-08-21]罗田天气预报

[升平网络工作室]2025-8-21 县安防委2025年度第三次全体(扩大)会召开

QQ|Archiver|手机版|小黑屋|资讯论坛BBS.SPW8.CN ( 鄂ICP备2021011341号-3 )|网站地图


手机扫一扫继续访问
[免责声明]
本站系本网编辑转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。
如涉及作品内容、版权和其它问题,请在30日内与本网联系,我们将在第一时间删除内容!
[声明]本站文章版权归原作者所有 内容为作者个人观点 本站只提供参考并不构成任何投资及应用建议。

进入社区 | 发表新帖 | 百度收录 |
技术提供:罗田县升平网络工作室
站长Email:admin@spw8.cn
投诉电话(刮开查看):15374567400

GMT+8, 2025-8-23 17:02 , Processed in 0.160021 second(s), 30 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表