国产精品毛片一区二区三区四区_国产亚洲中文日韩欧_91 超碰在线观看_一二三四电影在线观看免费_亚洲第一午夜福利网站_中文字幕在线永久_国产人妖的免费的视频_在线日韩视频成人网站观看_国产后入学生妹清纯妺_激情视频激情图片国产亚洲

  1. 首頁(yè)
  2. 新聞資訊
  3.  
  4. 建站經(jīng)驗(yàn)
  5.  

PHP后端銀聯(lián)支付及退款實(shí)例代碼

發(fā)布時(shí)間:2018-09-11 14:20:59 來(lái)源:
聲明:此文以當(dāng)前銀聯(lián)官方最新SDK(2016-08-09 5.1.0版)進(jìn)行說(shuō)明,若出現(xiàn)包不相同的情況請(qǐng)檢查是否是此版本

近期遇到銀聯(lián)支付以及相關(guān)退款(此文僅以手機(jī)控件支付作為前提)操作,下面會(huì)依次寫(xiě)出期間遇到的問(wèn)題以及基本流程,在此之前通過(guò)官方的一張圖片了解一個(gè)支付中,對(duì)于后端人員的我們需要做到的一些事情。
 

 

由此圖可以看出,后端在此負(fù)責(zé)1、平臺(tái)訂單生成;2、銀聯(lián)全渠道平臺(tái)訂單推送;3、返回tn碼給前端進(jìn)行支付;4、處理前臺(tái)通知以及全渠道平臺(tái)的異步通知。

此間難點(diǎn)有三,訂單推送、異步通知處理、訂單狀態(tài)查詢。

通過(guò)官方的郵件說(shuō)明下載相關(guān)的包并放入后端php代碼中,(支付控件去下載你看到的估計(jì)只有IOS,安卓版的SDK,對(duì)于后端來(lái)說(shuō),隨便下載一個(gè)即可,PHP的代碼在里面都有放置);然后仔細(xì)閱讀SDK中的readme.txt文件,此后進(jìn)行以下步驟:

一、相關(guān)參數(shù)配置

對(duì)接過(guò)程中使用在sdk的assets文件夾中測(cè)試環(huán)境配置文件及證書(shū),放置到sdk文件夾中,并配置/sdk/SDKconfig.php文件已正確的讀取acp_sdk.ini配置文件。

在acp_sdk.ini文件中配置好acpsdk.signCert.path、acpsdk.encryptCert.path、acpsdk.rootCert.path、acpsdk.middleCert.path四個(gè)文件的絕對(duì)地址(自定義文件路徑即可)。

因項(xiàng)目開(kāi)發(fā)過(guò)程中會(huì)出現(xiàn)系統(tǒng)不同或項(xiàng)目地址不同導(dǎo)致的證書(shū)絕對(duì)地址等錯(cuò)誤,尤其在實(shí)際生產(chǎn)環(huán)境中,極易出現(xiàn)項(xiàng)目部署文件地址不同,不可能在開(kāi)發(fā)后每次更新都要更換證書(shū)地址,在此修改了一下SDK中的SDKconfig.php已兼容不同文件地址較長(zhǎng),這里還請(qǐng)點(diǎn)擊展開(kāi)查看

<?php
namespace com\unionpay\acp\sdk;;
include_once 'log.class.php';
include_once 'common.php';

class SDKConfig {

  private static $_config = null;
  public static function getSDKConfig(){
    if (SDKConfig::$_config == null ) {
      SDKConfig::$_config = new SDKConfig();
    }
    return SDKConfig::$_config;
  }

  private $frontTransUrl;
  private $backTransUrl;
  private $singleQueryUrl;
  private $batchTransUrl;
  private $fileTransUrl;
  private $appTransUrl;
  private $cardTransUrl;
  private $jfFrontTransUrl;
  private $jfBackTransUrl;
  private $jfSingleQueryUrl;
  private $jfCardTransUrl;
  private $jfAppTransUrl;
  private $qrcBackTransUrl;
  private $qrcB2cIssBackTransUrl;
  private $qrcB2cMerBackTransUrl;

  private $signMethod;
  private $version;
  private $ifValidateCNName;
  private $ifValidateRemoteCert;

  private $signCertPath;
  private $signCertPwd;
  private $validateCertDir;
  private $encryptCertPath;
  private $rootCertPath;
  private $middleCertPath;
  private $frontUrl;
  private $backUrl;
  private $secureKey;
  private $logFilePath;
  private $logLevel;

  function __construct(){

    //如果想把a(bǔ)cp_sdk.ini挪到其他路徑的話,請(qǐng)修改下面這行指定絕對(duì)路徑。
    $configFilePath = dirname(__FILE__) . "/acp_sdk.ini";
    $certsFilePath = dirname(dirname(__FILE__)) . "/certs/";

    if(!file_exists($configFilePath)){
      $logger = LogUtil::getLogger();
      $logger->LogError("配置文件加載失敗,文件路徑:[" . $configFilePath . "].請(qǐng)檢查啟動(dòng)php的用戶是否有讀權(quán)限。");
      return;
    }
    $ini_array = parse_ini_file($configFilePath, true);
    $sdk_array = $ini_array["acpsdk"];
    $this->frontTransUrl = array_key_exists("acpsdk.frontTransUrl", $sdk_array)?$sdk_array["acpsdk.frontTransUrl"] : null;
    $this->backTransUrl = array_key_exists("acpsdk.backTransUrl", $sdk_array)?$sdk_array["acpsdk.backTransUrl"] : null;
    $this->singleQueryUrl = array_key_exists("acpsdk.singleQueryUrl", $sdk_array)?$sdk_array["acpsdk.singleQueryUrl"] : null;
    $this->batchTransUrl = array_key_exists("acpsdk.batchTransUrl", $sdk_array)?$sdk_array["acpsdk.batchTransUrl"] : null;
    $this->fileTransUrl = array_key_exists("acpsdk.fileTransUrl", $sdk_array)?$sdk_array["acpsdk.fileTransUrl"] : null;
    $this->appTransUrl = array_key_exists("acpsdk.appTransUrl", $sdk_array)?$sdk_array["acpsdk.appTransUrl"] : null;
    $this->cardTransUrl = array_key_exists("acpsdk.cardTransUrl", $sdk_array)?$sdk_array["acpsdk.cardTransUrl"] : null;
    $this->jfFrontTransUrl = array_key_exists("acpsdk.jfFrontTransUrl", $sdk_array)?$sdk_array["acpsdk.jfFrontTransUrl"] : null;
    $this->jfBackTransUrl = array_key_exists("acpsdk.jfBackTransUrl", $sdk_array)?$sdk_array["acpsdk.jfBackTransUrl"] : null;
    $this->jfSingleQueryUrl = array_key_exists("acpsdk.jfSingleQueryUrl", $sdk_array)?$sdk_array["acpsdk.jfSingleQueryUrl"] : null;
    $this->jfCardTransUrl = array_key_exists("acpsdk.jfCardTransUrl", $sdk_array)?$sdk_array["acpsdk.jfCardTransUrl"] : null;
    $this->jfAppTransUrl = array_key_exists("acpsdk.jfAppTransUrl", $sdk_array)?$sdk_array["acpsdk.jfAppTransUrl"] : null;
    $this->qrcBackTransUrl = array_key_exists("acpsdk.qrcBackTransUrl", $sdk_array)?$sdk_array["acpsdk.qrcBackTransUrl"] : null;
    $this->qrcB2cIssBackTransUrl = array_key_exists("acpsdk.qrcB2cIssBackTransUrl", $sdk_array)?$sdk_array["acpsdk.qrcB2cIssBackTransUrl"] : null;
    $this->qrcB2cMerBackTransUrl = array_key_exists("acpsdk.qrcB2cMerBackTransUrl", $sdk_array)?$sdk_array["acpsdk.qrcB2cMerBackTransUrl"] : null;

    $this->signMethod = array_key_exists("acpsdk.signMethod", $sdk_array)?$sdk_array["acpsdk.signMethod"] : null;
    $this->version = array_key_exists("acpsdk.version", $sdk_array)?$sdk_array["acpsdk.version"] : null;
    $this->ifValidateCNName = array_key_exists("acpsdk.ifValidateCNName", $sdk_array)?$sdk_array["acpsdk.ifValidateCNName"] : "true";
    $this->ifValidateRemoteCert = array_key_exists("acpsdk.ifValidateRemoteCert", $sdk_array)?$sdk_array["acpsdk.ifValidateRemoteCert"] : "false";

    $this->signCertPath = $certsFilePath . (array_key_exists("acpsdk.signCert.path", $sdk_array)?$sdk_array["acpsdk.signCert.path"]: null);
    $this->signCertPwd = array_key_exists("acpsdk.signCert.pwd", $sdk_array)?$sdk_array["acpsdk.signCert.pwd"]: null;

    $this->validateCertDir = array_key_exists("acpsdk.validateCert.dir", $sdk_array)? $sdk_array["acpsdk.validateCert.dir"]: null;
    $this->encryptCertPath = $certsFilePath . (array_key_exists("acpsdk.encryptCert.path", $sdk_array)? $sdk_array["acpsdk.encryptCert.path"]: null);
    $this->rootCertPath = $certsFilePath . (array_key_exists("acpsdk.rootCert.path", $sdk_array)? $sdk_array["acpsdk.rootCert.path"]: null);
    $this->middleCertPath = $certsFilePath . (array_key_exists("acpsdk.middleCert.path", $sdk_array)?$sdk_array["acpsdk.middleCert.path"]: null);

    $this->frontUrl = array_key_exists("acpsdk.frontUrl", $sdk_array)?$sdk_array["acpsdk.frontUrl"]: null;
    $this->backUrl = array_key_exists("acpsdk.backUrl", $sdk_array)?$sdk_array["acpsdk.backUrl"]: null;

    $this->secureKey = array_key_exists("acpsdk.secureKey", $sdk_array)?$sdk_array["acpsdk.secureKey"]: null;
    $this->logFilePath = array_key_exists("acpsdk.log.file.path", $sdk_array)?$sdk_array["acpsdk.log.file.path"]: null;
    $this->logLevel = array_key_exists("acpsdk.log.level", $sdk_array)?$sdk_array["acpsdk.log.level"]: null;

  }

  public function __get($property_name)
  {
    if(isset($this->$property_name))
    {
      return($this->$property_name);
    }
    else
    {
      return(NULL);
    }
  }

<strong>}
</strong>

 

二、全渠道商品訂單推送

相關(guān)代碼請(qǐng)點(diǎn)擊查看

use com\unionpay\acp\sdk\AcpService;
use com\unionpay\acp\sdk\LogUtil;
use com\unionpay\acp\sdk\SDKConfig;

  /**
   * 銀聯(lián)支付下單
   *
   * @param $orders
   * @param $orders_type
   * @return array
   */
  public function unionPay($orders, $orders_type = 0)
  {
    include_once dirname(dirname(dirname(__FILE__))) . '/Model/unionpay-sdk/sdk/acp_service.php';
    $config = new SDKConfig();
    $AcpService = new AcpService();
    $log = LogUtil::getLogger();
    $time = date('YmdHis', time());
    $params = array(

      //以下信息非特殊情況不需要改動(dòng)
      'version' => $config->getSDKConfig()->version,         //版本號(hào)
      'encoding' => 'utf-8',         //編碼方式
      'txnType' => '01',           //交易類型
      'txnSubType' => '01',         //交易子類
      'bizType' => '000201',         //業(yè)務(wù)類型
      'frontUrl' => $config->getSDKConfig()->frontUrl, //前臺(tái)通知地址
      'backUrl' => $this->getURL('api_pay_unionpay_call_back'),  //后臺(tái)通知地址
      'signMethod' => $config->getSDKConfig()->signMethod,         //簽名方法
      'channelType' => '08',         //渠道類型,07-PC,08-手機(jī)
      'accessType' => '0',        //接入類型
      'currencyCode' => '156',      //交易幣種,境內(nèi)商戶固定156

      //TODO 以下信息需要填寫(xiě)
      'merId' => $this->getParameter('mer_id'),   //商戶代碼,請(qǐng)改自己的測(cè)試商戶號(hào)
      'orderId' => $orders["order_no"],  //商戶訂單號(hào),8-32位數(shù)字字母,不能含“-”或“_”
      'txnTime' => $time, //訂單發(fā)送時(shí)間,格式為YYYYMMDDhhmmss,取北京時(shí)間
      'txnAmt' => $orders['total_price'] * 100,  //交易金額,單位分
    );

    $AcpService->sign ( $params ); // 簽名
    $url = $config->getSDKConfig()->appTransUrl;

    $result_arr = $AcpService->post ($params, $url);

    if(count($result_arr)<=0) { //沒(méi)收到200應(yīng)答的情況 $log->LogInfo('沒(méi)收到200應(yīng)答的情況');
    }

//    $this->printResult ($url, $params, $result_arr ); //頁(yè)面打印請(qǐng)求應(yīng)答數(shù)據(jù)

    if (!$AcpService->validate ($result_arr) ){
      $log->LogInfo('應(yīng)答報(bào)文驗(yàn)簽失敗');
    }
    if ($result_arr["respCode"] == "00"){
      //成功
      return array('txn_time'=>$time, 'tn'=>$result_arr["tn"]);
//      echo "后續(xù)請(qǐng)將此tn傳給手機(jī)開(kāi)發(fā),由他們用此tn調(diào)起控件后完成支付。
\n";
//      echo "手機(jī)端demo默認(rèn)從仿真獲取tn,仿真只返回一個(gè)tn,如不想修改手機(jī)和后臺(tái)間的通訊方式,【此頁(yè)面請(qǐng)修改代碼為只輸出tn】。
\n";
    } else {
      //其他應(yīng)答碼做以失敗處理
      return array('txn_time'=>$time, 'tn'=>0);
      //echo "失?。?span style="margin: 0px; padding: 0px; max-width: 100%; box-sizing: border-box !important; word-wrap: break-word !important; font-size: inherit; line-height: inherit; color: rgb(238, 220, 112); overflow-wrap: inherit !important; word-break: inherit !important;">" . $result_arr["respMsg"] . "。
\n";

    }
  }

 

在此注意txnTime格式不要傳錯(cuò),測(cè)試環(huán)境下應(yīng)該不會(huì)出現(xiàn)什么問(wèn)題,將得到的tn返回APP進(jìn)行支付即可

三、異步通知處理以及訂單交易狀態(tài)查詢

這一步主要作用為處理銀聯(lián)交易成功信息,并盡可能避免出現(xiàn)回調(diào)未處理導(dǎo)致問(wèn)題。

先說(shuō)異步通知處理,此步驟為訂單狀態(tài)修改的主要依據(jù)。無(wú)實(shí)際難點(diǎn),保證相關(guān)參數(shù)無(wú)問(wèn)題即可

/**
   * 銀聯(lián)回調(diào)
   *
   * @param Request $request
   * @return array|Response
   */
  public function unionPayCallBackAction(Request $request)
  {
    if ($request->get('type') == 1){//前臺(tái)通知-進(jìn)行訂單狀態(tài)查詢
      $query = $this->unionPayQuery($request, array(), 1);

      return new JsonResponse($query);
    }

    require_once dirname(dirname(dirname(__FILE__))) . "/Model/unionpay-sdk/sdk/acp_service.php";
    $log = LogUtil::getLogger();
    $AcpService = new AcpService();


    if ($request->request->has('signature') && $AcpService->validate($_POST)) {
      $order_no = $request->request->get('orderId');
      $respCode = $request->request->get('respCode');
      $total = $request->request->get('txnAmt'); // 交易金額
      if ($respCode === '00' || $respCode === 'A6') {
        $trade_no = $request->request->get('origQryId')?:'UN' . date('YmdHis', time()) . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 713), 1))), 08);
        $this->dispose($order_no, $trade_no, 4);//訂單交易處理-請(qǐng)根據(jù)實(shí)際情況自行編寫(xiě)
      }
    } else {
      if (!$request->request->has('signature')) {
        $log->LogInfo('簽名為空');
      } else {
        $log->LogInfo('驗(yàn)簽失敗');
      }
    }

    exit;
  }

 

訂單交易狀態(tài)查詢

 do{//循環(huán)查詢,直到獲取到退款訂單的queryID
      sleep($number * 2);
      $query = $this->unionPayQuery('', $orders);
      $number += 1;
    }while($query['errorCode'] != 0 || empty($query['result_arr']["queryId"]));

public function unionPayQuery($request, $orders)
  {
    require_once dirname(dirname(dirname(__FILE__))) . "/Model/unionpay-sdk/sdk/acp_service.php";
    $config = new SDKConfig();
    $AcpService = new AcpService();
    $log = LogUtil::getLogger();
    $params = array(
      //以下信息非特殊情況不需要改動(dòng)
      'version' => $config->getSDKConfig()->version,    //版本號(hào)
      'encoding' => 'utf-8',     //編碼方式
      'signMethod' => $config->getSDKConfig()->signMethod,     //簽名方法
      'txnType' => '00',       //交易類型
      'txnSubType' => '00',     //交易子類
      'bizType' => '000000',     //業(yè)務(wù)類型
      'accessType' => '0',    //接入類型
      'channelType' => '07',     //渠道類型

      //TODO 以下信息需要填寫(xiě)
      'orderId' => $orders['order_no'],  //請(qǐng)修改被查詢的交易的訂單號(hào),8-32位數(shù)字字母,不能含“-”或“_”
      'merId' => $this->getParameter('mer_id'),   //商戶代碼,請(qǐng)改自己的測(cè)試商戶號(hào)
      'txnTime' => date('YmdHis', time()), //請(qǐng)修改被查詢的交易的訂單發(fā)送時(shí)間,格式為YYYYMMDDhhmmss
    );

    $AcpService->sign ( $params ); // 簽名
    $url = $config->getSDKConfig()->singleQueryUrl;

    $result_arr = $AcpService->post ( $params, $url);
    if(count($result_arr)<=0) { //沒(méi)收到200應(yīng)答的情況 $log->LogInfo('沒(méi)收到200應(yīng)答的情況');
    }

    if (!$AcpService->validate ($result_arr) ){
      $log->LogInfo('應(yīng)答報(bào)文驗(yàn)簽失敗');
    }
    if ($result_arr["respCode"] == "00"){
      if ($result_arr["origRespCode"] == "00"){
        //交易成功
        $trade_no = 'UN' . date('YmdHis', time()) . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 713), 1))), 08);
        $this->dispose($orders['order_no'], $trade_no, 4);
        $result = array('errorCode'=>0'message'=>'交易成功''result_arr'=>$result_arr);

      } else if ($result_arr["origRespCode"] == "03"
        || $result_arr["origRespCode"] == "04"
        || $result_arr["origRespCode"] == "05"){
        //后續(xù)需發(fā)起交易狀態(tài)查詢交易確定交易狀態(tài)

        $result = array('errorCode'=>2'message'=>'交易處理中''result_arr'=>$result_arr);

      } else {
        //其他應(yīng)答碼做以失敗處理

        echo "交易失?。?quot; . $result_arr["origRespMsg"] . "。
\n";

        $result = array('errorCode'=>1'message'=>"交易失?。?quot; . $result_arr["origRespMsg"] . "."'result_arr'=>$result_arr);
      }
    } else if ($result_arr["respCode"] == "03"
      || $result_arr["respCode"] == "04"
      || $result_arr["respCode"] == "05" ){
      //后續(xù)需發(fā)起交易狀態(tài)查詢交易確定交易狀態(tài)

      $result = array('errorCode'=>2'message'=>"處理超時(shí),請(qǐng)稍后查詢."'result_arr'=>$result_arr);
    } else {
      //其他應(yīng)答碼做以失敗處理


      $result = array('errorCode'=>1'message'=>"失?。?quot; . $result_arr["respMsg"] . "."'result_arr'=>$result_arr);
    }

    return $result;
  }

 

到此為止,若是項(xiàng)目沒(méi)有訂單線上退款就完成了。

訂單退款相關(guān)

