上一次教程我们解决了用户登录问题,今天解决微信支付问题。
微信支付的文档第一次接触特别头晕,看的云里雾里的,好在还是解决了,今天就分享下微信支付的解决方法
小程序微信支付流程为:
1、用户点击支付按钮
2、小程序向我的服务器发送用户openid、支付金额,因为之前已经获取过用户openid,所以这里可以直接发送
3、我的服务器接收到这些信息后将这些信息和其它一些信息(具体发送字段参考这里)一起发送到接口https://api.mch.weixin.qq.com/pay/unifiedorder 换取prepay_id,这里的复杂之处在于有一个签名字段sign需要我们生成,具体方法见下文
4、经过第三步我的服务器就可以得到prepay_id,可微信觉得还不够安全,因此又要求我对这个信息签名确保安全性,没办法,我的服务器只好将prepay_id和appId等一起做一次加密,然后将加密信息连同其它一些信息发送给小程序端
5、小程序端接收到需要的信息后,就可以调用wx.requestPayment来调起用户的支付窗口请求用户支付
6、用户输入密码支付成功后微信会将结果发送到我的服务器,这时我会验证这个结果(支付金额等)正确不正确,如果正确整个流程就结束了
小程序端代码:
wx.request({
url: 'https://mydomain/mycontroller/pay',
data:{
openid:openid,
userid:userid,
hongbao:that.data.hongbao,
},
success:function(res){
console.log(res)
wx.requestPayment({
'timeStamp': res.data.timeStamp,
'nonceStr': res.data.nonceStr,
'package': res.data.package,
'signType': 'MD5',
'paySign': res.data.paySign,
'success': function (res) {
console.log(res)
},
'fail': function (res) {
console.log(res)
}
})
}
})
后端php处理我封装了一个类
<?php
$config = [
'appid' => APPID, //小程序APPID
'mch_id' => MCHID, //商户号
'api_key' => APISECRET //商户api secret
];
class Wxpay{
//统一支付接口
public static function uniorder($openid,$fee,$ip){
$nonceStr = self::getNonceStr();
$unidorder = array(
'appid' => $config['appid'],
'mch_id' => $config['mch_id'],
'nonce_str' => $nonceStr,
'body' => "问答-红包",//商品名称
'device_info' => "WEB",
'out_trade_no' => self::getTradeNum(),
'total_fee' => $fee* 100,
'spbill_create_ip' => $ip,
'notify_url' => 'https://mydomain/mycontroller/notify',
'trade_type' => 'JSAPI',
'openid' => $openid
);
$sign = self::getSign($unidorder);
$unidorder['sign'] = $sign;
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$xmldata = self::array2xml($unidorder);
$res = self::curl_post($url,$xmldata);
if(!$res){
return "api post error";
}
$result = self::xml2array($res);
if($result['result_code']=='FAIL'){
return $result['result_msg'];
}
$prepay_id = $result['prepay_id'];
//二次签名
$time = time();
$arr_sign2 = array(
'appId' => $config['appid'],
'nonceStr' => $nonceStr,
'package' => "prepay_id=$prepay_id",
'signType' => 'MD5',
'timeStamp' => $time
);
$paySign = self::getSign($arr_sign2);
return json_encode([
'timeStamp' => strval($time),
'nonceStr' => $nonceStr,
'package' => "prepay_id=$prepay_id",
'paySign' => $paySign
]);
}
public static function curl_post($url,$data){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
//获取16为随机字符串
public static function getNonceStr(){
$charts = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz0123456789";
$max = strlen($charts);
$noncestr = "";
for($i = 0; $i < 16; $i++)
{
$noncestr .= $charts[mt_rand(0, $max-1)];
}
return $noncestr;
}
//获取签名
public static function getSign($arr){
//排序处理,微信文档要求必须参数名ASCII码从小到大排序
ksort($arr);
$stringA = "";
foreach($arr as $key => $val){
$stringA .= "$key=$val&";
}
$stringSignTemp = $stringA."key=$config['api_key']";
$sign = strtoupper(md5($stringSignTemp));
return $sign;
}
//生成交易订单号 时间+随机六位数,例20180801121212097654
public static function getTradeNum(){
$num = "0123456789";
$left_num = "";
for($i=0;$i<6;$i++){
$left_num .= $num[mt_rand(0,9)];
}
return date("YmdHis",time()).$left_num;
}
//array2xml
public static function array2xml($arr){
if(!is_array($arr) || count($arr) <= 0){
return false;
}
$xml = "<xml>";
foreach ($arr as $key=>$val){
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
//xml2array
public static function xml2array($xml){
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
}
在控制器里调用这个类就可以实现支付了
//支付处理
public function actionPay(){
$get = Yii::$app->request->get();
$openid = $get['openid'];
$fee = $get['hongbao'];
$ip = Yii::$app->request->userIP;
$res = W下pay::uniorder($openid, $fee, $ip);
return $res;
}
以上就是今天的主要内容了,支付类如有问题可以和我联系。