PHP微信支付統一下單

wx1234cn發表於2019-02-16

一、Model層,Wxpay.php

<?php
namespace appcommonmodel;
class Wxpay
{
    private $appid = `wxe8*****d4`;                            //微信公眾號appid
    private $secret = `37c4*******5f0`;                        //微信公眾號appsecret               
    private $mchid = `13******02`;                             //商家號
    private $key = `5363e******49e8`;                          //支付金鑰
    private $sslcert_path = `apiclient_cert.pem`;              //證照所在絕對路徑
    private $sslkey_path = `apiclient_key.pem`;                //證照所在絕對路徑
    
    public function __construct($appid = ``, $secret = ``, $mchid = ``, $key = ``)
    {
        if(!empty($appid))     $this->appid = $appid;
        if(!empty($secret))    $this->secret = $secret;
        if(!empty($mchid))     $this->mchid  = $mchid;
        if(!empty($key))       $this->key= $key;
    }
    /*
     * 微信內H5調起支付
     * @params string $openid : 微信使用者openid
     * @params string $out_trade_no : 商家生成的訂單號(唯一性)
     * @params int $total_fee : 支付金額,單位分
     * return array $ret : 返回支付時所需要的資料
     * */
    public function payForWeixin($openid,$out_trade_no,$total_fee,$attach=`微信支付`,$body=`微信支付`)
    {
        //支付資料
        $data[`openid`] = $openid;
        $data[`out_trade_no`] = $out_trade_no;
        $data[`total_fee`] = $total_fee*100;
        $data[`spbill_create_ip`] = $_SERVER["REMOTE_ADDR"];
        $data[`attach`] = $attach;
        $data[`body`] = $body;
        $data[`appid`] = $this->appid;
        $data[`mch_id`] = $this->mchid;
        $data[`nonce_str`] = random(12);
        $data[`trade_type`] = "JSAPI";
        $data[`notify_url`] = "http://****.com/home/wxpaynofiy/notify.html";

        $sign = $this->getParam($data);
        $dataXML = "<xml>
           <appid>".$data[`appid`]."</appid>
           <attach>".$data[`attach`]."</attach>
           <body>".$data[`body`]."</body>
           <mch_id>".$data[`mch_id`]."</mch_id>
           <nonce_str>".$data[`nonce_str`]."</nonce_str>
           <notify_url>".$data[`notify_url`]."</notify_url>
           <openid>".$data[`openid`]."</openid>
           <out_trade_no>".$data[`out_trade_no`]."</out_trade_no>
           <spbill_create_ip>".$data[`spbill_create_ip`]."</spbill_create_ip>
           <total_fee>".$data[`total_fee`]."</total_fee>
           <trade_type>".$data[`trade_type`]."</trade_type>
           <sign>".$sign."</sign>
        </xml>";
        $url = `https://api.mch.weixin.qq.com/pay/unifiedorder`;
        $result =  $this->https_post($url,$dataXML);
        $ret = $this->xmlToArray($result);
        
        if($ret[`return_code`] == `SUCCESS` && $ret[`return_msg`] == `OK`) {
            return array(
                `appId`     => $this->appid,
                `timeStamp` => time(),
                `nonceStr`  => $data[`nonce_str`],
                `package`   => `prepay_id=`.$ret[`prepay_id`],
                `signType`  => `MD5`,
                `paySign`   => $sign
            );
        } else {
            $this->errorLog("微信支付失敗,",$ret);
            return null;
        }
    }
     /*
     *   微信二維碼支付
     *   @params string $openid : 使用者的openid
     *   @params string $out_trade_no : 商戶訂單號
     *   @params number $total_fee : 訂單金額,單位分
     *   return string $code_url : 二維碼URL連結
     */
    public function payForQrcode($out_trade_no,$total_fee,$body="魔盒CMS",$attach="微信支付")
    {
        //支付資料
        $data[`out_trade_no`] = $out_trade_no;
        $data[`total_fee`] = $total_fee*100;
        $data[`spbill_create_ip`] = $_SERVER["REMOTE_ADDR"];
        $data[`attach`] = $attach;
        $data[`body`] = $body;
        $data[`appid`] = $this->appid;
        $data[`mch_id`] = $this->mchid;
        $data[`nonce_str`] = random(12);
        $data[`trade_type`] = "NATIVE";
        $data[`notify_url`] = "http://****.com/home/wxpaynofiy/notify.html";

        $sign = $this->getParam($data);
        $dataXML = "<xml>
           <appid>".$data[`appid`]."</appid>
           <attach>".$data[`attach`]."</attach>
           <body>".$data[`body`]."</body>
           <mch_id>".$data[`mch_id`]."</mch_id>
           <nonce_str>".$data[`nonce_str`]."</nonce_str>
           <notify_url>".$data[`notify_url`]."</notify_url>
           <out_trade_no>".$data[`out_trade_no`]."</out_trade_no>
           <spbill_create_ip>".$data[`spbill_create_ip`]."</spbill_create_ip>
           <total_fee>".$data[`total_fee`]."</total_fee>
           <trade_type>".$data[`trade_type`]."</trade_type>
           <sign>".$sign."</sign>
        </xml>";
        $url = `https://api.mch.weixin.qq.com/pay/unifiedorder`;
        $result =  $this->https_post($url,$dataXML);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`] == `SUCCESS` && $ret[`return_msg`] == `OK`) {
            return $ret[`code_url`];
        } else {
            $this->errorLog("獲取微信支付二維碼失敗,",$ret);
            return null;
        }
    }

    /*
     * 訂單查詢
     * @params string $transaction_id : 微信訂單號
     * @params string $out_trade_no : 商家訂單號(與微信訂單號二選一)
     * */
    public function findOrder($out_trade_no)
    {
        $data[`appid`] = $this->appid;
        $data[`mch_id`] = $this->mchid;
        $data[`nonce_str`] = random(12);
        $data[`out_trade_no`] = $out_trade_no;
        $sign = $this->getParam($data);
        $dataXML = "<xml>
            <appid>".$data[`appid`]."</appid>
            <mch_id>".$data[`mch_id`]."</mch_id>
            <nonce_str>".$data[`nonce_str`]."</nonce_str>
            <out_trade_no>".$data[`out_trade_no`]."</out_trade_no>
            <sign>".$sign."</sign>
         </xml>";
        $url = `https://api.mch.weixin.qq.com/pay/orderquery`;
        $result =  $this->https_post($url,$dataXML);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`] == `SUCCESS` && $ret[`return_msg`] == `OK`) {
            return $ret;
        } else {
            $this->errorLog("查詢微信支付訂單失敗,",$ret);
            return null;
        }
    }
    /*
    * 退款訂單查詢
    * @params string $transaction_id : 微信訂單號
    * @params string $out_trade_no : 商家訂單號(與微信訂單號二選一)
    * */
    public function findRefundOrder($out_trade_no)
    {
        $data[`appid`] = $this->appid;
        $data[`mch_id`] = $this->mchid;
        $data[`nonce_str`] = random(12);
        $data[`out_trade_no`] = $out_trade_no;
        $sign = $this->getParam($data);
        $dataXML = "<xml>
            <appid>".$data[`appid`]."</appid>
            <mch_id>".$data[`mch_id`]."</mch_id>
            <nonce_str>".$data[`nonce_str`]."</nonce_str>
            <out_trade_no>".$data[`out_trade_no`]."</out_trade_no>
            <sign>".$sign."</sign>
         </xml>";
        $url = `https://api.mch.weixin.qq.com/pay/refundquery`;
        $result =  $this->https_post($url,$dataXML);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`] == `SUCCESS` && $ret[`return_msg`] == `OK`) {
            return $ret;
        } else {
            $this->errorLog("查詢微信支付退款訂單失敗,",$ret);
            return $ret[`err_code_des`];
        }
    }
    /*
     * 申請退款
     * @params string $out_trade_no : 商戶訂單號
     * @params string $out_refund_no : 商戶退款單號
     * @params int $total_fee : 訂單金額
     * @params int $refund_fee : 退款金額
     * @params string $refund_desc : 退款原因
     * */
    public function refund($out_trade_no,$out_refund_no,$total_fee,$refund_fee,$refund_desc=`退款`)
    {
        $data[`appid`]  = $this->appid;
        $data[`mch_id`] = $this->mchid;
        $data[`nonce_str`] = random(12);
        $data[`out_trade_no`] = $out_trade_no;
        $data[`out_refund_no`] = $out_refund_no;
        $data[`total_fee`] = $total_fee*100;
        $data[`refund_fee`] = $refund_fee*100;
        $data[`refund_desc`] = $refund_desc;
        $data[`notify_url`] = "http://*****.com/home/wxpaynofiy/refund.html";
        $sign = $this->getParam($data);
        $dataXML = "<xml>
           <appid>".$data[`appid`]."</appid>
           <mch_id>".$data[`mch_id`]."</mch_id>
           <nonce_str>".$data[`nonce_str`]."</nonce_str>
           <out_trade_no>".$data[`out_trade_no`]."</out_trade_no>
           <out_refund_no>".$data[`out_refund_no`]."</out_refund_no>
           <total_fee>".$data[`total_fee`]."</total_fee>
           <refund_fee>".$data[`refund_fee`]."</refund_fee>
           <refund_desc>".$data[`refund_desc`]."</refund_desc>
           <notify_url>".$data[`notify_url`]."</notify_url>
           <sign>".$sign."</sign>
        </xml>";
        $url = `https://api.mch.weixin.qq.com/secapi/pay/refund`;
        $result =  $this->https_post($url,$dataXML,true);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`] == `SUCCESS` && $ret[`return_msg`] == `OK`) {
            return $ret;
        } else {
            $this->errorLog("微信退款失敗,",$ret);
            return null;
        }
    }
    /*
     * 企業付款至使用者零錢
     * @params string $openid : 使用者openid
     * @params int $total_fee : 付款金額,單位分
     * @params string $out_trade_no : 商家訂單號
     * @params string $username : 微信使用者名稱稱(注意微信暱稱若為空時支付會出錯)
     * @params string $desc : 付款描述
     * @params string $check_name : 是否檢測使用者名稱
     * */
    public function payForUser($openid,$total_fee,$out_trade_no,$username=`魔盒CMS`,$desc=`魔盒CMS付款給使用者`,$check_name=`NO_CHECK`)
    {
        $data[`amount`] = $total_fee*100;
        $data[`check_name`] = $check_name;
        $data[`desc`] = $desc;
        $data[`mch_appid`] = $this->appid;
        $data[`mchid`] = $this->mchid;
        $data[`nonce_str`] = random(12);
        $data[`openid`] = $openid;
        $data[`partner_trade_no`] = $out_trade_no;
        $data[`re_user_name`] = $username;
        $data[`spbill_create_ip`] = $_SERVER["REMOTE_ADDR"];
        $sign = $this->getParam($data);

        $dataXML="<xml>
        <mch_appid>".$data[`mch_appid`]."</mch_appid>
        <mchid>".$data[`mchid`]."</mchid>
        <nonce_str>".$data[`nonce_str`]."</nonce_str>
        <partner_trade_no>".$data[`partner_trade_no`]."</partner_trade_no>
        <openid>".$data[`openid`]."</openid>
        <check_name>".$data[`check_name`]."</check_name>
        <re_user_name>".$data[`re_user_name`]."</re_user_name>
        <amount>".$data[`amount`]."</amount>
        <desc>".$data[`desc`]."</desc>
        <spbill_create_ip>".$data[`spbill_create_ip`]."</spbill_create_ip>
        <sign>".$sign."</sign>
        </xml>";

        $url = `https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers`;
        $result =  $this->https_post($url,$dataXML,true);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`]==`SUCCESS` && $ret[`result_code`] == `SUCCESS`)
        {
            //支付成功返回商戶訂單號、微信訂單號、微信支付成功時間
            $result[`partner_trade_no`] = $ret[`partner_trade_no`];
            $result[`payment_no`] = $ret[`payment_no`];
            $result[`payment_time`] = $ret[`payment_time`];
            return $ret;
        } else {
           $this->errorLog(`付款給使用者失敗`,$ret);
           return null;
        }
    }
     /*
     * 普通紅包
     * @params string $out_trade_no : 商家訂單號
     * @params string $openid : 接收紅包使用者的openid
     * @params int $total_fee : 紅包金額,單位分
     * @params int $total_num : 紅包發放總人數
     * @params string $wishing : 紅包祝福語
     * @params string $act_name : 活動名稱
     * @params string $remark : 備註
     * @params string $scene_id :場景值ID。發放紅包使用場景,紅包金額大於200或者小於1元時必傳。PRODUCT_1:商品促銷、PRODUCT_2:抽獎、PRODUCT_3:虛擬物品兌獎 、PRODUCT_4:企業內部福利、PRODUCT_5:渠道分潤、PRODUCT_6:保險回饋、PRODUCT_7:彩票派獎、PRODUCT_8:稅務刮獎
     * */
    public function redPack($openid,$total_fee,$out_trade_no,$total_num = 1,$wishing = `感謝您光臨***平臺進行購物`,$act_name=`***購物發紅包`,$remark = `購物領紅包`)
    {
        $data[`mch_billno`]     = $out_trade_no;
        $data[`mch_id`]         = $this->mchid;
        $data[`wxappid`]        = $this->appid;
        $data[`send_name`]      = `傳送紅包者的名稱`;
        $data[`re_openid`]      = $openid;
        $data[`total_amount`]   = $total_fee;
        $data[`total_num`]      = $total_num;
        $data[`wishing`]        = $wishing;
        $data[`client_ip`]      = $_SERVER["REMOTE_ADDR"];
        $data[`act_name`]       = $act_name;
        $data[`remark`]         = $remark;
        $data[`nonce_str`]      = random(12);
        $sign = $this->getParam($data);

        $dataXML="<xml>
        <sign>".$sign."</sign>
        <mch_billno>".$data[`mch_billno`]."</mch_billno>
        <mch_id>".$data[`mch_id`]."</mch_id>
        <wxappid>".$data[`wxappid`]."</wxappid>
        <send_name>".$data[`send_name`]."</send_name>
        <re_openid>".$data[`re_openid`]."</re_openid>
        <total_amount>".$data[`total_amount`]."</total_amount>
        <total_num>".$data[`total_num`]."</total_num>
        <wishing>".$data[`wishing`]."</wishing>
        <client_ip>".$data[`client_ip`]."</client_ip>
        <act_name>".$data[`act_name`]."</act_name>
        <remark>".$data[`remark`]."</remark>
        <nonce_str>".$data[`nonce_str`]."</nonce_str>
        </xml>";

        $url = `https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack`;
        $result =  $this->https_post($url,$dataXML,true);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`]==`SUCCESS` && $ret[`result_code`] == `SUCCESS`)
        {
            return $ret;
        } else {
            $this->errorLog(`發放普通紅包失敗`,$ret);
            return $ret[`err_code_des`];
        }

    }

    /*
    * 裂變紅包:一次可以發放一組紅包。首先領取的使用者為種子使用者,種子使用者領取一組紅包當中的一個,並可以通過社交分享將剩下的紅包給其他使用者。
     * 裂變紅包充分利用了人際傳播的優勢。
    * @params string $out_trade_no : 商家訂單號
    * @params string $openid : 接收紅包使用者的openid
    * @params int $total_fee : 紅包金額,單位分
    * @params int $total_num : 紅包發放總人數
    * @params string $wishing : 紅包祝福語
    * @params string $act_name : 活動名稱
    * @params string $remark : 備註
    * @params string $scene_id :場景值ID。發放紅包使用場景,紅包金額大於200或者小於1元時必傳。PRODUCT_1:商品促銷、PRODUCT_2:抽獎、PRODUCT_3:虛擬物品兌獎 、PRODUCT_4:企業內部福利、PRODUCT_5:渠道分潤、PRODUCT_6:保險回饋、PRODUCT_7:彩票派獎、PRODUCT_8:稅務刮獎
    * */
    public function redPackGroup($openid,$total_fee,$out_trade_no,$total_num,$wishing = `感謝您光臨***進行購物`,$act_name=`**購物發紅包`,$remark = `購物領紅包`)
    {
        $data[`mch_billno`]     = $out_trade_no;
        $data[`mch_id`]         = $this->mchid;
        $data[`wxappid`]        = $this->appid;
        $data[`send_name`]      = `傳送紅包者的名稱`;
        $data[`re_openid`]      = $openid;
        $data[`total_amount`]   = $total_fee;
        $data[`amt_type`]       = `ALL_RAND`;   //ALL_RAND—全部隨機,商戶指定總金額和紅包發放總人數,由微信支付隨機計算出各紅包金額
        $data[`total_num`]      = $total_num;
        $data[`wishing`]        = $wishing;
        $data[`client_ip`]      = $_SERVER["REMOTE_ADDR"];
        $data[`act_name`]       = $act_name;
        $data[`remark`]         = $remark;
        $data[`nonce_str`]      = random(12);
        $sign = $this->getParam($data);

        $dataXML="<xml>
        <sign>".$sign."</sign>
        <mch_billno>".$data[`mch_billno`]."</mch_billno>
        <mch_id>".$data[`mch_id`]."</mch_id>
        <wxappid>".$data[`wxappid`]."</wxappid>
        <send_name>".$data[`send_name`]."</send_name>
        <re_openid>".$data[`re_openid`]."</re_openid>
        <total_amount>".$data[`total_amount`]."</total_amount>
        <amt_type>".$data[`amt_type`]."</amt_type> 
        <total_num>".$data[`total_num`]."</total_num>
        <wishing>".$data[`wishing`]."</wishing>
        <client_ip>".$data[`client_ip`]."</client_ip>
        <act_name>".$data[`act_name`]."</act_name>
        <remark>".$data[`remark`]."</remark>
        <nonce_str>".$data[`nonce_str`]."</nonce_str>
        </xml>";

        $url = `https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack`;
        $result =  $this->https_post($url,$dataXML,true);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`]==`SUCCESS` && $ret[`result_code`] == `SUCCESS`)
        {
            return $ret;
        } else {
            $this->errorLog(`發放裂變紅包失敗`,$ret);
            return $ret[`err_code_des`];
        }

    }
    /*
     * 查詢紅包記錄
     * @params string $out_trade_no : 商家訂單號
     * */
    public function findRedPack($out_trade_no)
    {
        $data[`mch_billno`]     = $out_trade_no;
        $data[`mch_id`]         = $this->mchid;
        $data[`appid`]          = $this->appid;
        $data[`bill_type`]      = `MCHT`;           //MCHT:通過商戶訂單號獲取紅包資訊。
        $data[`nonce_str`]      = random(12);
        $sign = $this->getParam($data);

        $dataXML="<xml>
        <sign>".$sign."</sign>
        <mch_billno>".$data[`mch_billno`]."</mch_billno>
        <mch_id>".$data[`mch_id`]."</mch_id>
        <appid>".$data[`appid`]."</appid>
        <bill_type>".$data[`bill_type`]."</bill_type> 
        <nonce_str>".$data[`nonce_str`]."</nonce_str>
        </xml>";

        $url = `https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo`;
        $result =  $this->https_post($url,$dataXML,true);
        $ret = $this->xmlToArray($result);
        if($ret[`return_code`]==`SUCCESS` && $ret[`result_code`] == `SUCCESS`)
        {
            return $ret;
        } else {
            $this->errorLog(`查詢紅包記錄失敗`,$ret);
            return $ret[`err_code_des`];
        }
    }
    /*
     * 獲取使用者微信的OPENID
     * */
    public function openid($c=false)
    {
        if($_GET[`state`]!="zgm"){
            $t = $c ? "snsapi_userinfo" : "snsapi_base";
            $url=urlencode(get_url());
            $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$this->appid."&redirect_uri=".$url."&response_type=code&scope=".$t."&state=zgm#wechat_redirect";
            echo "<html><script>window.location.href=`$url`;</script></html>";
            exit;
        }
        if($_GET[`code`]){
            $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appid."&secret=".$this->secret."&code=".$_GET[`code`]."&grant_type=authorization_code";
            $wx_db=json_decode($this->https_get($url));
            if($c){
                $url_2="https://api.weixin.qq.com/sns/userinfo?access_token=".$wx_db->access_token."&openid=".$wx_db->openid."&lang=zh_CN";
                $db=json_decode($this->https_get($url_2));
                return $db;
            }else{
                return $wx_db->openid;
            }
        }
    }
    /*
    * 發起網路GET請求
    * @params string $url : URL連結
    */
    private function https_get($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE); 
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE); 
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE); 
        curl_setopt($curl, CURLOPT_HEADER, FALSE) ; 
        curl_setopt($curl, CURLOPT_TIMEOUT,60);   
        if (curl_errno($curl)) {
            return `Errno`.curl_error($curl);
        }
        else{$result=curl_exec($curl);}
        curl_close($curl);
        return $result;
    }
    //對引數排序,生成MD5加密簽名
    private function getParam($paramArray, $isencode=false)
    {
        $paramStr = ``;
        ksort($paramArray);
        $i = 0;
        foreach ($paramArray as $key => $value)
        {
            if ($key == `Signature`){
                continue;
            }
            if ($i == 0){
                $paramStr .= ``;
            }else{
                $paramStr .= `&`;
            }
            $paramStr .= $key . `=` . ($isencode?urlencode($value):$value);
            ++$i;
        }
        $stringSignTemp=$paramStr."&key=".$this->key;
        $sign=strtoupper(md5($stringSignTemp));
        return $sign;
    }
    //POST提交資料
    private function https_post($url,$data,$ssl = false)
    {
        $ch = curl_init ();
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
        if($ssl) {
            curl_setopt ( $ch,CURLOPT_SSLCERT,$this->sslcert_path);
            curl_setopt ( $ch,CURLOPT_SSLKEY,$this->sslkey_path);
        }
        curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
        curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
        $result = curl_exec($ch);
        if (curl_errno($ch)) {
            return `Errno: `.curl_error($ch);
        }
        curl_close($ch);
        return $result;
    }
    /*
    * XML轉array
    * @params xml $xml : xml 資料
    * return array $data : 轉義後的array陣列
    */
    private function xmlToArray($xml)
    {
        libxml_disable_entity_loader(true);
        $xmlstring = simplexml_load_string($xml, `SimpleXMLElement`, LIBXML_NOCDATA);
        $val = json_decode(json_encode($xmlstring),true);
        return $val;
    }
    /*
    * 記錄日誌
    * @params string $msg : 提示語句
    * @params array $ret : 錯誤結果
    */
    private function errorLog($msg,$ret)
    {
        file_put_contents(ROOT_PATH . `runtime/error/wxpay.log`, "[" . date(`Y-m-d H:i:s`) . "] ".$msg."," .json_encode($ret).PHP_EOL, FILE_APPEND);
    }
}

