TP3.2.3 接入銀聯支付


TP3.2.3 接入銀聯支付

    項目接入銀聯支付的過程, 在此記錄下,希望能幫助開發盆友平坑。

    銀聯SKD鏈接:https://open.unionpay.com/ajweb/product/newProDetail?proId=1&cataId=14

    首先我們先下載官方提供的SDK  ,下載好了解壓選擇版本 ,里面有PHP  java  .net  這里我們自然是選擇PHP版本的,接入前我們先配環境,它要我們PHP

  的版本 在5.3以上,並且需開啟環境的curl、openssl功能。

   然后就是它提供的測試證書了,默認在window系統是放在D:/certs ,意思是在你的電腦的D創建一個名為certs 的文件夾,然后將4個證書放進去,測試的名為

  acp_test_enc.cer  acp_test_middle.cer  acp_test_root.cer  acp_test_sign.pfx ,在創建一個名為logs文件夾D:/logs/  放支付生成的日志文件,linux中請

 修改成Linux中的路徑。

  如圖:

  

    你可以在assets文件夾中找到你要的證書,測試環境官方提供四個證書,生產環境官方提供三個,還個簽名證書就是后綴為.pfx 的需要你去你的銀聯那里申請

  下載對應的你還需要可以需要解簽名證書的密碼 和商戶號 , 這些后面都會提到的。

    在然后我們將名為SDK文件夾中的六個文件放到我們項目放到 ThinkPHP\Library\Vendor\Yunpay 的文件夾中

    

     寫邏輯代碼前你還得前配置好你的acp_sdk.ini 文件 ,文件里面都寫的很清楚,這里就不一一解釋了,這里是我的支付代碼

    

