tp5 -- 微信公众号支付
近来期间比较忙, 忙完之后发现最近有挺多的东西没有整理,于是乎。就将以前用到的一些小东西整理了一下。
如果您需要前后端分离的JASPI或者APP支付 请查看:TP5 -- 微信支付整合(APP,JSAPI)
如果对您有帮助,则是我最大的幸运。
本篇主要是说了一下整合TP5的微信公众号支付。
不过由于最近TP6已经出了,小伙伴们要记得向最新的进发哦。
好了,废话不多说了。开始。
首先呢,需要引入我们封装好的类库:
同样在 extend/ 下
因为会将支付类库放在一起,于是就在extend 文件夹下创建了一个pay文件夹用来存储所有类文件。
以下内容为wxpay类的内容:
- namespace pay;
- class Wxpay
- {
- private $config =[
- "appid" => "********", // 公众号ID
- "mch_id" => "********", // 商户号
- "notify_url" => "********", // 回调地址
- "key" => "********", // 微信支付 商户秘钥KEY
- ];
- public function index($param,$openid)
- {
- $order=array(
- 'body' => $param['body'],// 商品描述
- 'total_fee' => intval($param['total']*100),// 订单金额 以(分)为单位
- // 'total_fee' => 1,
- 'out_trade_no' => $param['order_sn'],// 订单号
- 'trade_type' => 'JSAPI',// JSAPI公众号支付
- 'openid' => $openid// 获取到的openid
- );
- $userip = $param['userip'];
- // 统一下单 获取prepay_id
- $unified_order=$this->unifiedOrder($order,$userip);
- // 获取当前时间戳
- $time=time();
- // 组合jssdk需要用到的数据
- $data=array(
- 'appId' =>$this->config['appid'], //appid
- 'timeStamp' =>strval($time), //时间戳
- 'nonceStr' =>$unified_order['nonce_str'],// 随机字符串
- 'package' =>'prepay_id='.$unified_order['prepay_id'],// 预支付交易会话标识
- 'signType' =>'MD5' //加密方式
- );
- // 生成签名
- $data['paySign']=$this->makeSign($data);
- return $data;
- }
- /**
- * 统一下单
- * @param array $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单金额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型:JSAPI,NATIVE,APP)
- */
- public function unifiedOrder($order,$userip)
- {
- $config=array(
- 'appid' => $this->config['appid'], //appid
- 'mch_id' => $this->config['mch_id'], //商户号ID
- 'nonce_str' => $this->getNonceStr(),
- 'spbill_create_ip' => $userip, //你的IP
- 'notify_url' => $this->config['notify_url'],
- //'notify_url' =>$url
- );
- // 合并配置数据和订单数据
- $data=array_merge($order,$config);
- // 生成签名
- $sign=$this->makeSign($data);
- $data['sign']=$sign;
- //转换成xml
- $xml=$this->toXml($data);
- $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//接收xml数据的文件
- $header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
- $ch = curl_init ($url);
- curl_setopt($ch, CURLOPT_URL, $url);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 兼容本地没有指定curl.cainfo路径的错误
- curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
- curl_setopt($ch, CURLOPT_POST, 1);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
- $response = curl_exec($ch);
- if(curl_errno($ch)){
- // 显示报错信息;终止继续执行
- die(curl_error($ch));
- }
- curl_close($ch);
- //转换成数组
- $result=$this->toArray($response);
- //dump($result);
- // 显示错误信息
- if ($result['return_code']=='FAIL') {
- die($result['return_msg']);
- }
- $result['sign']=$sign;
- $result['nonce_str']=$this->getNonceStr();
- return $result;
- }
- /**
- * 生成签名
- * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
- */
- public function makeSign($data)
- {
- // 去空
- $data=array_filter($data);
- //签名步骤一:按字典序排序参数
- ksort($data);
- //将数组转成url形式
- $string_a=http_build_query($data);
- $string_a=urldecode($string_a);
- //签名步骤二:在string后加入KEY
- $string_sign_temp=$string_a."&key=".$this->config['key'];
- //签名步骤三:MD5加密
- $sign = md5($string_sign_temp);
- // 签名步骤四:所有字符转为大写
- $result=strtoupper($sign);
- return $result;
- }
- /**
- * 将xml转为array
- * @param string $xml xml字符串
- * @return array 转换得到的数组
- */
- public function toArray($xml){
- //禁止引用外部xml实体
- libxml_disable_entity_loader(true);
- $result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
- return $result;
- }
- /**
- *
- * 产生随机字符串,不长于32位
- * @param int $length
- * @return 产生的随机字符串
- */
- public function getNonceStr($length = 32)
- {
- $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
- $str ="";
- for ( $i = 0; $i < $length; $i++ ) {
- $str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
- }
- return $str;
- }
- /**
- * 输出xml字符
- * @throws WxPayException
- */
- public function toXml($data){
- if(!is_array($data) || count($data) <= 0){
- throw new WxPayException("数组数据异常!");
- }
- $xml = "<xml>";
- foreach ($data as $key=>$val){
- if (is_numeric($val)){
- $xml.="<".$key.">".$val."</".$key.">";
- }else{
- $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
- }
- }
- $xml.="</xml>";
- return $xml;
- }
- /**
- * 验证
- * @return array 返回数组格式的notify数据
- */
- public function notify(){
- // 获取xml
- $xml=file_get_contents('php://input', 'r');
- // 转成php数组
- $data=$this->toArray($xml);
- // 保存原sign
- $data_sign=$data['sign'];
- // sign不参与签名
- unset($data['sign']);
- $sign=$this->makeSign($data);
- // 判断签名是否正确 判断支付状态
- if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') {
- $result=$data;
- }else{
- $result=false;
- }
- // 返回状态给微信服务器
- if ($result) {
- $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
- }else{
- $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
- }
- // file_put_contents("./Public/aaa.text",$result);
- // echo $str;
- return $result;
- }
- public function https_request($url, $data = null)
- {
- $curl = curl_init();
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
- curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
- if (!empty($data)){
- curl_setopt($curl, CURLOPT_POST, 1);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
- }
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
- $output = curl_exec($curl);
- // var_dump($output);
- curl_close($curl);
- return $output;
- }
- }
然后就是调用方法了:
- namespace app\index\controller;
- use pay\Wxpay;
- class Index extends Base
- {
- /**
- *调用支付接口
- *
- */
- public function getorder()
- {
- $param = input('get.');
- $pays = model('pay')->where('id',$id)->find();
- $wxpay = [
- 'order_sn' => $pays['pay_sn'], //支付订单号
- 'total' => $pays['money'], //支付总额
- 'body' => $pays['body'], //支付说明
- 'userip' => $pays['userip'], //用户IP
- ];
- $openid = $this->_user['openid'];
- $pay = new Wxpay();
- $data = $pay->index($wxpay,$openid);
- $logUrl = "********"; //支付完成跳转地址
- $this->assign([
- 'data'=>json_encode($data),
- 'logUrl'=>$logUrl,
- ]);
- return $this->fetch();
- }
- }
其次是对应的调用空白页面:
- <!DOCTYPE html>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
- <title>订单提交成功</title>
- <style>
- .info{
- text-align: center;
- margin-top: 40px;
- }
- </style>
- </head>
- <body>
- <div class="info">支付进行中,请稍候...</div>
- <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
- <script type="text/javascript">
- //调用微信JS api 支付
- function onBridgeReady(){
- var data = {$data};
- WeixinJSBridge.invoke(
- 'getBrandWCPayRequest', data,
- function(res){
- if(res.err_msg == "get_brand_wcpay_request:ok" ) {
- // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
- window.location.href="{$logUrl}";
- }else{
- alert('支付失败');
- // alert(res.err_code+res.err_desc+res.err_msg); // 显示错误信息
- }
- }
- );
- }
- if (typeof WeixinJSBridge == "undefined"){
- if( document.addEventListener ){
- document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
- }else if (document.attachEvent){
- document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
- document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
- }
- }else{
- onBridgeReady();
- }
- </script>
- </body>
- </html>
最后就是回调了(拿到回调在此控制器汇中进行数据库操作):
- namespace app\index\controller;
- use Think\Controller;
- /**
- * 支付回调 -- 接收并处理调整数据库
- */
- class ClassName extends AnotherClass
- {
- private $config =[
- "key" => "*******", //微信支付 商户秘钥KEY
- ];
- /**
- * notify_url接收页面
- */
- public function wxpaynotify()
- {
- $result=$this->notify();
- if ($result)
- {//以下为处理数据库操作等 操作完成后输出success
- echo "SUCCESS";
- }
- }
- /**
- * 一下验证类 活获取 token 等可写入至 common 公告类中
- * 验证
- * @return array 返回数组格式的notify数据
- */
- public function notify(){
- // 获取xml
- $xml=file_get_contents('php://input', 'r');
- // 转成php数组
- $data=$this->toArray($xml);
- // 保存原sign
- $data_sign=$data['sign'];
- // sign不参与签名
- unset($data['sign']);
- $sign=$this->makeSign($data);
- // 判断签名是否正确 判断支付状态
- if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') {
- $result=$data;
- }else{
- $result=false;
- }
- // 返回状态给微信服务器
- if ($result) {
- $str='<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
- }else{
- $str='<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
- }
- // file_put_contents("./Public/aaa.text",$result);
- // echo $str;
- return $result;
- }
- /**
- * 将xml转为array
- * @param string $xml xml字符串
- * @return array 转换得到的数组
- */
- public function toArray($xml){
- //禁止引用外部xml实体
- libxml_disable_entity_loader(true);
- $result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
- return $result;
- }
- /**
- * 生成签名
- * @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
- */
- public function makeSign($data)
- {
- // 去空
- $data=array_filter($data);
- //签名步骤一:按字典序排序参数
- ksort($data);
- //将数组转成url形式
- $string_a=http_build_query($data);
- $string_a=urldecode($string_a);
- //签名步骤二:在string后加入KEY
- $string_sign_temp=$string_a."&key=".$this->config['key'];
- //签名步骤三:MD5加密
- $sign = md5($string_sign_temp);
- // 签名步骤四:所有字符转为大写
- $result=strtoupper($sign);
- return $result;
- }
- }
以上就是微信公众号支付的全部内容。
如有疑问,请评论或留言。
感谢您的查看。
2019年05月31日
tp5 -- 微信公众号支付的更多相关文章
- 微信公众号支付之坑:调用支付jsapi缺少参数 timeStamp等错误解决方法
这段时间一直比较忙,一忙起来真感觉自己就只是一台挣钱的机器了(说的好像能挣到多少钱似的,呵呵):这会儿难得有点儿空闲时间,想把前段时间开发微信公众号支付遇到问题及解决方法跟大家分享下,这些“暗坑”能不 ...
- 使用开源库MAGICODES.WECHAT.SDK进行微信公众号支付开发
概要 博客使用Word发博,发布后,排版会出现很多问题,敬请谅解.可加群获取原始文档. 本篇主要讲解微信支付的开发流程,相关业务基于MAGICODES.WECHAT.SDK实现.通过本篇教程,您可以很 ...
- ASP.NET MVC 微信公众号支付,微信公众平台配置
微信公众号支付,首先要登录微信公众号进行配置: 第一步:配置网页授权域名
- 微信公众号支付流程(Node实现)
前言 花费了一天时间,调通了微信公众号支付.作下记录,方便以后再次填坑.先声明,微信公众号支付,不同于微信H5支付,这点在本文结束时再详细说明. 微信配置 设置测试目录 在微信公众平台设置,栏目见下图 ...
- 微信公众号支付开发全过程 --JAVA
按照惯例,开头总得写点感想 ------------------------------------------------------------------ 业务流程 这个微信官网说的还是很详细的 ...
- 到处是坑的微信公众号支付开发(java)
之前公司项目开发中支付是用阿里的支付做的,那叫一个简单,随意:悲催的是,现在公司开发了微信公众号,所以我步入了全是坑的微信支付开发中... ------------------------------ ...
- 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结
最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...
- 微信公众号支付JSAPI网页,total_fee错误不正确,header重定向参数丢失,无法获取订单号和金额解决
微信公众号支付官方demo错误, 公众号支付只能用在微信里,也就是微信内部浏览器. 1.到WxPayHubHelper.php文件 JsApi_pub()类下createOauthUrlForCode ...
- 微信公众号支付提示mch_id参数格式错误
背景: .Net MVC微信公众号支付功能 问题: 今天在做网站微信支付的时候,一直提示“微信公众号支付提示mch_id参数格式错误” ! 解决方法: 其实这个问题一般并不是说你配置有错,首先它提示你 ...
随机推荐
- lightoj1066【BFS】
题意: 就是按照A->B->C->D....去拿,求步数: 思路: 有一个注意点:如果碰到合法字母吃掉,再以后的某次可以重新到改点: BFS的因为标记而减少了重复位置的到达,但是按照 ...
- Unity3D中常用的数据结构总结与分
阅读目录 1.几种常见的数据结构 2.几种常见数据结构的使用情景 来到周末,小匹夫终于有精力和时间来更新下博客了.前段时间小匹夫读过一份代码,对其中各种数据结构灵活的使用赞不绝口,同时也大大激发了小匹 ...
- Metabolic and gut microbial characterization of obesity-prone mice under high-fat diet (文献分享一组-赵容丽)
题目:高脂饮食下易肥胖小鼠的代谢和肠道微生物特性研究 Metabolic and gut microbial characterization of obesity-prone mice under ...
- pytest入门学习(2)
pytest的hello world pyt1.py def func(x): print (x+1); return x+1; def test_answer(): assert func(3) = ...
- 茅台【思维/数学/剪枝】By cellur925
题目传送门 给你\(n\)根木棍,问有多少种方法,使得选出的三根木棍能组成三角形. 开始想要用搜索的,但是写着写着卡壳了(?),于是改用贪心,开始对拍,觉得很稳,只是最后两个数据可能有点卡.很第一题难 ...
- TensorFlow数据集(二)——数据集的高层操作
参考书 <TensorFlow:实战Google深度学习框架>(第2版) 一个使用数据集进行训练和测试的完整例子. #!/usr/bin/env python # -*- coding: ...
- Eclipse 修改编码方式
1.修改全局(Eclipse默认)文本编码方式 2.修改某个工程编码方式 右键工程点击”属性“后,如下图
- bzoj 2441 [中山市选2011]小W的问题
bzoj 2441 [中山市选2011]小W的问题 Description 有一天,小W找了一个笛卡尔坐标系,并在上面选取了N个整点.他发现通过这些整点能够画出很多个"W"出来.具 ...
- 微信支付——基于laravel框架的php实现
现在经手的几乎每个项目都支持微信支付,简单记录下接入的大致流程. 1.首先商户等申请各种账号,微信支付商户号,APPID,API密钥,Appsecret 2.app端上传支付需要的各个字段 3.后台收 ...
- 1-26HashSet简介
Set的特点 Set里面存储的元素不能重复,没有索引,存取顺序不一致. package com.monkey1024.set; import java.util.HashSet; /** * Set的 ...