# 微信支付 实战开发
> 现阶段,最火的开发都离不开微信相关的
> 近期工作比较忙 正好工作正好是开发微信支付 , 那我现在就查一个微信支付的教程吧
> 希望对着手微信支付的人有所帮助,
微信支付,肯定离不开早一些相关成熟的微信支付类库了,但我找了很久,完全适合TP5,并且符合相关命名规则的的类库没有找到.
> 那我就自己改一下吧 现在共享给大家.
> 文件放在 extend/com/wxpay文件夹下
> 命名空间问com\wxpay
> 源代码我就放在本节微信支付类库源代码
接下来,我们一起开发微信支付吧
## 微信的支付流程
简单的说一下支付的流程
第一步 获取openid
第二步 根据openid进行统一下单获取订单号
第三步 根据统一下单的订单号 获取获取JsApi$getParameters参数
最后 JsApi中支付
下面根据这个顺路 我们一起来做吧
## 在base模块建立一个公共的新控制器
> 我喜欢把一些公用的处理逻辑的类都放到base模块,
> ![](https://box.kancloud.cn/8dadeb5933dc95e5229c208caf9cf331_288x325.png)
> 这些以后都是你的宝贝 .. 你懂得
建立好WxPay控制器以后,记得把接口文件的列表也挪过来
~~~
<?php
/**
* Created by PhpStorm.
* User: Mikkle
* Email:776329498@qq.com
* Date: 2017/2/4
* Time: 15:48
*/
namespace app\base\controller;
/**
* 微信支付帮助库
* ====================================================
* 命名空间 com\wxpay\+类名+_pub
* 接口分三种类型:
* 【请求型接口】--Wxpay_client_
* 统一支付接口类--UnifiedOrder
* 订单查询接口--OrderQuery
* 退款申请接口--Refund
* 退款查询接口--RefundQuery
* 对账单接口--DownloadBill
* 短链接转换接口--ShortUrl
* 【响应型接口】--Wxpay_server_
* 通用通知接口--Notify
* Native支付——请求商家获取商品信息接口--NativeCall
* 【其他】
* 静态链接二维码--NativeLink
* JSAPI支付--JsApi
* =====================================================
* 【CommonUtil】常用工具:
* trimString(),设置参数时需要用到的字符处理函数
* createNoncestr(),产生随机字符串,不长于32位
* formatBizQueryParaMap(),格式化参数,签名过程需要用到
* getSign(),生成签名
* arrayToXml(),array转xml
* xmlToArray(),xml转 array
* postXmlCurl(),以post方式提交xml到对应的接口url
* postXmlSSLCurl(),使用证书,以post方式提交xml到对应的接口url
*/
use think\Controller;
use think\Db;
use think\Session;
use com\wxpay\UnifiedOrder_pub as UnifiedOrder;
use com\wxpay\JsApi_pub as JaApi;
class WxPay extends Controller{
}
~~~
## 建立一个微信配置config参数
~~~
protected $wx_config=[
'wechat_appid'=>'wx1111111111111',//微信公众号身份的唯一标识。审核通过后,在微信发送的邮件中查看
'wechat_mchid'=>'1111111111',//受理商ID,身份标识 商户号
'wechat_appkey'=>'********************************',//商户支付密钥Key。审核通过后,在微信发送的邮件中查看
'wechat_appsecret'=>'****************************',//JSAPI接口中获取openid,审核后在公众平台开启开发模式后可查看
//证书路径,注意应该填写绝对路径 不用证书也是能支付的
'sslcert_path'=>'',
'sslkey_path'=> '',
];
protected $this->notify_url=""; //自己定义
~~~
这些参数是你微信支付的参数
## 订单数据库的设置参数
为了以后程序移植方便,我把订单数据库的数据参数化了
这样大家移植也方便多了
代码如下
~~~
protected $order_table_param=[
'table'=>'my_orders', //订单表名称
'no_field'=>'order_no', //订单号 字段名字
'state_field'=> 'is_pay',//订单支付状态值字段名
'amount_field'=>'amount',//订单金额值字段名
'pay_ok'=> '1', //订单已支付状态值
'pay_no'=> '0', // 订单未支付状态值
'map' => [['status' => 1] ,[ 'order_state'=>0]], //其他订单是否可以支付的参数值
];
~~~
## 接下来 类的初始化
在初始化里, 首先定义时区 ,这是参照官方的文档的
接下来 动态加载config参数
我把支付的参数写到这个文档里,而没有写的config文件中,主要为了以后移植方便
接下来注入openid,我微信登录是在控制器类就完成的 所以这里就直接获取session
然后注入到$this->open_id
~~~
/**
* #User: Mikkle
* #Email:776329498@qq.com
* #Date:
*/
public function _initialize(){
ini_set('date.timezone','Asia/Shanghai');
config($this->wx_config);
//已登陆的设置openid 本人微信登录是在控制器里完成
if (Session::has('open_id','html5')) $this->open_id=Session::get('open_id','html5');
}
~~~
## 统一下单方法
接下来 我把官方的统一下单封装了一个方法 不多说了 源代码如下
~~~
/**
* 统一下单方法
* #User: Mikkle
* #Email:776329498@qq.com
* #Date:
* @param array $data
* @return bool
*/
protected function unifiedOrder($data=[]){
$unifiedOrder = new UnifiedOrder();
$unifiedOrder->setParameter("openid",$this->open_id); // openid
$unifiedOrder->setParameter("body",'商品订单号'+$data['order_no']); // 商品描术
$unifiedOrder->setParameter("out_trade_no",$data['order_no'].'_'.$unifiedOrder->createNoncestr(6)); // 商户订单号
$unifiedOrder->setParameter("total_fee",$data['amount']*100); // 总金额
$unifiedOrder->setParameter("notify_url",$this->notify_url); // 通知地址 $this->notify_url自己定义
$unifiedOrder->setParameter("trade_type","JSAPI"); // 交易类型
return $unifiedOrder->getPrepayId();
}
~~~
## 获取JsApi$getParameters参数
接下来封装获取Jsapi的参数
~~~
/**
* 获取JsApi$getParameters参数
* #User: Mikkle
* #Email:776329498@qq.com
* #Date:
* @param string $unified_order
* @return string
*/
protected function getParameters($unified_order=''){
$jsApi= new JaApi();
$jsApi->setPrepayId($unified_order);
$jsApiParameters = $jsApi->getParameters();
return $jsApiParameters;
}
~~~
## 准备工作都OK的 下面进入主菜
## 根据订单号支付订单的方法
### 首先根据订单号查找订单
~~~
$param=$this->order_table_param;
$order_info=Db::table($param['table'])
->field(' '. $param['no_field'].' , '.$param['amount_field'].' ')
->where($param['map'][0])
->where($param['state_field'],'=','0')
->where(['order_no'=>$order_no])
->find();
~~~
我是为了通用性 搞了一个订单查询这么复杂 你如果就一个程序用 重新写一些也可以
### 判断订单状态
~~~
if (!$order_info) return ['code'=>1010,'msg'=>'订单不存在或者已经是完成状态'];
$data=[
'order_no'=>$order_no,
'amount'=>$order_info['amount'],
];
~~~
如何订单不存在或者已经完成返回错误信息
如何订单存在 获取订单金额
### 进行统一下单 获取统一下单的订单号
~~~
$unified_order = $this->unifiedOrder($data); //统一下单
$this->unified_order=$unified_order;
~~~
### 获取JsApi$getParameters参数
~~~
$jsApiParameters=$this->getParameters($unified_order);
~~~
## 最后整合代码整合一个方法
整合好的代码如下
~~~
/**
* 根据订单号支付订单返回$getParameters参数
* #User: Mikkle
* #Email:776329498@qq.com
* #Date:
* @param string $order_no
* @param array $param
* @return array
*/
public function payByOrderNo($order_no='2017020453102495',$param=[]){
$param=$this->order_table_param;
$order_info=Db::table($param['table'])
->field(' '. $param['no_field'].' , '.$param['amount_field'].' ')
->where($param['map'][0])
->where($param['state_field'],'=','0')
->where(['order_no'=>$order_no])
->find();
if (!$order_info) return ['code'=>1010,'msg'=>'订单不存在或者已经是完成状态'];
$data=[
'order_no'=>$order_no,
'amount'=>$order_info['amount'],
];
$unified_order = $this->unifiedOrder($data); //统一下单
$this->unified_order=$unified_order;
$jsApiParameters=$this->getParameters($unified_order);
return ['code'=>1001,'order_no'=>$order_no,'jsApiParameters'=>$jsApiParameters,'amount'=>$order_info['amount'],];
}
~~~
## 最后 在你的项目的控制器中调用这个方法就能支付了
~~~
<?php
/**
* Created by PhpStorm.
* User: Mikkle
* Email:776329498@qq.com
* Date: 2017/2/8
* Time: 11:32
*/
namespace app\api\controller;
class WxpayAction extends Auth
{
public function index($order_no='2017020453102495'){
$data=controller('base/WxPay')->payByOrderNo($order_no);
$this->assign('amount',$data['amount']);
$this->assign('order_no',$order_no);
$this->assign("jsApiParameters" ,$data['jsApiParameters']);
$this->assign('openid',$this->open_id);
return $this->fetch('wxpay/pay');
}
}
~~~
模版的源代码
~~~
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
<title>微信安全支付</title>
<link rel="stylesheet" href="__WECHAT_CSS__/weui.css"/>
<link rel="stylesheet" href="__WECHAT_EXAMPLE__/example.css"/>
<script type="text/javascript">
function okAjax(out_trade_no,ext){
$.ajax({
type:"post",
url:"",
data:{out_trade_no:out_trade_no,ext:ext},
dataType:"text",
success:function(data){
if(data){
wx.closeWindow()
}
},
async:false
});
}
//调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{$jsApiParameters},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
okAjax('{$order_no}','{$order_no}');
}else{
WeixinJSBridge.log(res.err_msg);
// alert('{$order_no}');
alert('支付失败!'+res.err_code+res.err_desc+res.err_msg);
}
}
);
}
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>
</head>
<body ontouchstart>
<div class="weui_msg">
<div class="weui_icon_area"><i class="weui_icon_success weui_icon_msg"></i></div>
<div class="weui_text_area">
<h2 class="weui_msg_title"><font color="#888">你将为{$order_no}支付{$amount}元</font></h2>
</div>
</div>
<div class="weui_opr_area">
<p class="weui_btn_area">
<button type="button" class="weui_btn weui_btn_primary" onclick="callpay()" >立即支付</button>
<a href="javascript:;" onclick="wx.closeWindow()" class="weui_btn weui_btn_default">取消</a>
</p>
</div>
</div>
<script src="__WECHAT_EXAMPLE__/zepto.min.js"></script>
<script src="__WECHAT_EXAMPLE__/router.min.js"></script>
<script src="__WECHAT_EXAMPLE__/example.js"></script>
</body>
</html>
~~~
- 序言及更新日志
- 前言一 开发PHP必备的环境(你可以不看)
- LinUX系统ThinkPHP5链接MsSQL数据库的pdo_dblib扩展
- centos7.2挂载硬盘攻略
- Centos系统Redis安装及Redis的PHP扩展安装
- Centos系统增加Swap(系统交换区)的方法
- 前言二 开发PHP软件配置和介绍(你依然可以不看)
- 数据库SQL文件
- 本地Git(版本控制)的搭建
- GIT远程仓库的克隆和推送
- Git常用命令
- PHP面向对象思想实战经验领悟
- PHP面向对象实战----命名空间
- PHP面向对象实战----继承
- 基类实战--底层方法封装
- 基类实战--构造函数实战
- 基类实战--析构函数的使用
- TP5实战开发前篇---控制器(controller)
- 控制器中Request类的使用
- 控制器中基类的使用
- TP5实战开发前篇---模型篇(model)
- TP5实战开发前篇---验证器篇(Validate)
- TP5实战课程入门篇---花拳绣腿
- 模块以及类的文件的建立
- Api开发------单条信息显示
- Api开发---单条信息复杂关联显示
- Api开发---查询信息缓存Cache的应用
- TP5实战技巧---开发思路 引路造桥
- TP5实战技巧---整合基类 化繁为简
- TP5实战课程入门篇---数据操作
- Api开发---数据的添加和修改
- API开发---快速开发API通用接口
- TP5专用微信sdk使用教程
- THINKPHP5微信SDK更新记录及升级指导
- TP5专用SDK 微信参数配置方法
- 微信公众号推送接口对接教程
- 微信推送接口对接示例含扫描登录微信端部分
- TP5专用微信支付SDK使用简介
- TP5专用支付宝支付SDK使用说明
- 使用NW将开发的网站打包成桌面应用
- TP5高阶实战课程 进阶篇概述
- 进阶篇一 实战开发之习惯及要求
- 进阶篇二 实战开发之控制器
- 控制器基类之控制器基类使用方法
- 控制器基类之控制器基类常用方法分享
- 控制器基类之构造函数的使用方法
- 进阶篇三 实战开发之权限控制
- TP5实战源码 --- 全局用户信息验证类Auth
- TP5实战源码 --- 微信Auth实战开发源码
- 进阶篇四 实战开发之模型
- 模型基类之模型基类的用途
- 模型基类之常用数据处理方法
- 模型逻辑层之实战代码(含事务)
- 模型实战开发之模型常用方法
- 模型实战源码 --- 乐观锁的应用
- 模型实战技巧---Model事件功能的使用
- 模型事件实战应用---数据库操作日志
- 进阶篇五 实战开发之缓存(Cache)
- TP5实战源码---应用缓存获取城市信息
- TP5实战源码---应用缓存获取分类详情
- 进阶篇六 TP5类库的封装和使用
- DataEdit快捷操作类库
- ShowCode快捷使用类库
- 阿里大于 短信API接口 TP5专用类库
- DatabaseUpgrade数据库对比及更新类库
- AuthWeb权限类使用说明
- 进阶篇七 服务层的应用
- 服务层源码示例
- 服务层基类源码
- 进阶篇八 应用层Redis数据处理基类
- Redis服务层基类源码
- 进阶篇九 使用Redis类库处理一般的抢购(秒杀)活动示例
- 进阶篇十 某大型项目应用本Redis类源码示例(含事务 乐观锁)
- 进阶篇十一 逻辑层的应用
- 逻辑层基类源码
- 进阶篇 服务层代码示例
- 高阶实战课程 进阶篇持续新增中
- 高阶篇一 TP5命令行之守护任务源码
- TP5实战源码 --- 命令行
- TP5实战源码 --- 通过shell建立PHP守护程序
- 高阶篇二 使用Redis队列发送微信模版消息
- 高阶篇二 之 Worker队列基类源码
- 高阶篇三 TP5实战之Redis缓存应用
- Redis实战源码之Hash专用类库源码
- Redis实战源码之Model类结合
- Redis实战源码之模型Hash基类源码
- Redis实战源码之Hash查询使用技巧
- Redis实战源码之 shell脚本中redis赋值和取值
- 高阶篇四 Swoole的实战应用
- swoole基类代码
- Swoole扩展WebsocketServer专用类
- 基于Swoole的多Room聊天室的程序
- Swoole守护服务shell源码
- 高阶篇五 命令行异步多进程队列类的应用
- tp_worker类源码
- WorkerBase
- WorkerCommand
- WorkerRedis
- Redis类
- CycleWorkBase
- WorkerHookBase异步钩子
- 队列日志SQL
- 高阶篇六 定时执行队列类库以及使用方法
- 定时队列类库源码
- 高阶篇七 异步执行循环队列类库以及使用教程
- CycleWorkBase源码
- 高阶实战课程 进阶篇持续新增中
- Extend便捷类库源码库
- 阿里相关类库
- SendSms--验证码API接口文件
- 权限相关类库目录
- AuthWeb 权限验证类库
- Redis便捷操作类库(20171224更新)
- Redis
- Tools工具类库集
- Curl类库
- DataEdit
- Rand类库
- ShowCode类库
- Upload类库
- 附件集合
- 附件一:微信支付 实战开发源码
- 微信支付类库源代码
- Common_util_pub.php
- DownloadBill_pub.php
- JsApi_pub.php
- NativeCall_pub.php
- NativeLink_pub.php
- OrderQuery_pub.php
- Refund_pub.php
- RefundQuery_pub.php
- SDKRuntimeException.php
- ShortUrl_pub.php
- UnifiedOrder_pub.php
- Wxpay_client_pub.php
- Wxpay_server_pub.php
- WxPayConf_pub.php
- 微信支付回调页面源码
- 附件二 顺丰快递BSP接口实战开发源码
- 顺丰快递BSP接口实战开发源码
- 顺丰BSP基类
- 顺丰BSP基础代码
- 顺丰BSP下单接口
- 顺丰BSP查单接口
- 顺丰BSP确认/取消接口
- 附件三 APP注册登陆接口源码(含融云平台接口)
- 附件四 TP5订单Model(含事务 获取器 修改器等方法)
- 附录五 RSA加密解密
- Rsa文件源码
- 附件六 阿里大于短信接口
- 附件七 AES加解密类
- AES加解密类源码
- 附件八 TP5路由设置源码
- 附件九 TP5 Excel导入导出下载便捷类库
- Excel类库TP5源码
- 附件十 TP5便捷操作Redis类库源码
- TP5源码 Redis操作便捷类库
- 附件十一 TP5源码 上传文件入库类源码
- 上传类Upload源码
- Upload类上传配置文件
- 存储图像文件的数据库SQL文件
- 存储文件的数据库SQL文件
- 附件十二 TP5 图片处理增强类 支持缩略图在线显示
- 附件十三 微信推送消息接口类库源码
- 附件十三 微信推送消息接口类库源码 之 基类
- 附件十四 存储微信昵称的处理方法