交通銀行網銀支付與支付寶等聚合支付最大不同在於:核心加密/簽名邏輯由 Java 實現,PHP 需通過 Socket 與 Java 服務端通信。官方提供兩種模式:Socket 通信與 Java Bridge,本文採用前者。
JAVA_HOME 與 PATHkeytool -import -keystore "C:\Program Files\Java\jre1.5\lib\security\cacerts" \ -storepass changeit -alias test_bocommca -file "C:\socket\cert\test_root.cer"
in/B2CMerchantSocket.xml,測試商號可不改start.batnohup sh start.sh & 後台運行$config['interfaceVersion'] = "1.0.0.0"; $config['tranType'] = 0; // B2C $config['curType'] = 'CNY'; $config['notifyType'] = 1; // 主動通知 $config['merURL'] = "/pay/notify"; $config['goodsURL'] = '/goods/1.html'; $config['jumpSeconds'] = 3; $config['socketUrl'] = "tcp://127.0.0.1:8891"; $config['merID'] = '301310063009501';
class Bocom extends CI_Model {
private $arrReturn = [];
private $socket;
public function __construct() {
parent::__construct();
$this->config->load('bocom');
$this->socket = $this->config->item('socketUrl');
}
// 發起支付
public function pay($arr_data) {
// 組裝報文數據...
$source = implode('|', array_slice($this->arrReturn, 0, -1));
$fp = stream_socket_client($this->socket, $errno, $errstr, 30);
if (!$fp) return false;
$in = "";
$in .= "cb2200_sign ";
$in .= "$source ";
fwrite($fp, $in);
$retMsg = '';
while (!feof($fp)) $retMsg .= fgets($fp, 1024);
fclose($fp);
return $this->xmlParse($retMsg);
}
// 異步通知驗證
public function notify() {
if (!isset($_REQUEST['notifyMsg'])) return false;
$notifyMsg = $_REQUEST["notifyMsg"];
// 分離簽名與原文
$lastIndex = strripos($notifyMsg, "|");
$signMsg = substr($notifyMsg, $lastIndex + 1);
$srcMsg = substr($notifyMsg, 0, $lastIndex + 1);
// 發送驗證請求至 Java 端
$fp = stream_socket_client($this->socket, $errno, $errstr, 30);
$in = "";
$in .= "cb2200_verify ";
$in .= "{$this->config->item('merID')} ";
$in .= "$notifyMsg ";
fwrite($fp, $in);
$retMsg = '';
while (!feof($fp)) $retMsg .= fgets($fp, 1024);
fclose($fp);
// 解析驗證結果
$dom = new DOMDocument;
$dom->loadXML($retMsg);
$retCode = $dom->getElementsByTagName('retCode')->item(0)->nodeValue;
if ($retCode != '0') return false;
$arr = preg_split("/\|/", $srcMsg);
return $arr[9] == "1" ? $this->updateBill($arr[1]) : false;
}
private function xmlParse($retMsg) { /* 解析 XML 返回陣列 */ }
private function updateBill($billNo) { /* 更新訂單狀態 */ }
}
$this->load->model("Bocom");
// 支付
$this->arrData = $this->Bocom->pay($this->data);
// 通知
$this->arrData = $this->Bocom->notify();
iconv 轉換| 分隔字段,末尾附加簽名stream_socket_client 長連接,需處理超時與異常