1. 那一抹淡淡的忧伤—–微信开发基础
2. 用纯js是不可能用纯js了,这辈子都不用纯js了 —– 微信JSSDK开发以及问题解答
3. 要你命3000 —— 微信支付开发系列问题解决
为什么要开发微信和微信开发的优势我就不用多说了吧。微信支付的方式分好几种:
1.扫码支付
2.公众号支付
3.APP支付
不管是那种支付方式,都要用到统一下单这个接口,而一般大多数人都会卡在预支付id没有拿到这一步,今天就主要分析预支付id的获取和问题解决
如果不知道怎么配置,请看这里
生成商户订单
先要根据自己的业务逻辑生成自己可读的商户订单号,一般推荐年月日+随机数+用户uid
$order_no = date('YmdHis').rand(1000,9999).$uid;
使用微信统一下单接口,获得微信的预支付信息,对于统一下单接口的详细信息可以看这里
第一步:
我们先实例化微信统一下单接口的类,这个类在微信支付V3demo里有,当然在这里我将微信demo类库再次封装加入命名空间更好的适应Thinkphp。
UnifiedOrder_pub类:
namespace Org\Weixinpay;
use Org\Weixinpay\Wxpay_client_pub;
use Org\Weixinpay\WxPayConf_pub;
use Org\Weixinpay\SDKRuntimeException;
/**
* 统一支付接口类
*/
class UnifiedOrder_pub extends Wxpay_client_pub
{
function __construct($appid,$mchid,$key,$appsecret)
{
Common_util_pub::__construct($appid,$mchid,$key,$appsecret);
//设置接口链接
$this->url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//设置curl超时时间
$this->curl_timeout = 60;
}
/**
* 生成接口参数xml
*/
function createXml()
{
try
{
//检测必填参数
if($this->parameters["out_trade_no"] == null)
{
throw new SDKRuntimeException("缺少统一支付接口必填参数out_trade_no!"."
");
}elseif($this->parameters["body"] == null){
throw new SDKRuntimeException("缺少统一支付接口必填参数body!"."
");
}elseif ($this->parameters["total_fee"] == null ) {
throw new SDKRuntimeException("缺少统一支付接口必填参数total_fee!"."
");
}elseif ($this->parameters["notify_url"] == null) {
throw new SDKRuntimeException("缺少统一支付接口必填参数notify_url!"."
");
}elseif ($this->parameters["trade_type"] == null) {
throw new SDKRuntimeException("缺少统一支付接口必填参数trade_type!"."
");
}elseif ($this->parameters["trade_type"] == "JSAPI" &&
$this->parameters["openid"] == NULL){
throw new SDKRuntimeException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"."
");
}
$this->parameters["appid"] = $this->appid;//公众账号ID
$this->parameters["mch_id"] = $this->mchid;//商户号
//$this->parameters["sub_mch_id"] = "1xxxxxxx2";//子商户号
$this->parameters["spbill_create_ip"] = get_client_ip();//终端ip
$this->parameters["nonce_str"] = $this->createNoncestr();//随机字符串
$this->parameters["sign"] = $this->getSign($this->parameters);//签名
return $this->arrayToXml($this->parameters);
}catch (SDKRuntimeException $e)
{
return array('return_code'=>'FAIL','return_msg'=>$e->errorMessage());
}
}
/**
* 获取prepay_id
*/
function getPrepayId()
{
$this->postXml();
$this->result = $this->xmlToArray($this->response);
return $this->result;
}
}
我们实例化UnifiedOrder_pub,并依此传入参数,$appid,$mchid,$key,$appsecret
//appid 商家appid
//mchid 商家商户号
//key 商家支付秘钥
//appsecret JSAPI获准码
//调用统一下单
$unifiedOrder = new UnifiedOrder_pub($this->config['pay_weixin_appid'],$this->config['pay_weixin_mchid'],$this->config['pay_weixin_key'],$this->config['pay_weixin_appsecret']);
waring:在第一步里面会出的错误就是你的四个参数没有按顺序给对,记住这里面的参数一定要按顺序给,并且你要检查你的四个参数是否是有效的没有过期
在第一步出错的同学都不能吊起微信支付的样式,即下图:
但是如果你写入了调试js的话可以看见具体错误,这里就不提调试js了。
第二步:向统一下单接口中添加所需参数
$unifiedOrder->setParameter("openid",$this->user_info['openid']);//用户微信唯一标识
$unifiedOrder->setParameter("body",$this->order_info['order_name']);//商品描述
$unifiedOrder->setParameter("out_trade_no",$order_no);//商户订单号
$unifiedOrder->setParameter("total_fee",floatval($pay_money*100));//总金额
$unifiedOrder->setParameter("notify_url",$notice_url);//通知地址
$unifiedOrder->setParameter("trade_type","JSAPI");//交易类型
warning: 在第二步中,尤其要注意的就这个通知地址的格式,通知地址一定不能带任何参数的地址,包括你是pathinfo模式也好,只能以www.xxxxx.com/index.php这种模式结尾。
www.xxx.com/index.php?a=index,www.xxx.com/index.php/admin/index 这样的写法全部是错的。
第三步:获取预支付信息
将上述内容提交给接口,正确可返回预支付ID
$prepay_result = $unifiedOrder->getPrepayId();
如果错误,我们可以打印来查看是什么错误
var_dump($prepay_result);
$prepay_result['return_code'] == 'FAIL'//标志支付失败
$prepay_result['return_msg']//这个角标中有具体错误信息打印看看!
//缺少统一支付接口必填参数out_trade_no!
//缺少统一支付接口必填参数body
//缺少统一支付接口必填参数total_fee!
//缺少统一支付接口必填参数notify_url!
//...等等一些的错误提示,大家可以打印出来看看,然后对照着修改
当我们已经拿到预支付ID的时候,那么支付准备已经完成
第一步:在前台文件中我们使用注册支付JSAPI
//调起支付必备参数准备
function onBridgeReady(msg_json){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":msg_json.appId, //公众号名称,由商户传入
"timeStamp":msg_json.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr":msg_json.nonceStr, //随机串
"package":msg_json.package,
"signType":msg_json.signType, //微信签名方式:
"paySign":msg_json.paySign //微信签名
},
function(res){
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
check_pay_is_ture_ok(); //检测微信支付状态
}else{
}
}
);
}
第二步:支付js准备绑定事件(这里就举例按钮)
$('#button_pay_now').on('click',function(){
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
}else{
onBridgeReady(msg_json);
}
});
到这里我们就可以看到调起微信支付的JS效果了
微信坑就在你很好的完成以上步骤也不能支付,总会报错,在这里我就把我曾经遇到的错误写下来,与大家一起探讨
1.缺少统一支付接口必填参数total_fee!
这个错造成的原因:
q:你没有传递参数total_fee a:检查是否传递参数,最好一步步打印到日志中查看
q:total_fee 参数格式错误 a:参数的单位是分,也就是一元钱的话就是100,所以建议最后处理的时候都要处理为分,建议最后用floatval处理下
2.缺少统一支付接口必填参数notify_url!
这个错造成的原因:
q:你没有传递参数notify_url a:检查是否传递参数,最好一步步打印到日志中查看
q:notify_url 参数格式错误 a:通知地址一定不能带任何参数的地址,包括你是pathinfo模式也好,只能以www.xxxxx.com/index.php这种模式结尾
3.签名错误
这个错造成的原因:
1.你的四个参数的错误,尤其注意key这个参数,如果你的key是大小写混合的话,一定要在签名前把其转化为统一的大写形式
2.签名中的APPID 和appsecret
appid和商户号
不匹配
3.过期的key,可以支付的公众号可是要一年过期一次,相应的key每年都会有变化。