二、Controller層,Test.php

<?php
namespace appgoodscontroller;
use appcommonmodelWxpay;
class Test
{
    /*
    * 呼叫微信支付
    * 一、獲取微信使用者的openid; 
    * 二、呼叫微信支付介面
    * 三、生成H5中使用的簽名內容
    */
    public function wx()
    {
        $wxpay = new Wxpay();
        $openid = $wxpay->openid();
        $pay = $wxpay->payForWeixin($openid,date(`YmdHis`).rand(1,5),`0.1`);
        $paySign =strtoupper(MD5(`appId=`.$pay[`appId`].`&nonceStr=`.$pay[`nonceStr`].`&package=`.$pay[`package`].`&signType=MD5&timeStamp=`.$pay[`timeStamp`].`&key=536*****9e8`));
         $h5 = array(
            `appId`     => $pay[`appId`],
            `timeStamp` => $pay[`timeStamp`],
            `nonceStr`  => $pay[`nonceStr`],
            `package`   => $pay[`package`],
            `signType`  => $pay[`signType`],
            `paySign`   => $paySign
        );
        $this->assign(`wxpay`,$h5);
        return view();
    }
}

三、HTML中呼叫微信支付,wx.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>訂單示例</title>
</head>
<body>

<script type="text/javascript">
    function onBridgeReady(){
        WeixinJSBridge.invoke(
            `getBrandWCPayRequest`, {
                "appId":"{$wxpay[`appId`]}",
                "timeStamp":"{$wxpay[`timeStamp`]}",
                "nonceStr":"{$wxpay[`nonceStr`]}",
                "package":"{$wxpay[`package`]}",
                "signType":"MD5",
                "paySign":"{$wxpay[`paySign`]}"
            },
            function(res){
                if(res.err_msg == "get_brand_wcpay_request:ok" ){
                    // 使用以上方式判斷前端返回,微信團隊鄭重提示:
                    //res.err_msg將在使用者支付成功後返回ok,但並不保證它絕對可靠。
                }
            });
    }
    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();
    }
