転送ブロガーhttps://blog.csdn.net/qq_38378384/article/details/80882980
それは、あまりにも多くの穴に、公共の番号を開発する少しより多くの経験を持っている可能性があるビットを書き込むための小さなプログラムモジュールのインターフェイスを支払うために数日かかった、と私はプロセスを通じてそれを記録したかったです。
上に移動するために支払うためにまず、マイクロ文字の最初のチャートアプレット:
私はそれがBaiduの学生は基本的にドキュメントのある非常に理解していない確認してくると信じています。私はおそらく以下のビジネスプロセス全体のロジックをまとめます。
契約の良好な受信とデータ送信パラメータの後端部とのインタフェースを呼び出すことにより、インタフェース、アプレットを開発小さなプログラムの形で一般的にマーチャント・システムのマイクロチャネル。この小さなプログラムの支払いでは、微信サーバーとの対話を維持する必要があります。大体このようなプロセス:
小さなプログラムは、ユーザーのOpenIDを取得するために商人サーバに渡され、コードを取得するためにログインインターフェイスを起動します
私たちは、公共OpenIDの数が異なるとマイクロチャネルプラットフォームは、それがユーザIDのアイデンティティであることを知って、それは我々がOpenIDを通じ異なるユーザを区別する必要がある、と言うことです、これが開発したマイクロチャネル単位は非常に精通している必要があります。支払うことを誰が知るために、我々は、OpenIDのは、それを取得する必要がありますどのように、その後、現在のユーザーのOpenIDを取得する必要がありますか?見て:
-
アプレットは、バックサーバに仮登録証明書のコードを取得するために)(wx.loginを呼び出し、開発者。
-
開発者は、一意のユーザとセッション鍵のOpenID SESSION_KEYを識別するサーバコードを交換します。
それを読んでいませんか?私に聞いて、心配しないでくださいすると、このビジネスプロセスは、一般的には、マイクロ文字にコードを取得する小さなプログラムwx.loginコード()で呼び出す必要があります最初のものです説明してください、そして商人サーバを通過するためのコード要求を得、その後、サンパウロの操作を経由してマーチャントサーバによってマイクロチャネルサーバとSESSION_KEYおよびOpenIDのを来て。
擬似コード(アプレット側):
-
入手トークン: 関数(){
-
//コールログインタフェース
-
wx.login({
-
成功:機能(RES){
-
VARコード= res.code。
-
wx.request({
-
url: 商户服务器接口地址,
-
data: {
-
code: code
-
},
-
method: 'POST',
-
success: function (res) {
-
wx.setStorageSync( 'token', res.data.token); //存在小程序缓存中
-
},
-
fail: function (res) {
-
console.log(res.data);
-
}
-
})
-
}
-
})
-
}
调用这几行代码就可以向跟微信服务器要code,并且将code传到商户服务器中,记住这里最好使用post发送请求,安全性的东西我应该不用讲了,因为避免其他人滥用接口,于是我们使用token来进行验证。并将商户服务器返回的token存在小程序缓存中。
那么服务器端应该怎么做呢?
我门通过小程序提交的code,和小程序的APPID以及APPSECRET和拼接下列的url,并用curl进行get请求。
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
返回的数据是一个json对象,我门通过使用json_decode(JSON,true)解析为数组,数据包括用户的openID以及session_key,获取到了后我们应该将openID存入数据库中,它代表着用户的身份,那么令牌应该怎么生成呢。
二.token的生成以及缓存
我们根据一个用户表将id和openid联系起来,对应openID的id则是用户的uid,我们可以这么封装
-
//要缓存的数据数组
-
$cacheValue = $result; //包含openID和session_key
-
$cacheValue[ 'uid'] =$uid; //用户id
-
-
$cacheValue[ 'scope'] =ScopeEnum::User; //用户权限级别
缓存的方式我们可以选择redis,memcache, 文件缓存等等,采用键值对(key-value)的方式进行存储,记得设置好过期时间。这里的key我们用token来赋值,token可以通过这样的方式进行生成:
-
//获取32位随机字符串
-
$str = getRandChar( 32); //自定义方法生成32位随机串
-
//三组字符串进行md5加密
-
$timeStamp =$_SERVER[ 'REQUEST_TIME_FLOAT'];
-
//salt
-
$salt = config( 'secure.token_salt'); //随机字符串
-
//返回token
-
-
return md5($str.$timeStamp.$salt);
这种算法基本保障了token的唯一性。因为值是我们获取到的openID和session_key所在的数组,所以需要将数组转成json才能存进去。以后的代码当我们需要openID或者uid等时可以直接通过取缓存的方式来取。
三,调用统一下单接口,获取prepay_id,再次签名
在你写完了订单操作后,如何让用户支付订单费用呢?这里就是重点了,我一步一步来说:
1.下载微信JS-SDK:
(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1)
解压打开进入lib文件夹中:
我们需要将lib中的文件放到我们的框架中,例如我使用的是tp5,就放到extend下,最好是在extend下建个子文件夹。其中WxPay.Api.php是入口,WxPay.Config.php是配置文件。下好后需要改动一些地方。在WxPay.Config.php中修改下列的东西改成你的。
然后在WxPay.Api.php中require一下WxPay.Notify.php,如图:
在某个控制器或者服务层的代码先是用Loader::import()引入WxPay.Api.php,相当于五个都引入了。
2.调用统一下单api
这里要啰嗦的是,如何你写的是有关商品买卖的小程序,那么需要在支付前再次检测一下库存量,因为用户下完订单后不一定马上就会付款,如果在付款的期间库存量没了便会出现问题。业务逻辑我就不说太多了,这取决于你写代码的严谨性。
在我们引入了上面那个文件后,先实例化这个类WxPayUnifiedOrder,把需要的参数通过调用对应的方法传入。
伪代码如下:
-
//调用微信支付统一下单接口
-
$wxOrderData = new \WxPayUnifiedOrder();
-
//设置相关参数
-
$wxOrderData->SetOut_trade_no( $this->orderNO);
-
$wxOrderData->SetTrade_type( 'JSAPI');
-
wxOrderData- $> SetTotal_fee(totalPrice * $ 100); //ここでは、単価のポイントです
-
$ wxOrderData-> SetBody( 'MC')。
-
$ wxOrderData-> SetOpenid($のOpenIDの);
-
wxOrderData- $> SetNotify_url(設定( 'secure.pay_back_url')); //コールバックペイ
最初のものはご注文番号、注文番号の生成方法をカスタマイズすることができますし、2番目のパラメータは死んで、3番目は合計注文価格であり、それは、その後、トランスコードされ、第四中国人であれば4番目の名前です。 OpenIDのは、この時間は、我々はキャッシュから取ることができること、です。最後の1が支払われているコールバックが成功したマイクロチャネル支払いアドレスがアクセスされます。パブリックネットワークにアクセスすることができ、またはプロキシサーバーを逆にngrok使用する場合は、ローカルに転送しなければなりません。
パラメータが設定された後、SDKの直接メソッドを呼び出します
$wxOrder = \WxPayApi::unifiedOrder($wxOrderData);
パラメータが間違っていない場合は、返されたデータはprepay_idが含まれています、これは我々が必要とするパラメータです。
3.署名再び
-
// JSAPI入力オブジェクトを提出
-
$ jsApiPayData = 新しい\ WxPayJsApiPay();
-
//設定APPID
-
$ jsApiPayData-> SetAppid(設定( 'wx.app_id'));
-
// timeStampに
-
$ jsApiPayData-> SetTimeStamp((文字列)時間());
-
//ランダムな文字列
-
$randStr = md5(time().mt_rand( 0,1000));
-
$jsApiPayData->SetNonceStr($randStr);
-
//数据报
-
$jsApiPayData->SetPackage( 'prepay_id='.$wxOrder['prepay_id']);
-
//类型
-
$jsApiPayData->SetSignType( 'MD5');
-
//生成签名
-
$sign = $jsApiPayData->MakeSign();
-
//获得签名数组
-
$signData = $jsApiPayData->GetValues();
-
//增加字段paySign
-
$signData[ 'paySign']=$sign;
-
//删除signData中的app_Id字段
-
unset($signData['appId']);
-
return $signData;
再次签名完成后,就把五个参数返回给小程序。
四,小程序获取五个参数后,鉴权调起支付
伪代码(小程序端)
-
pay: function () {
-
var token = wx.getStorageSync('token');
-
var that = this;
-
-
wx.request({
-
url: baseUrl + '/order',
-
header: {
-
token: token
-
},
-
data: { //产品的数据
-
products:
-
[
-
{
-
product_id: 1, count: 1
-
},
-
-
{
-
product_id: 2, count: 1
-
}
-
]
-
},
-
method: 'POST',
-
success: function (res) {
-
console.log(res.data);
-
if (res.data.pass) {
-
wx.setStorageSync( 'order_id', res.data.order_id);
-
that.getPreOrder(token, res.data.order_id); //调用getPreOrder
-
}
-
else {
-
console.log('订单未创建成功');
-
}
-
}
-
})
-
},
-
-
getPreOrder: function (token, orderID) {
-
if (token) {
-
wx.request({
-
url: baseUrl + '/pay/pre_order',
-
method: 'POST',
-
header: {
-
token: token
-
},
-
data: {
-
id: orderID
-
},
-
success: function (res) {
-
var preData = res.data;
-
console.log(preData);
-
-
wx.requestPayment({ //请求支付
-
timeStamp: preData.timeStamp.toString(),
-
nonceStr: preData.nonceStr,
-
package: preData.package,
-
signType: preData.signType,
-
paySign: preData.paySign,
-
success: function (res) {
-
console.log(res.data);
-
},
-
fail: function (error) {
-
console.log(error);
-
}
-
})
-
}
-
})
-
}
-
},
如果一切正常的话,在微信开发者工具就会显示这个二维码,
如果在真机上测试的话,就会直接弹出支付页面。小程序会直接显示支付成功或者失败的页面,然后微信服务器就会开始访问我们之前设置的支付回调地址来推送支付结果,根据结果可以来更新订单的状态。这里我就不写业务逻辑了,大概讲一下就好。
五,支付回调
实际上我们需要重写WxPayNotify类的NotifyProcess方法,这里记得Loader::impor()引入那个入口类。
-
/**
-
*
-
* 回调方法入口,子类可重写该方法
-
* 注意:
-
* 1、微信回调超时时间为2s,建议用户使用异步处理流程,确认成功之后立刻回复微信服务器
-
* 2、微信服务器在调用失败或者接到回包为非确认包的时候,会发起重试,需确保你的回调是可以重入
-
* @param array $data 回调解释出的参数
-
* @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
-
* @return true 回调出来完成不需要继续回调,false回调处理未完成需要继续回调
-
*/
-
public function NotifyProcess($data, &$msg)
-
{
-
//TODO 用户基础该类之后需要重写该方法,成功的时候返回true,失败返回false
-
return true;
-
}
也就是说你需要写个新类继承WxPayNotify,再重写NotifyProcess方法,根据检查$data['result_code']是否为SUCCESS可以判断成功与否,成功的话你可以根据业务需求写业务逻辑,最后return true 即可。这时候会想,我重写了这个方法后微信怎么调用呢,其实这里微信不是要直接调用这个方法,你应该在微信支付回调的方法中实例化这个新类,然后根据获得的对象去调用Handle()方法。$obj = new 新类(),$obj->Handle()。