DedeCMS (織夢) 旅遊網站需接入騰訊財付通 (Tenpay) 支付。官方無現成模組,自行封裝 tenpay 類放入 include/payment/ 目錄,配合會員中心訂單流程。
<?php
if (!defined('DEDEINC')) exit('Request Error!');
class tenpay {
var $dsql;
var $mid;
var $return_url = '/plus/carbuyaction.php?dopost=return'; // 回調入口
function __construct() {
global $dsql;
$this->dsql = $dsql;
}
// 設定回調地址(可選)
function SetReturnUrl($url) {
if ($url) $this->return_url = $url;
}
// 生成支付按鈕/表單
function GetCode($order, $payment) {
global $cfg_basehost, $cfg_cmspath;
if ($cfg_cmspath) $cfg_basehost .= '/' . $cfg_cmspath;
$partner = $payment['tenpay_account'];
$outTradeNo = $order['out_trade_no'];
$totalFee = floatval($order['price']) * 100; // 分
$body = $order['out_trade_no'];
$bankType = 'DEFAULT';
$transType = 1; // 1 實物 2 虛擬
$tradeMode = $payment['tenpay_pay_method'] ?? '1';
$params = [
'partner' => $partner,
'out_trade_no' => $outTradeNo,
'total_fee' => $totalFee,
'notify_url' => $cfg_basehost . $this->return_url . "&code={$payment['code']}",
'return_url' => $cfg_basehost . $this->return_url . "&code={$payment['code']}",
'body' => $body,
'bank_type' => $bankType,
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'fee_type' => '1',
'subject' => $body,
'sign_type' => 'MD5',
'service_version' => '1.0',
'input_charset' => 'UTF-8',
'sign_key_index' => '1',
'attach' => '',
'product_fee' => '',
'transport_fee' => '0',
'time_start' => date('YmdHis'),
'time_expire' => '',
'buyer_id' => '',
'goods_tag' => '',
'trade_mode' => $tradeMode,
'transport_desc' => '',
'trans_type' => $transType,
'agentid' => '',
'agent_type' => '',
'seller_id' => '',
];
ksort($params);
$signStr = '';
$urlParams = '';
foreach ($params as $k => $v) {
$urlParams .= "$k=" . urlencode($v) . "&";
if ($v !== '' && $k !== 'sign') $signStr .= "$k=$v&";
}
$signStr .= "key={$payment['tenpay_key']}";
$sign = strtolower(md5($signStr));
$urlParams = rtrim($urlParams, '&');
$btn = '<div style="text-align:center"><a href="https://gw.tenpay.com/gateway/pay.htm?' . $urlParams . '&sign=' . $sign . '"><button>立即使用財付通支付</button></a></div>';
// 清空購物車(Dede 內建類)
require_once DEDEINC . '/shopcar.class.php';
$cart = new MemberShops();
$cart->clearItem();
$cart->MakeOrders();
return $btn;
}
// 回調處理
function respond() {
$code = preg_replace('#[^0-9a-z-]#i', '', $_GET['code'] ?? '');
require_once DEDEDATA . "/payment/$code.php"; // 載入該支付方式配置(含 tenpay_key)
$attach = $_GET['attach'] ?? '';
$tradeState = $_GET['trade_state'] ?? '';
$totalFee = $_GET['total_fee'] ?? 0;
$outTradeNo = trim($_GET['out_trade_no'] ?? '');
// 驗證訂單號格式(示例:S-P123RN4)
if (!preg_match('/S-P\d+RN\d+/', $outTradeNo)) return '訂單號格式錯誤';
// 核對金額
$row = $this->dsql->GetOne("SELECT * FROM `#@__shops_orders` WHERE oid = '$outTradeNo'");
if (!$row || $row['priceCount'] != $totalFee) return '支付金額不符';
$this->mid = $row['userid'];
// 驗證簽名
ksort($_GET);
$signStr = '';
foreach ($_GET as $k => $v) {
if ($v !== '' && $k !== 'sign' && $k !== 'code') $signStr .= "$k=$v&";
}
$signStr .= "key={$payment['tenpay_key']}";
$calcSign = strtolower(md5($signStr));
if ($calcSign !== strtolower($_GET['sign'] ?? '')) return '簽名驗證失敗';
if ($tradeState == '0') { // 成功
if ($this->success_db($outTradeNo)) {
return "支付成功!<br><a href='/'>返回首頁</a> <a href='/member'>會員中心</a>";
} else {
return "支付失敗!<br><a href='/'>返回首頁</a>";
}
}
return '交易狀態異常';
}
// 更新訂單狀態
function success_db($orderSn) {
$sql = "UPDATE `#@__shops_orders` SET `state`=1 WHERE `oid`='$orderSn' AND `userid`='{$this->mid}'";
if ($this->dsql->ExecuteNoneQuery($sql)) {
$this->log_result("verify_success,訂單號:$orderSn");
return true;
}
$this->log_result("verify_failed,訂單號:$orderSn");
return false;
}
function log_result($msg) {
$fp = fopen(dirname(__FILE__) . "/../../data/payment/log.txt", 'a');
flock($fp, LOCK_EX);
fwrite($fp, "$msg,執行時間:" . date('Y-m-d H:i:s') . "\r\n");
flock($fp, LOCK_UN);
fclose($fp);
}
}
include/payment/tenpay.php。data/payment/ 目錄可寫入日誌。carbuyaction.php?dopost=return&code=tenpay → 更新訂單狀態。sign、total_fee、out_trade_no 三要素。notify_url (服務器間通知) 作為最終以準,return_url 僅作頁面跳轉提示。DedeCMS 整合財付通核心在於:GetCode() 組裝簽名跳轉網關,respond() 驗證回調簽名並更新訂單。代碼遵循 Dede 支付模組規範,可直接放入 include/payment/ 使用。新專案請改用微信支付/支付寶官方 SDK。