</script>
</body>
</html>

四、接收微信支付返回結果,支付時設定的notify_url值,確保此連結外網能訪問。wxpaynofiy.php

<?php
namespace apphomecontroller;
class Wxpaynofiy
{
     public function notify()
    {
        $xml = isset($GLOBALS["HTTP_RAW_POST_DATA"]) ? $GLOBALS[`HTTP_RAW_POST_DATA`] : file_get_contents("php://input");
        $data = xmlToArray($xml);
        if($data[`return_code`] == `SUCCESS` && $data[`result_code`] == `SUCCESS`){
            if($this->checkSign($data)) {
                $transaction_id = $data[`transaction_id`];      //微信支付訂單號
                $out_trade_no   = $data[`out_trade_no`];        //商家訂單號
                $this->errorLog(`微信支付返回結果,微信支付訂單號:`.$transaction_id.`,商家訂單號:`.$out_trade_no,[]);

            } else {
                $this->errorLog(`微信支付返回結果簽名驗證失敗`,$data);
            }
        } else {
            $this->errorLog(`微信支付返回結果`,$data);
        }
        echo `<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>`;
    }

    /*
     * 驗證簽名
     * @params array $result : 微信支付成功返回的結果陣列
     * return bool $ret : 成功true,失敗false
     * */
    private function checkSign(array $data)
    {
        $str = ``;
        ksort($data);
        foreach ($data as $k => $v) {
            if($k != `sign`) $str .= $k.`=`.$v.`&`;
        }
        $temp = $str . `key=5363******49e8`;     //key:商戶支付金鑰
        $sign = strtoupper(md5($temp));
        return $sign == $data[`sign`] ? true : false;
    }

    private function errorLog($msg,$ret)
    {
        file_put_contents(ROOT_PATH . `runtime/error/wxpaynofiy.log`, "[" . date(`Y-m-d H:i:s`) . "] ".$msg."," .json_encode($ret).PHP_EOL, FILE_APPEND);
    }
}

五、常見問題

1、H5支付時出現“簽名錯誤”,需要注意的呼叫微信“統一下單”介面後返回pre_pay_id後,需要使用者再次進行簽名返回給HTML;
2、“支付目錄沒有授權”,進入微信商家管理後臺設定即可;

相關文章