# 微信支付 实战开发 > 现阶段,最火的开发都离不开微信相关的 > 近期工作比较忙 正好工作正好是开发微信支付 , 那我现在就查一个微信支付的教程吧 > 希望对着手微信支付的人有所帮助, 微信支付,肯定离不开早一些相关成熟的微信支付类库了,但我找了很久,完全适合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> ~~~