ThinkPHP结合微信支付笔记

后端开发
2018年06月29日
964

微信支付前期准备工作

  1. 已经认证的微信服务号(略)
  2. 拥有微信支付权限
  3. 下载微信官方SDK,并解压到ThinkPHP/ThinkPHP/Library/Vendor/WxPay/下

    SDK下载地址: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

  4. 下载商户证书,解压到服务器下,本例放置于pay/cert/下
  5. 配置账号信息Vendor/Wxpay/lib/WxPay.Config.php
php
/** * 配置账号信息 */ class WxPayConfig { //=======【基本信息设置】===================================== // /** * TODO: 修改这里配置为您自己申请的商户信息 * 微信公众号信息配置 * * APPID:绑定支付的APPID(必须配置,开户邮件中可查看) * * MCHID:商户号(必须配置,开户邮件中可查看) * * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置) * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert * * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN * @var string */ const APPID = '8888888888888888'; const MCHID = '8888888888'; const KEY = '88888888888888888888888888888'; const APPSECRET = '88888888888888888888888888'; //=======【证书路径设置】===================================== /** * TODO:设置商户证书路径 * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载, * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书) * @var path */ const SSLCERT_PATH = '/www/pay/cert/apiclient_cert.pem'; const SSLKEY_PATH = '/www/pay/cert/apiclient_key.pem'; const CAINFO_PATH = '/www/pay/cert/rootca.pem'; //=======【curl代理设置】=================================== /** * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0 * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器, * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置) * @var unknown_type */ const CURL_PROXY_HOST = "0.0.0.0"; const CURL_PROXY_PORT = 0; //=======【上报信息配置】=================================== /** * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】, * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少 * 开启错误上报。 * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报 * @var int */ const REPORT_LEVENL = 1; }

扫码支付模式二

业务流程:

1、用户在页面下订单,数据提交到数据库,自动跳转到支付页面

数据模拟:

php
$data = array( 'id' => 1, 'name' => 'XXX商品', 'price' => 100, // 单位:分 'time' => '20161012100000', 'payment_status' => 0, // 支付状态 未支付 'status' => 0, // 订单状态 未处理 );

2、支付页面接收参数,获取数据数据信息,调用微信支付,生成二维码,并展示在支付页面上

3、用户在规定时间内通过扫码方式进行支付

4、用户支付完成后,接收微信服务器发送的通知,处理业务逻辑并回应微信服务器

sql
update table set payment_status = 1 where id = 1; // 设置为已支付状态

5、完成支付!

支付页面代码:

php
class IndexController extends Controller { // 控制器初始化方法 public function _initialize() { // 自动加载类 vendor( 'WxPay.lib.WxPay#Api' ); vendor( 'WxPay.example.WxPay#NativePay' ); vendor( 'WxPay.example.log' ); } public function index(){ $id = I('get.id'); // 此处获取订单数据信息,计算出商品总金额 [ code.... ] // 实例化支付模型 $notify = new \NativePay(); $total_fee = 1; // 通过计算得出的商品总金额,单位:分,此处为模拟数据 /** * 流程: * 1、调用统一下单,取得code_url,生成二维码 * 2、用户扫描二维码,进行支付 * 3、支付完成之后,微信服务器会通知支付成功 * 4、在支付成功通知中需要查单确认是否真正支付成功(见:notify.php) */ $input = new \WxPayUnifiedOrder(); $input->SetBody("购买xxxx支付"); // 支付标题 $input->SetAttach("{$id}"); // 商家数据包 $input->SetOut_trade_no(\WxPayConfig::MCHID.date("YmdHis")); // 支付订单号 $input->SetTotal_fee("{$total_fee}"); // 支付总价 (单位: 分) $input->SetTime_start(date("YmdHis")); // 支付链接生成时间 $input->SetTime_expire(date("YmdHis", time() + 600)); // 支付链接过期时间 $input->SetGoods_tag("goods_tag"); // 商品标签 $input->SetNotify_url("http://www.xxxx.com/notify.html"); // 支付回调地址 $input->SetTrade_type("NATIVE"); // 支付模式 $input->SetProduct_id("{$info['sn_code']}"); // 商品ID $result = $notify->GetPayUrl($input); // 获取URL $url = urlencode($result["code_url"]); $return_info['url'] = $url; exit(I('get.jsoncallback') . "(" . json_encode($return_info) . ")"); /** * 页面通过Ajax请求获取微信支付返回数据, * 接收数据并再次请求prcode方法获取二维码 并输出到页面上 */ } // 输出二维码 public function qrcode() { Vendor( 'WxPay.example.phpqrcode.phpqrcode'); $url = I('get.data','urldecode'); $qr = new \QRcode; $qr::png($url); } // 接收微信端返回的数据 , 支付回调地址 // 微信支付服务器会在半小时内请求8次这个方法(好像是这样的,具体忘了),直到此方法返回"SUCCESS"状态后终止 public function notify() { header("content-type:text/xml"); $xml = $GLOBALS['HTTP_RAW_POST_DATA']; //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); if($data['result_code'] == "SUCCESS" && $data['return_code'] == "SUCCESS" ) { // 此处处理你的业务逻辑,如更新订单支付状态 [ code.... ] // 返回成功状态码,告诉微信端别再请求这个页面了! echo "SUCCESS"; exit; } } }

JsApi

业务流程:

1、用户在微信客户端访问页面,授权服务器获取用户资料,并下订单,数据提交到数据库,自动跳转到支付页面

2、支付页面接收参数,生成支付链接

3、用户在规定时间内进行支付

4、用户完成支付后,接收微信服务器发送的通知,处理业务逻辑并回应微信服务器

5、完成支付并返回用户之前访问的页面

代码如下:

php
class JsApiController extends Controller { public function _initialize() { // 自动加载类 Vendor('WxPay.lib.WxPay#Api'); Vendor('WxPay.example.WxPay#JsApiPay'); Vendor('WxPay.example.log'); } public function index() { // 获取订单信息,计算出商品总金额 [ code.... ] $total_fee = 1; // 数据模拟 // 获取用户openid $tools = new \JsApiPay(); $openId = $tools->GetOpenid(); // 统一下单 $input = new \WxPayUnifiedOrder(); $input->SetBody("商品xxxx支付"); $input->SetAttach("{$id}"); $input->SetOut_trade_no(\WxPayConfig::MCHID.date("YmdHis")); $input->SetTotal_fee("{$total_fee}"); $input->SetTime_start(date("YmdHis")); $input->SetTime_expire(date("YmdHis", time() + 600)); $input->SetGoods_tag("goods_tag"); $input->SetNotify_url("http://www.xxx.com/notify.html"); $input->SetTrade_type("JSAPI"); $input->SetOpenid($openId); $order = \WxPayApi::unifiedOrder($input); $jsApiParameters = $tools->GetJsApiParameters($order); $this->assign('jsApiParameters',$jsApiParameters); $this->display(); } // 接收微信端返回的数据 public function notify() { $xml = $GLOBALS['HTTP_RAW_POST_DATA']; //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); if($data['result_code'] == "SUCCESS" && $data['return_code'] == "SUCCESS" ) { // 此处处理你的业务逻辑 [ code.... ] // 返回成功状态码,告诉微信端别再请求这个页面了! echo "SUCCESS"; exit; } } }

index.html:

html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>订单支付</title> <meta name="viewport" content="width=device-width, initial-scale=1"/> <script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { WeixinJSBridge.invoke( 'getBrandWCPayRequest', {$jsApiParameters}, function(res){ if(res.err_msg == "get_brand_wcpay_request:ok" ) { alert("支付成功"); window.location.href = "{$url}"; } else { alert("支付失败"); window.location.href= "{$url}"; } } ); } 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 onload="callpay()"> <!-- <font color="#9ACD32"><b>该笔订单支付金额为<span style="color:#f00;font-size:50px">1分</span>钱</b></font><br/><br/> <div> <button style="width:210px; height:50px; border-radius: 15px;background-color:#FE6714; border:0px #FE6714 solid; cursor: pointer; color:white; font-size:16px;" type="button" onclick="callpay()" >立即支付</button> </div> --> </body> </html>