各位好,以下教程适合初次接触微信支付的小白,这是一个小白都能看懂,并且立即复制就能用的demo,本文从鹅厂复杂难懂的sdk中剥离解析,以几乎原生的方式呈现给你一份微信支付大餐。当然这只是微信支付其中的一种,但是所有鹅厂提供的微信支付,套路都是一样,比如电脑端的扫码支付,都是一个套路。大家看了这篇文章就知道微信支付是怎么一回事了。基本流程是这样的:
步骤1:用户选择微信支付。例如:
步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。
步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后返回json字符串。
步骤4:商户公众号调起微信支付。
第一步:前端代码:
前端使用微信自定义的一个方法:WeixinJSBridge.invoke(),不需要额外引用任何第三方js,这个函数只在微信中生效,可以引用微信专用js:http://res.wx.qq.com/open/js/jweixin-1.4.0.js ,可以使用web开发者工具查看效果,网页中会报错。这里面的几个参数需要写正确,后面用YII写一个php的接口传给前端。
<div style="text-align:center;size:30px;">
<input type="button" style="width:200px;height:80px;" value="微信支付" onclick="callpay()">
</div>
<script type="text/javascript">
function callpay(){
WeixinJSBridge.invoke('getBrandWCPayRequest',{
"appId":"公众号appID",
"timeStamp":"1564389542",
"nonceStr":"dBMPdafhPvospBoRPbSZcIobiLncQdya",
"package":"prepay_id=wx291639019757571e2762612e1533749100",
"signType" : "MD5",
"paySign":"78CB396C8FE94FD3F0C51AE8BB53F326"
},function(res){
WeixinJSBridge.log(res.err_msg);
if(res.err_msg == "get_brand_wcpay_request:ok"){
alert("微信支付成功!");
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
alert("用户取消支付!");
}else{
alert("支付失败!");
}
})
}
</script>
第二步:后端PHP代码
先调用统一下单接口获取必要参数。Yii接口写的,只需要调用第一个函数$this->actionTestwxpay();其他函数是该函数的引用。
大家可以参考微信支付之JSAPI支付SDK与DEMO ,这里面写的超级详细的。下载地址:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
但是现在我写的是一个小白都能看懂的demo。复制代码马上能出效果的demo。
//统一下单
public function actionTestwxpay(){
$post = [];
$post['appid'] = $appid = '';//重要参数
$post['body'] = $body = 'JSAPI支付测试'; //比如说会员充值,是一个签名,随便定义
$post['mch_id'] = $mch_id = '1424126202';//商户ID ,重要参数 ,跟appid一样是最重要的参数之一,以后别人给你打钱都在这里存着
$post['nonce_str'] = $nonce_str = $this->tesfsfsd();//随机字符串 ,随便定义
$post['notify_url'] = $notify_url = 'http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php'; //回调地址,随便写
$post['openid'] = $openid = 'oRG0ZxPPF0fbH1KCmMV5goJ69W8I';//明良的openid ,重要参数之三,不能错,自己去后台找,关注列表中有
$post['out_trade_no'] = $out_trade_no = time();//商户订单号,随便定义
$post['spbill_create_ip'] = $spbill_create_ip = '123.12.12.123';//服务器的ip,随便定义
$post['total_fee'] = $total_fee = '10000';//支付金额,最低为一分钱,即0.01元, 必须是整数,这里设置100块,你也可以设置1,显示为0.01元
$post['trade_type'] = $trade_type = 'JSAPI';//交易类型,默认必写
$sign = $this->sign($post);//签名,以上字段的顺序不能乱
$post_xml = '<xml>
<appid>' . $appid . '</appid>
<body>' . $body . '</body>
<mch_id>' . $mch_id . '</mch_id>
<nonce_str>' . $nonce_str . '</nonce_str>
<notify_url>' . $notify_url . '</notify_url>
<openid>' . $openid . '</openid>
<out_trade_no>' . $out_trade_no . '</out_trade_no>
<spbill_create_ip>' . $spbill_create_ip . '</spbill_create_ip>
<total_fee>' . $total_fee . '</total_fee>
<trade_type>' . $trade_type . '</trade_type>
<sign>' . $sign . '</sign>
</xml> ';
//统一接口prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$xml = $this->http_request_json($url, $post_xml);
$array = $this->xml($xml);//全要大写
if ($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS') {
$time = time();
$tmp = [];//临时数组用于签名
$tmp['appId'] = $appid;
$tmp['nonceStr'] = $nonce_str;
$tmp['package'] = 'prepay_id=' . $array['PREPAY_ID'];
$tmp['signType'] = 'MD5';
$tmp['timeStamp'] = "$time";
$data['state'] = 1;
$data['timeStamp'] = "$time";//时间戳
$data['nonceStr'] = $nonce_str;//随机字符串
$data['signType'] = 'MD5';//签名算法,暂支持 MD5
$data['package'] = 'prepay_id=' . $array['PREPAY_ID'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
$data['paySign'] = $this->sign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;
$data['out_trade_no'] = $out_trade_no;
} else {
$data['state'] = 0;
$data['text'] = "错误";
$data['RETURN_CODE'] = $array['RETURN_CODE'];
$data['RETURN_MSG'] = $array['RETURN_MSG'];
}
return json_encode($data); //小程序或公众号需要的数据 返回前端
}
//随机字符串
public function tesfsfsd(){
$result = '';
$str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';//自己随便写
for ($i=0;$i<32;$i++){
$result .= $str[rand(0,48)];
}
return $result;
}
/**
* 签名函数
*方法:
签名步骤一:按字典序排序参数
ksort($this->values);
$string = $this->ToUrlParams();
签名步骤二:在string后加入KEY
$string = $string . "&key=".WxPayConfig::KEY;
签名步骤三:MD5加密
$string = md5($string);
签名步骤四:所有字符转为大写
$result = strtoupper($string);
* @return string
*/
public function sign($data){
$stringA = '';
foreach ($data as $key=>$value){
if(!$value) continue;
if($stringA) $stringA .= '&'.$key."=".$value;
else $stringA = $key."=".$value;
}
$wx_key = 'xxxxxxxxxxxxxxxxxxx';//这个密匙请正确填写,自己在公众号后台找,会跟着你的appid在一起
$stringSignTemp = $stringA.'&key='.$wx_key;
return strtoupper(md5($stringSignTemp));
}
//curl请求
function http_request_json($url,$data = null,$headers=array()){
$curl = curl_init();
if( count($headers) >= 1 ){
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)){
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
//获取xml
private function xml($xml){
$p = xml_parser_create();
xml_parse_into_struct($p, $xml, $vals, $index);
xml_parser_free($p);
$data = "";
foreach ($index as $key=>$value) {
if($key == 'xml' || $key == 'XML') continue;
$tag = $vals[$value[0]]['tag'];
$value = $vals[$value[0]]['value'];
$data[$tag] = $value;
}
return $data;
}
这里PHP返回 的接口参数是这样的,用postman调试后显示的是一个json字符串:
{
"state": 1,
"timeStamp": "1564389542",
"nonceStr": "dBMPdafhPvospBoRPbSZcIobiLncQdya",
"signType": "MD5",
"package": "prepay_id=wx291639019757571e2762612e1533749100",
"paySign": "78CB396C8FE94FD3F0C51AE8BB53F326",
"out_trade_no": 1564389541
}
然后大家把这个字符串里面的参数复制到前端文件中,就可以正常调用微信支付了。
下面我用我的测试公众号(没有测试号的可以自己去申请一个测试号)去点击一下前端页面微信支付那个按钮,马上就出现了这样的一个界面:(如果没有出现这个界面,看下报了什么错,反馈给我,一般都是参数错了,或者签名不正确)
到这里基本就说明调用微信支付成功了。我这个是公众号的,小程序微信支付跟这个差不多,调用的函数是这个:
wx.requestPayment({
timeStamp: '1564371379',
nonceStr: 'JoTcEhgphkSAXPcpSqYFqKFUDMktGulc',
package: 'prepay_id=wx29113619598850b0682884011250194100',
signType: 'MD5',
paySign: '86BFA0E44B87FF783BB575F0B9FE584C',
success (res) { },
fail (res) { }
})
最后需要注明的一点是:在微信支付的后台里面,网址:https://pay.weixin.qq.com/index.php/extend/pay_setting
我们要设置一点
大家按要求设置一个微信支付授权的域名就行了。
有很多朋友会问,为什么会出现这样那样的错误,其实开发中遇到的错误一般会有很明显的提示,这个是微信返回给你的提示。
比如说:
签名错误,这个有很多原因,但是微信一般就是说签名错误,他不会具体到哪里,主要是参数错误或者没按照要求排序了。
第一,可能是商户密匙错误,在申请支付后系统会给予一个商户账号和密码,这个密码是单独不能跟app的密匙混淆。
第二,没有按照要求去签名,请注意微信支付中的两次签名。
第一次签名有10个参数,必须按字典顺序排序,然后把生成的签名当做一个参数传给xml
这11个参数中只有三个是重要的【
$appid // 这个不用说了,公众号ID。
$mch_id // 商户号,开通微信支付,这个就是V信给你的银行卡号
$openid //自己去公众号后台看下关注列表,一定要是自己的,谁支付就是谁的
】,其他都是随便写的。
//签名方法再次说明:
签名步骤一:按字典序排序参数
ksort($this->values);
$string = $this->ToUrlParams();
签名步骤二:在string后加入KEY
$string = $string . "&key=".WxPayConfig::KEY;
签名步骤三:MD5加密
$string = md5($string);
签名步骤四:所有字符转为大写
$result = strtoupper($string);
请注意两次签名都是用这个方法,其中的key=WxPayConfig::KEY是唯一的,一定不能错。
谢谢大家,希望各位能快速玩转微信支付。