经过摸索,与官方提供的slim无异,同样使用__invoke魔法函数即可,步骤如下:
1.config.php打开hook,即设置$config['enable_hooks'] = TRUE;
详情文档参见:http://codeigniter.org.cn/user_guide/general/hooks.html
2.在hook.php中实现
<?php
require_once __DIR__ . '/../third_party/wxpay/WxPay.Api.php';
use \LeanCloud\Engine\LeanEngine;
use \LeanCloud\Engine\Cloud;
use \LeanCloud\Client;
use \LeanCloud\Storage\CookieStorage;
/*
* Define cloud functions and hooks on LeanCloud
*/
// /1.1/functions/sayHello
Cloud::define("pay", function($params, $user) {
// var_dump($user);
$openid = $user->get('authData')["lc_weapp"]["openid"];
// 初始化值对象
$input = new WxPayUnifiedOrder();
// 文档提及的参数规范:商家名称-销售商品类目
$input->SetBody($params['body']);
// 订单号应该是由小程序端传给服务端的,在用户下单时即生成,demo中取值是一个生成的时间戳
$input->SetOut_trade_no($params['tradeNo']);
// 费用应该是由小程序端传给服务端的,在用户下单时告知服务端应付金额,demo中取值是1,即1分钱
$input->SetTotal_fee($params['totalFee']);
$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");
$input->SetTrade_type("JSAPI");
// 由小程序端传给服务端
$input->SetOpenid($openid);
// 向微信统一下单,并返回order,它是一个array数组
$order = WxPayApi::unifiedOrder($input);
// json化返回给小程序端
header("Content-Type: application/json");
return getJsApiParameters($order);
// return "hello {$params['name']}";
});
function getJsApiParameters($UnifiedOrderResult) {
if(!array_key_exists("appid", $UnifiedOrderResult)
|| !array_key_exists("prepay_id", $UnifiedOrderResult)
|| $UnifiedOrderResult['prepay_id'] == "")
{
throw new WxPayException("参数错误");
}
$jsapi = new WxPayJsApiPay();
$jsapi->SetAppid($UnifiedOrderResult["appid"]);
$timeStamp = time();
$jsapi->SetTimeStamp("$timeStamp");
$jsapi->SetNonceStr(WxPayApi::getNonceStr());
$jsapi->SetPackage("prepay_id=" . $UnifiedOrderResult['prepay_id']);
$jsapi->SetSignType("MD5");
$jsapi->SetPaySign($jsapi->MakeSign());
$parameters = json_encode($jsapi->GetValues());
return $parameters;
}
class CIEngine extends LeanEngine {
function __invoke() {
$this->dispatch($_SERVER['REQUEST_METHOD'],
$_SERVER['REQUEST_URI']);
}
}
$hook['pre_system'] = function() {
// 参数依次为 AppId, AppKey, MasterKey
Client::initialize("SgHcsYqoLaFTG0XDMD3Gtm0I-**", "xdv2nwj**glFoFXkQcxP" ,"v3P5xzDa0b5***0xX0biHpT");
Client::useMasterKey(true);
Client::setStorage(new CookieStorage());
$engine = new CIEngine();
// 以下是核心语句,直接像使用函数那样在对象上调用
$engine();
};
3.最后,在小程序端调用云函数
AV.Cloud.run('pay', paramsJson).then(function(response) {
response = JSON.parse(response);
// 调用成功,得到成功的应答 data
console.log(response);
// 发起支付
wx.requestPayment({
'timeStamp': response.timeStamp,
'nonceStr': response.nonceStr,
'package': response.package,
'signType': 'MD5',
'paySign': response.paySign,
'success':function(res){
wx.showToast({
title: '支付成功'
});
// update order,此处是不良示范,应该通过上述SetNotify_url回调通知里在服务端更新订单状态
var query = new AV.Query('Order');
query.get(that.data.orderId).then(function (order) {
order.set('status', 1);
order.save();
console.log('status: ' + 1);
}, function (err) {
});
}
});
}, function(err) {
// 处理调用失败
console.log(err);
});
这里有一个坑,就是服务端发来的数据是纯文本,而不是json对象,哪怕是调了header函数,header("Content-Type: application/json");还是一样,所以要强转一下。
response = JSON.parse(response);
而之前的做法,要先在小程序中调用wx.login,请拿appid/appsecret获取openId,最后wx.request请求统一下单url。现在的做法要简单多的,小程序端就不关心https://lendoo.leanapp.cn
这个地址是何物了,直接跑AV.Cloud.run()就可以了。
4. 完善微信支付回调通知
由服务端发起回调更新订单的状态才是正确的打开方式,于是在WXPay.php文件增加notify方法,供微信侧回调用
public function notify() {
//获取通知的数据
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
//如果返回成功则验证签名
$result = WxPayResults::Init($xml);
$notify = new PayNotifyCallBack();
$notify->Handle(false);
$returnValues = $notify->GetValues();
//交易成功
if(!empty($returnValues['return_code']) && $returnValues['return_code'] == 'SUCCESS'){
//商户逻辑处理,如订单状态更新为已支付
$out_trade_no = $result['out_trade_no'];
// 通过订单id,将它改为已支付状态
$order = Object::create('Order', $out_trade_no);
$order->set('status', 1);
$order->save();
}
echo $notify->ToXml();//返回给微信确认
}
其中PayNotifyCallBack类,在微信提供的php sdk包已经提供,我只是改了文件名,原包名为notify.php
微信php sdk的下载地址是:https://pay.weixin.qq.com/wiki/doc/api/download/WxpayAPI_php_v3.zip
相应地,在统一下单的配置参数中,换上真实的回调地址,即将上述$input->SetNotify_url("http://paysdk.weixin.qq.com/example/notify.php");
更正为$input->SetNotify_url("https://lendoo.leanapp.cn/WXPay/notify");
这样一来,微信支付那头就是隔段时间发通知过来,直到处理成功为止;如果终止不能成功,微信端才会放弃。 源码下载:http://git.oschina.net/dotton/lendoo-wx,本文涉及代码存于/pages/order/payment文件夹中;相应后端代码托管在:http://git.oschina.net/dotton/lendoo-web,代码存于config/hooks.php目录下
对微信小程序开发有兴趣的朋友可以关注我的公众号【huangxiujie85】,第一时间获取博文推送。