忙碌的生活算是告一段落了,又可以抽出时间来拓展自己的能力了,前段时间几乎花了一个星期的时间,搞了一系列的支付,微信支付中的公众号支付、扫码支付、app支付服务器端;支付宝支付中的手机网页支付、app支付,在这里一一介绍下,先从微信公众号支付说起吧!
微信公众号支付,之前使用thinkphp的时候,已经搞过了,现在的项目都迁到yii2中来的,所以把之前的包直接复制过来的,不过途中也遇到了一些问题。
一、微信公共号后台设置
1.设置微信授权目录,这里可以设置3个,也可以设置测试目录,我这里设置链接是这样的:
http://www.xxx.cn/pay/index/
2.接口权限里的网页授权页的修改,这里改成www.xxx.cn 即可
3.微信api中wxpay.config.php的配置
二、下载微信的包文件,包文件中有个uri的bug,之前做tp的时候遇到的,现在也记不清是哪里了,之后会把包出来,大家可以参考。在yii2中,我把包统一放到了common下面,这是我的目录截图:
common/wxpay/lib下面的是微信的核心类库,一个不能少,cert是证书,extend下面的是我单独拆分出来的统一下单类和回调类。
控制器中方法就是pay/index,代码如下:
<?php namespace weixinh5\controllers; use common\models\Common; use common\models\Order; use common\models\Store; use yii\web\Controller; use yii; use common\lib\WxPay\WxPayApi; use common\lib\Wxpay\Extend\WxPay; use common\lib\Wxpay\Extend\PayNotify; use common\lib\AliPay\lib\AlipaySubmit; use common\lib\AliPay\lib\AlipayNotify; use common\lib\AliAppPay\lib\AlipayRsaSubmit; use common\lib\AliAppPay\lib\AlipayRsaNotify; use common\models\WxpayRecord; use common\models\Paylog; use common\models\Cashrecord; use yii\web\NotFoundHttpException; class PayController extends Controller { public function init() { parent::init(); $this->enableCsrfValidation = false; //这里一定要写,否则yii2会屏蔽掉微信返回的支付结果 } public function actionIndex($id) { //获取商铺信息 if (empty($id)) throw new \Exception('参数错误!'); $model = new Order(); $rs = $model->isPayResult($id); //判断是否支付 $store = new Store(); $storeInfo = $store->getFrontOne(['id'=>$rs['info']->storeid]); //1、获取openid $WxPay = new WxPay(); try { $openId = $WxPay->GetOpenid(); //②、统一下单 $input = new \WxPayUnifiedOrder(); $input->SetBody("小程府-" . $storeInfo->name); //商品详情 $input->SetOut_trade_no($id); $input->SetTotal_fee($rs['info']->yingshou * 100); //金额 $input->SetTime_start(date("YmdHis")); $input->SetTime_expire(date("YmdHis", time() + 600)); // $input->SetGoods_tag("test");//商品标记 $input->SetNotify_url("http://www.xxx.cn/pay/notify/") //回调地址 $input->SetTrade_type("JSAPI"); $input->SetOpenid($openId); $order = WxPayApi::unifiedOrder($input); $jsApiParameters = $WxPay->GetJsApiParameters($order); //获取共享收货地址js函数参数 $editAddress = $WxPay->GetEditAddressParameters(); return $this->renderAjax('index',[ 'ordersn'=>$id, 'yingshou'=>$rs['info']->yingshou, 'jsApiParameters'=>$jsApiParameters, 'editAddress'=>$editAddress, 'storename'=>$storeInfo->name ]); } catch (\Exception $e) { return $e->getMessage(); } } //这里是扫码支付,一起贴出了,本人使用了第二种扫码模式, public function actionNative($id) { if (empty($id)) throw new \Exception('参数错误!'); $model = new Order(); $rs = $model->isPayResult($id); //判断是否支付 $store = new Store(); $storeInfo = $store->getFrontOne(['id'=>$rs['info']->storeid]); //1、获取openid $WxPay = new WxPay(); $paySwift = Order::createOrderSn(); try { $input = new \WxPayUnifiedOrder(); $input->SetBody("小程府-" . $storeInfo->name); $input->SetAttach($id); //附加上订单号 $input->SetOut_trade_no($paySwift); //设置伪订单,防止微信提示商户订单重复 $input->SetTotal_fee($rs['info']->yingshou * 100); $input->SetTime_start(date("YmdHis")); $input->SetTime_expire(date("YmdHis", time() + 600)); $input->SetNotify_url("http://www.xxx.cn/pay/notify/"); $input->SetTrade_type("NATIVE"); $input->SetProduct_id($id); $result = $WxPay->GetPayUrl($input); $url2 = $result["code_url"]; return $this->renderAjax('native',[ 'ordersn'=>$id, 'url2'=>$url2 ]); } catch (\Exception $e) { return $e->getMessage(); } } Public function actionNotify() {//公众号的网页支付回调 //php7已经启用此方法,所以建议改成file_get_contents('php://input') // $rsv_data = $GLOBALS ['HTTP_RAW_POST_DATA']; //弃用 // $rsv_data = file_get_contents('php://input'); // 回调的信息是不能被打印出来的,所以只能存到web目录下,以文件的形式打开查看 // file_put_contents('1.php',"<?php\r\nreturn ".var_export($rsv_data,true)."?>"); $notify = new PayNotify(); $notify->Handle(false); }
注意:上面的注释信息都非常的重要,自己也是掉了很多坑,才发现的,尤其是init的关闭csrf验证,HTTP_RAW_POST_DATA 在php7中的弃用,微信核心包里有牵扯到的,一并修改成了php://input
上面中的扫码支付,其中一个很重要的功能就是,防止微信支付中的跨号支付,例如,个人微信公众号,绑定的链接为另一个服务号,就会出现不能跨号支付的问题,而扫码支付可以很好的解决!
三、统一下单调用的是common/lib/extend下面的wxpay.php,在这里生产签名,返回
四、微信公众号支付会有一个确定支付的授权页,这里我把代码贴出来:
<?php use yii\helpers\Html; use common\widgets\LinkPager; use yii\bootstrap\ActiveForm; use yii\grid\GridView; use yii\helpers\Url; ?> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"> <meta content="yes" name="apple-mobile-web-app-capable"> <meta content="black" name="apple-mobile-web-app-status-bar-style"> <meta content="telephone=no,email=no" name="format-detection"> <meta content="no" name="msapplication-tap-highlight"> <meta name="screen-orientation" content="portrait"> <meta name="x5-orientation"content="portrait"> <meta name="full-screen" content="yes"> <meta name="x5-fullscreen" content="true"> <meta name="browsermode" content="application"> <meta name="x5-page-mode" content="app"> <title>微信支付</title> <script type="text/javascript"> //调用微信JS api 支付 function jsApiCall() { var od = document.getElementById('od').value; WeixinJSBridge.invoke( 'getBrandWCPayRequest', <?php echo $jsApiParameters; ?>, function(res){ if(res.err_msg == "get_brand_wcpay_request:fail" ) { //如果出现不能跨号支付的错误,直接调用扫码支付 window.location.href = "http://www.xxx.cn/pay/native/"+od; }else if(res.err_msg == "get_brand_wcpay_request:ok" ) { //支付成功,点击右上角的完成后跳转的链接 window.location.href = "http://www.xxx.cn/sdfs/succeed?ordersn="+od; } } ); } function callpay() { if (typeof WeixinJSBridge == "undefined"){ if( document.addEventListener ){ document.addEventListener('WeixinJSBridgeReady', jsApiCall, false); }else if (document.attachEvent){ document.attachEvent('WeixinJSBridgeReady', jsApiCall); document.attachEvent('onWeixinJSBridgeReady', jsApiCall); } }else{ jsApiCall(); } } </script> </head> <body> <style type="text/css"> *{padding:0;margin:0;} body{background:#fafafa;} .message{border-top:1px solid #eaeaea;border-bottom:1px solid #eaeaea;background:#fff;padding:5px 0 5px 10px;} .message p{height:30px;line-height:30px;font-size:14px;color:#151515;} button{width:80%;height:35px;border:none;border-radius:50px;display:block;margin:20px auto 0;font-size:14px;color:#fff;background:#ff4524;} </style> <div class="message"> <p>店铺名称:小程府-<?= $storename ?></p> <p>金额:<?= $yingshou?>元</p> <input type="hidden" class='od' id="od" value="<?= $ordersn ?>" /> </div> <button type="submit" onClick="callpay()" />确认支付</button> </body> </html>
这里我也把扫码支付的页面贴出来:
<!DOCTYPE html> <?php use yii\helpers\Html; ?> <html lang="en"> <head> <meta charset="UTF-8"> <title>扫码支付</title> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport"> <?= Html::jsFile('@static/js/wx/jquery.js'); ?> </head> <body> <style type="text/css"> *{padding:0;margin:0;} #bg{opacity:0.5;background:#000;position:fixed;width:100%;height:100%;} #saoma{width:220px;position:fixed;top:50%;left:50%; transform:translate(-50%,-50%); -webkit-transform:translate(-50%,-50%); padding:15px;border:1px #dedede;background:#fff;border-radius:5px;-webkit-border-radius:5px;} #saoma .tips{font-size:12px;color:#494949;line-height:20px;} #saoma h2{font-size:18px;text-align:center;margin-bottom:8px;} #imge{width:220px;height:220px;margin:0 auto;} </style> <div id="bg"></div> <div id="saoma"> <h2>扫描支付</h2> <span id="imge"> <img alt="扫码支付" src="http://paysdk.weixin.qq.com/example/qrcode.php?data=<?php echo urlencode($url2);?>" style="width:220px;height:220px;"/> </span> <div class="tips">温馨提示:未认证的订阅号和个人公众号请长按图片,识别图中二维码付款</div> <input type="hidden" value="<?= $ordersn ?>" id="ordersn"> </div> <script type="text/javascript"> function se(){ var ordersn = $("#ordersn").val(); $.post('/pay/checkorder/'+ordersn,function(data){ var date = JSON.parse(data); if(date.status == 1){ window.location.href = "http://www.xxx.cn/sldf/succeed?ordersn="+ordersn; } }) } setInterval(se,3000); </script> </body> </html>
wxpay的包文件百度云链接: http://pan.baidu.com/s/1dFG5qmd 密码: xy4b 拿走不谢,保证可用,记得修改wxpay.config.php的配置!