忙碌的生活算是告一段落了,又可以抽出时间来拓展自己的能力了,前段时间几乎花了一个星期的时间,搞了一系列的支付,微信支付中的公众号支付、扫码支付、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的配置!