ThinkPHP结合微信支付笔记
微信支付前期准备工作
- 已经认证的微信服务号(略)
- 拥有微信支付权限
- 下载微信官方SDK,并解压到ThinkPHP/ThinkPHP/Library/Vendor/WxPay/下
SDK下载地址: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1
- 下载商户证书,解压到服务器下,本例放置于pay/cert/下
- 配置账号信息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>