//銀聯充值操作
    public function pay()
    {
        header ( 'Content-type:text/html;charset=utf-8' );
        Vendor('Yunpay.acp_service');

        //前台通知地址
        $frontUrl = "http://".I("server.HTTP_HOST")."/Assets/rechargedetail";
        //后台通知地址
        $backUrl = "http://".I("server.HTTP_HOST");
        $params = array(
            //以下信息非特殊情況不需要改動
            'version' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->version,          //版本號
            'encoding' => 'utf-8',                                                              //編碼方式
            'txnType' => '01',                                                                  //交易類型
            'txnSubType' => '01',                                                              //交易子類
            'bizType' => '000201',                                                              //業務類型
            'frontUrl' =>  $frontUrl,                                                          //前台通知地址
            'backUrl' =>   $backUrl,                                                          //后台通知地址
            'signMethod' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->signMethod,    //簽名方法
            'channelType' => '08',                                                             //渠道類型,07-PC,08-手機
            'accessType' => '0',                                                                //接入類型
            'currencyCode' => '156',    
             // 超過超時時間調查詢接口應答origRespCode不是A6或者00的就可以判斷為失敗。
               'payTimeout' => date('YmdHis', strtotime('+15 minutes'))                         //訂單發送時間
        );
        $txnAmt = I('post.txnAmt');    //交易金額
        $orderId = I('post.orderId');  //商戶訂單號

        //加入商戶參數
        $params['txnAmt'] = $txnAmt*100;
        $params['merId'] = C('Yunpay.merId');    //商戶號
        $params['orderId'] = $orderId;
        $params['txnTime'] = date('YmdHis');

        //商品描述,可空
        $body = trim(I('post.WIDbody'));
        $ud = session('users.uid');
        $data = array(
                'uid'=>$ud,                                  //用戶id
                'win_code'=>$orderId,                     //商戶訂單號
                'winsubject'=>I('post.WIDsubject'),          //訂單名稱
                'wintotal_amount'=>$txnAmt,                //付款金額
                'winbody'=>I('post.WIDbody'),             //商品描述
                'state'=>'yl',                              //支付方式
                'status'=>'0',                              //是否支付
                'ordertime'=>time()                          //交易時間
            );
        M("pay_record")->add($data); // 保存交易信息
        \com\unionpay\acp\sdk\AcpService::sign ( $params );
        $uri = \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->frontTransUrl;
        $html_form = \com\unionpay\acp\sdk\AcpService::createAutoFormHtml( $params, $uri );
        echo $html_form;
    
    }

    這里我曾試過刪除里面的命名空間用 new的方式去寫,這樣可以簡潔代碼,但是后面異步的時候報錯,客服說不能刪除命名空間,這樣會導致方法名重復,所以還是乖乖的用demo

  中提供的方法。

    異步方法--------

    

  1     //銀聯充值異步
  2     public function xxx()
  3     {    
  4         Vendor('Yunpay.acp_service');
  5         $logger = \com\unionpay\acp\sdk\LogUtil::getLogger();
  6         $logger->LogInfo("receive back notify: " . \com\unionpay\acp\sdk\createLinkString ( $_POST, false, true ));
  7         if (isset ( $_POST ['signature'] )) {
  8                 // echo \com\unionpay\acp\sdk\AcpService::validate ( $_POST ) ? '驗簽成功' : '驗簽失敗';
  9                 $respCode = I('post.respCode');
 10                 $orderId = I('post.orderId');         // 商戶訂單號
 11                 $total_amount = I('post.settleAmt'); //訂單金額
 12                 $trade_no = I('post.queryId');         // queryId 銀聯唯一標識一筆交易
 13 
 14                 //判斷respCode=00、A6后,對涉及資金類的交易,請再發起查詢接口查詢,確定交易成功后更新數據庫。
 15                 if( $respCode=='00' ){
 16                      $this->unionpay($orderId,$total_amount,$trade_no);
 17                 }else{
 18                      $res = $this->confirmpay($orderId,'1');
 19                         if( $res == 'Successful' ){
 20                             $this->unionpay($orderId,$total_amount,$trade_no);
 21                      } else {
 22                             echo '交易失敗';
 23                      }
 24                 }
 25 
 26         } else {
 27             echo '簽名為空';
 28         }
 29 
 30 
 31     }
 32 
 33 
 34     //銀聯充值
 35     public function unionpay($orderId,$total_amount,$trade_no)
 36     {
 37         $per = M("pay_record")->where('win_code='.$orderId)->find(); //查找該訂單
 38         if( $per['status']=='1' ){
 39             echo '已充值';
 40             return;
 41         }
 42         $Pay = M("pay");
 43         // 在Pay模型中啟動事務
 44         $Pay->startTrans();            
 45         // 進行相關的業務邏輯操作
 46         $res = $Pay->where('uid='.$per['uid'])->setInc('money',$total_amount/100);
 47         //數據組合
 48         $data = array(
 49                 'alipay_number'=>$trade_no,                  //銀聯唯一標識
 50                 'status'=>'1',                              //交易狀態
 51                 'paytime'=>time()                          //交易時間
 52             );
 53         M("pay_record")->where('win_code='.$orderId)->save($data); // 修改交易信息
 54 
 55         if (!empty($res)){
 56           // 提交事務
 57           $Pay->commit();
 58         }else{
 59           // 事務回滾
 60           $Pay->rollback();
 61         }
 62     }
 63 
 64 
 65     //確定是否充值操作
 66     public function confirmpay($orderId,$L)
 67     {
 68         header ( 'Content-type:text/html;charset=utf-8' );
 69          Vendor('Yunpay.acp_service');
 70          $params = array(
 71             //以下信息非特殊情況不需要改動
 72             'version' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->version,          //版本號
 73             'encoding' => 'utf-8',          //編碼方式
 74             'signMethod' => \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->signMethod,          //簽名方法
 75             'txnType' => '00',              //交易類型
 76             'txnSubType' => '00',          //交易子類
 77             'bizType' => '000000',          //業務類型
 78             'accessType' => '0',          //接入類型
 79             'channelType' => '07',          //渠道類型
 80         );
 81         if($L == '0'){
 82             $time = M("order_pay")->where('win_code = "'.$orderId.'"')->find()['addtime'];
 83         }else{
 84             $time = M("pay_record")->where('win_code = "'.$orderId.'"')->find()['ordertime'];
 85         }
 86         $params['merId'] = C('Yunpay.merId');       //商戶號
 87         $params['orderId'] = $orderId;               //交易的訂單號
 88         $params['txnTime'] = date('YmdHis',$time); //訂單發送時間
 89 
 90         \com\unionpay\acp\sdk\AcpService::sign ( $params ); // 簽名
 91         $url = \com\unionpay\acp\sdk\SDKConfig::getSDKConfig()->singleQueryUrl;
 92 
 93         $result_arr = \com\unionpay\acp\sdk\AcpService::post ( $params, $url);
 94         if(count($result_arr)<=0) { //沒收到200應答的情況
 95             return 'No200';
 96         }
 97         if (!\com\unionpay\acp\sdk\AcpService::validate ($result_arr) ){
 98             return "應答報文驗簽失敗";
 99         }
100         if ($result_arr["respCode"] == "00"){
101             if ($result_arr["origRespCode"] == "00"){
102                 //交易成功
103                 //TODO
104                 return "Successful";
105             } else if ($result_arr["origRespCode"] == "03"
106                     || $result_arr["origRespCode"] == "04"
107                     || $result_arr["origRespCode"] == "05"){
108                 //后續需發起交易狀態查詢交易確定交易狀態
109                 //TODO
110                 return "交易處理中,請稍微查詢";
111             } else {
112                 //其他應答碼做以失敗處理
113                 //TODO
114                 return "交易失敗:" . $result_arr["origRespMsg"];
115             }
116         } else if ($result_arr["respCode"] == "03"
117                 || $result_arr["respCode"] == "04"
118                 || $result_arr["respCode"] == "05" ){
119             //后續需發起交易狀態查詢交易確定交易狀態
120             //TODO
121             return "處理超時,請稍微查詢";
122         } else {
123             //其他應答碼做以失敗處理
124             //TODO
125             return "失敗:" . $result_arr["respMsg"];
126         }
127 
128     }

    這里第一個方法xxx 中的respCode等於00 就是支付成功 ,如果沒有需要根據你生成的訂單號在次查詢在結果。這里客服說這種失敗不好模擬,就不說了,但是這操作方法還是

  建議寫下,以防萬一 。

    最后說明下幾個參數 queryId  銀聯唯一標識,需要保存, 還有銀聯支付是按 '分' 做單位的 所以支付跳轉前  假如是1元,你得乘以100,它才可以識別為1元,要不然就是0.01元

  然后異步到你的時候,如果你是元的單位在除於100,如果是分就不用了。

    搞定收工 , 祝大家早日成為大牛

  

    

 

 

    

  

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM