PHPを使用したバックエンドUnionPayの支払いと返金の例の詳細な説明
この記事では主にPHPでのバックエンドUnionPayの支払いと返金の例を詳しく紹介します。興味のある方はぜひ参考にしてください。
声明: この記事は最新の UnionPay SDK (2016-08-09 バージョン 5.1.0) に基づいています。異なるパッケージがある場合は、それがこのバージョンであるかどうかを確認してください
最近発生した UnionPay の支払いと関連する返金 (この記事では、携帯電話制御の支払いを前提として、そのプロセス中に発生した問題と基本的なプロセスを順に書き留めます。その前に、バックエンド担当者向けに、公式の画像を通じて支払いを理解します。この図からわかるように、バックエンドは 1. プラットフォーム注文の生成、2. UnionPay オムニチャネル プラットフォーム注文のプッシュ、3. フロントエンドへの tn コードの返しを行う必要があります。支払いのため; 4. オムニチャネル プラットフォームのフロント デスク通知および非同期通知を処理します。
ここには 3 つの問題があります。注文プッシュ、非同期通知処理、注文状況クエリです。
1. 関連するパラメーターの設定
SDK の Assets フォルダーでテストするドッキング プロセス 環境構成ファイルと証明書を SDK フォルダーに配置し、acp_sdk.ini 構成ファイルを正しく読み取るように /sdk/SDKconfig.php ファイルを構成します。acp_sdk.ini ファイル内の 4 つのファイル acpsdk.signCert.path、acpsdk.encryptCert.path、acpsdk.rootCert.path、および acpsdk.middleCert.path の絶対アドレスを構成します (ファイル パスをカスタマイズするだけです)。
プロジェクト開発中にシステムやプロジェクトアドレスが異なるため、証明書の絶対アドレスなどのエラーが発生する可能性があり、特に実際の運用環境では、プロジェクトデプロイメントファイルのアドレスが毎回異なることが非常に起こりやすくなります。証明書アドレスを変更するために、さまざまなファイル アドレスと互換性があるように SDK の SDKconfig.php を変更しました。
関連コードをクリックして表示してください
<?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(){ //如果想把acp_sdk.ini挪到其他路径的话,请修改下面这行指定绝对路径。 $configFilePath = dirname(__FILE__) . "/acp_sdk.ini"; $certsFilePath = dirname(dirname(__FILE__)) . "/certs/"; if(!file_exists($configFilePath)){ $logger = LogUtil::getLogger(); $logger->LogError("配置文件加载失败,文件路径:[" . $configFilePath . "].请检查启动php的用户是否有读权限。"); 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); } } }
3。非同期通知処理と注文トランザクション ステータス クエリ
まず、非同期通知処理について説明します。このステップは、注文ステータス変更の主な基礎です。実際に難しいことはありません。関連するパラメータに問題がないことを確認してください
use com\unionpay\acp\sdk\AcpService; use com\unionpay\acp\sdk\LogUtil; use com\unionpay\acp\sdk\SDKConfig; /** * 银联支付下单 * * @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( //以下信息非特殊情况不需要改动 'version' => $config->getSDKConfig()->version, //版本号 'encoding' => 'utf-8', //编码方式 'txnType' => '01', //交易类型 'txnSubType' => '01', //交易子类 'bizType' => '000201', //业务类型 'frontUrl' => $config->getSDKConfig()->frontUrl, //前台通知地址 'backUrl' => $this->getURL('api_pay_unionpay_call_back'), //后台通知地址 'signMethod' => $config->getSDKConfig()->signMethod, //签名方法 'channelType' => '08', //渠道类型,07-PC,08-手机 'accessType' => '0', //接入类型 'currencyCode' => '156', //交易币种,境内商户固定156 //TODO 以下信息需要填写 'merId' => $this->getParameter('mer_id'), //商户代码,请改自己的测试商户号 'orderId' => $orders["order_no"], //商户订单号,8-32位数字字母,不能含“-”或“_” 'txnTime' => $time, //订单发送时间,格式为YYYYMMDDhhmmss,取北京时间 'txnAmt' => $orders['total_price'] * 100, //交易金额,单位分 ); $AcpService->sign ( $params ); // 签名 $url = $config->getSDKConfig()->appTransUrl; $result_arr = $AcpService->post ($params, $url); if(count($result_arr)<=0) { //没收到200应答的情况 $log->LogInfo('没收到200应答的情况'); } // $this->printResult ($url, $params, $result_arr ); //页面打印请求应答数据 if (!$AcpService->validate ($result_arr) ){ $log->LogInfo('应答报文验签失败'); } if ($result_arr["respCode"] == "00"){ //成功 return array('txn_time'=>$time, 'tn'=>$result_arr["tn"]); // echo "后续请将此tn传给手机开发,由他们用此tn调起控件后完成支付。 \n"; // echo "手机端demo默认从仿真获取tn,仿真只返回一个tn,如不想修改手机和后台间的通讯方式,【此页面请修改代码为只输出tn】。 \n"; } else { //其他应答码做以失败处理 return array('txn_time'=>$time, 'tn'=>0); //echo "失败:" . $result_arr["respMsg"] . "。 \n"; } }
注文取引状況の照会
/** * 银联回调 * * @param Request $request * @return array|Response */ public function unionPayCallBackAction(Request $request) { if ($request->get('type') == 1){//前台通知-进行订单状态查询 $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(), 7, 13), 1))), 0, 8); $this->dispose($order_no, $trade_no, 4);//订单交易处理-请根据实际情况自行编写 } } else { if (!$request->request->has('signature')) { $log->LogInfo('签名为空'); } else { $log->LogInfo('验签失败'); } } exit; }
プロジェクトの注文がない場合は、オンラインで返金されます。完成します。
注文返金関連
do{//循环查询,直到获取到退款订单的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( //以下信息非特殊情况不需要改动 'version' => $config->getSDKConfig()->version, //版本号 'encoding' => 'utf-8', //编码方式 'signMethod' => $config->getSDKConfig()->signMethod, //签名方法 'txnType' => '00', //交易类型 'txnSubType' => '00', //交易子类 'bizType' => '000000', //业务类型 'accessType' => '0', //接入类型 'channelType' => '07', //渠道类型 //TODO 以下信息需要填写 'orderId' => $orders['order_no'], //请修改被查询的交易的订单号,8-32位数字字母,不能含“-”或“_” 'merId' => $this->getParameter('mer_id'), //商户代码,请改自己的测试商户号 'txnTime' => date('YmdHis', time()), //请修改被查询的交易的订单发送时间,格式为YYYYMMDDhhmmss ); $AcpService->sign ( $params ); // 签名 $url = $config->getSDKConfig()->singleQueryUrl; $result_arr = $AcpService->post ( $params, $url); if(count($result_arr)<=0) { //没收到200应答的情况 $log->LogInfo('没收到200应答的情况'); } if (!$AcpService->validate ($result_arr) ){ $log->LogInfo('应答报文验签失败'); } 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(), 7, 13), 1))), 0, 8); $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"){ //后续需发起交易状态查询交易确定交易状态 $result = array('errorCode'=>2, 'message'=>'交易处理中', 'result_arr'=>$result_arr); } else { //其他应答码做以失败处理 echo "交易失败:" . $result_arr["origRespMsg"] . "。 \n"; $result = array('errorCode'=>1, 'message'=>"交易失败:" . $result_arr["origRespMsg"] . ".", 'result_arr'=>$result_arr); } } else if ($result_arr["respCode"] == "03" || $result_arr["respCode"] == "04" || $result_arr["respCode"] == "05" ){ //后续需发起交易状态查询交易确定交易状态 $result = array('errorCode'=>2, 'message'=>"处理超时,请稍后查询.", 'result_arr'=>$result_arr); } else { //其他应答码做以失败处理 $result = array('errorCode'=>1, 'message'=>"失败:" . $result_arr["respMsg"] . ".", 'result_arr'=>$result_arr); } return $result; }
実際のロジックコードはご自身で実装してください
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{//循环查询,直到获取到退款订单的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'=>'订单未成交,无法退款'); } $params = array( //以下信息非特殊情况不需要改动 'version' => $config->getSDKConfig()->version, //版本号 'encoding' => 'utf-8', //编码方式 'signMethod' => $config->getSDKConfig()->signMethod, //签名方法 'txnType' => '04', //交易类型 'txnSubType' => '00', //交易子类 'bizType' => '000201', //业务类型 'accessType' => '0', //接入类型 'channelType' => '07', //渠道类型 'backUrl' => $config->getSDKConfig()->backUrl, //后台通知地址 //TODO 以下信息需要填写 'orderId' => "T" . $orders['order_no'], //商户订单号,8-32位数字字母,不能含“-”或“_”,可以自行定制规则,重新产生-此处为在退款订单前拼接 T 'merId' => $this->getParameter('mer_id'), //商户代码,请改成自己的商户号 'origQryId' => $query['result_arr']["queryId"], //原消费的queryId,可以从查询接口或者通知接口中获取 'txnTime' => date('YmdHis', time()), //订单发送时间,格式为YYYYMMDDhhmmss,重新产生,不同于原消费 'txnAmt' => $orders['total_price'] * 100, //交易金额,退货总金额需要小于等于原消费 ); $AcpService->sign ( $params ); // 签名 $url = $config->getSDKConfig()->backTransUrl; $result_arr = $AcpService->post ( $params, $url); if(count($result_arr)<=0) { //没收到200应答的情况 return array('errorCode'=>1, 'message'=>"没收到应答."); } if (!$AcpService->validate ($result_arr) ){ return array('errorCode'=>1, 'message'=>"应答报文验签失败."); } if ($result_arr["respCode"] == "00"){ //交易已受理,等待接收后台通知更新订单状态,如果通知长时间未收到也可发起交易状态查询 return array('errorCode'=>0, 'message'=>"受理成功."); } else if ($result_arr["respCode"] == "03" || $result_arr["respCode"] == "04" || $result_arr["respCode"] == "05" ){ //后续需发起交易状态查询交易确定交易状态 return array('errorCode'=>1, 'message'=>"处理超时,请稍微查询."); } else { //其他应答码做以失败处理 return array('errorCode'=>1, 'message'=>"失败:" . $result_arr["respMsg"] . "."); } }
プロジェクト関係は一時的に利用できません - follow-追加アップ
続きます。 。 。 。関連推奨事項:
PHPバックエンドUnionPay支払いの詳しい説明
PHPバックエンド
と返金例
UnionPay支払いDevelopment_html/ css_WEB-ITnose
以上がPHPを使用したバックエンドUnionPayの支払いと返金の例の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











PHPは主に手順プログラミングですが、オブジェクト指向プログラミング(OOP)もサポートしています。 Pythonは、OOP、機能、手続き上のプログラミングなど、さまざまなパラダイムをサポートしています。 PHPはWeb開発に適しており、Pythonはデータ分析や機械学習などのさまざまなアプリケーションに適しています。

PHPはWeb開発と迅速なプロトタイピングに適しており、Pythonはデータサイエンスと機械学習に適しています。 1.PHPは、単純な構文と迅速な開発に適した動的なWeb開発に使用されます。 2。Pythonには簡潔な構文があり、複数のフィールドに適しており、強力なライブラリエコシステムがあります。

PHPは1994年に発信され、Rasmuslerdorfによって開発されました。もともとはウェブサイトの訪問者を追跡するために使用され、サーバー側のスクリプト言語に徐々に進化し、Web開発で広く使用されていました。 Pythonは、1980年代後半にGuidovan Rossumによって開発され、1991年に最初にリリースされました。コードの読みやすさとシンプルさを強調し、科学的コンピューティング、データ分析、その他の分野に適しています。

PHPの中心的な利点には、学習の容易さ、強力なWeb開発サポート、豊富なライブラリとフレームワーク、高性能とスケーラビリティ、クロスプラットフォームの互換性、費用対効果が含まれます。 1)初心者に適した学習と使用が簡単。 2)Webサーバーとの適切な統合および複数のデータベースをサポートします。 3)Laravelなどの強力なフレームワークを持っています。 4)最適化を通じて高性能を達成できます。 5)複数のオペレーティングシステムをサポートします。 6)開発コストを削減するためのオープンソース。

phphassiblasifly-impactedwebdevevermentandsbeyondit.1)itpowersmajorplatformslikewordpratsandexcelsindatabase interactions.2)php'sadaptableability allowsitale forlargeapplicationsusingframeworkslikelavel.3)

PHPはWeb開発およびコンテンツ管理システムに適しており、Pythonはデータサイエンス、機械学習、自動化スクリプトに適しています。 1.PHPは、高速でスケーラブルなWebサイトとアプリケーションの構築においてうまく機能し、WordPressなどのCMSで一般的に使用されます。 2。Pythonは、NumpyやTensorflowなどの豊富なライブラリを使用して、データサイエンスと機械学習の分野で驚くほどパフォーマンスを発揮しています。

まだ人気があるのは、使いやすさ、柔軟性、強力なエコシステムです。 1)使いやすさとシンプルな構文により、初心者にとって最初の選択肢になります。 2)Web開発、HTTP要求とデータベースとの優れた相互作用と密接に統合されています。 3)巨大なエコシステムは、豊富なツールとライブラリを提供します。 4)アクティブなコミュニティとオープンソースの性質は、それらを新しいニーズとテクノロジーの傾向に適応させます。

PHPは、動的なWeb開発およびサーバー側のアプリケーションに使用されるサーバー側のスクリプト言語です。 1.PHPは、編集を必要とせず、迅速な発展に適した解釈言語です。 2。PHPコードはHTMLに組み込まれているため、Webページの開発が簡単になりました。 3。PHPプロセスサーバー側のロジック、HTML出力を生成し、ユーザーの相互作用とデータ処理をサポートします。 4。PHPは、データベースと対話し、プロセスフォームの送信、サーバー側のタスクを実行できます。