public function refundUnionPay($orders)
  {
    require_once(dirname(dirname(__FILE__)) . "/Model/unionpay-sdk/sdk/acp_service.php");

    set_time_limit(100);

    $config = new SDKConfig();
    $AcpService = new AcpService();
    $log = LogUtil::getLogger();
    $number = 0;
    do{//循環(huán)查詢,直到獲取到退款訂單的queryID
      sleep($number * 2);
      $query = $this->unionPayQuery('', $orders);
      $number += 1;
    }while($query['errorCode'] != 0 || empty($query['result_arr']["queryId"]));


    if ($query['errorCode'] != 0) {
      return array('errorCode'=>1'message'=>'訂單未成交,無(wú)法退款');
    }
    $params = array(

      //以下信息非特殊情況不需要改動(dòng)
      'version' => $config->getSDKConfig()->version,      //版本號(hào)
      'encoding' => 'utf-8',       //編碼方式
      'signMethod' => $config->getSDKConfig()->signMethod,       //簽名方法
      'txnType' => '04',         //交易類型
      'txnSubType' => '00',       //交易子類
      'bizType' => '000201',       //業(yè)務(wù)類型
      'accessType' => '0',      //接入類型
      'channelType' => '07',       //渠道類型
      'backUrl' => $config->getSDKConfig()->backUrl, //后臺(tái)通知地址

      //TODO 以下信息需要填寫(xiě)
      'orderId' => "T" . $orders['order_no'],   //商戶訂單號(hào),8-32位數(shù)字字母,不能含“-”或“_”,可以自行定制規(guī)則,重新產(chǎn)生-此處為在退款訂單前拼接 T
      'merId' => $this->getParameter('mer_id'),     //商戶代碼,請(qǐng)改成自己的商戶號(hào)
      'origQryId' => $query['result_arr']["queryId"], //原消費(fèi)的queryId,可以從查詢接口或者通知接口中獲取
      'txnTime' => date('YmdHis', time()),    //訂單發(fā)送時(shí)間,格式為YYYYMMDDhhmmss,重新產(chǎn)生,不同于原消費(fèi)
      'txnAmt' => $orders['total_price'] * 100,   //交易金額,退貨總金額需要小于等于原消費(fèi)
    );

    $AcpService->sign ( $params ); // 簽名
    $url = $config->getSDKConfig()->backTransUrl;

    $result_arr = $AcpService->post ( $params, $url);
    if(count($result_arr)<=0) { //沒(méi)收到200應(yīng)答的情況 return array('errorCode'=>1, 'message'=>"沒(méi)收到應(yīng)答.");
    }

    if (!$AcpService->validate ($result_arr) ){
      return array('errorCode'=>1'message'=>"應(yīng)答報(bào)文驗(yàn)簽失敗.");
    }

    if ($result_arr["respCode"] == "00"){
      //交易已受理,等待接收后臺(tái)通知更新訂單狀態(tài),如果通知長(zhǎng)時(shí)間未收到也可發(fā)起交易狀態(tài)查詢
      return array('errorCode'=>0'message'=>"受理成功.");

    } else if ($result_arr["respCode"] == "03"
      || $result_arr["respCode"] == "04"
      || $result_arr["respCode"] == "05" ){
      //后續(xù)需發(fā)起交易狀態(tài)查詢交易確定交易狀態(tài)
      return array('errorCode'=>1'message'=>"處理超時(shí),請(qǐng)稍微查詢.");
    } else {
      //其他應(yīng)答碼做以失敗處理

      return array('errorCode'=>1'message'=>"失?。?quot; . $result_arr["respMsg"] . ".");
    }
  }

 

依據(jù)返回狀態(tài)值進(jìn)行相關(guān)操作即可,實(shí)際邏輯代碼請(qǐng)自行實(shí)現(xiàn)

新聞資訊

 

服務(wù)項(xiàng)目

 

聯(lián)系我們

  • 咨詢電話:13316437003
  • 地址:廣東省深圳市福田區(qū)八卦四路中浩大廈2樓201
  • 業(yè)務(wù)咨詢:點(diǎn)擊這里給我發(fā)消息
  • 技術(shù)服務(wù):點(diǎn)擊這里給我發(fā)消息
  • 售后郵箱:service@dcnop.com
  • 技術(shù)郵箱:zcl@dcnop.com

 

微信公眾號(hào)

  • 客服:點(diǎn)擊這里給客服發(fā)消息

    技術(shù):點(diǎn)擊這里給技術(shù)發(fā)消息

    大誠(chéng)網(wǎng)絡(luò)--深圳網(wǎng)站制作|深圳網(wǎng)站優(yōu)化|深圳網(wǎng)站運(yùn)營(yíng)

    客戶服務(wù)熱線

    0755-82400810

    在線客服