金流卡關=業績雪崩!WordPress 第三方支付終極串接實戰:ECPay vs. HitPay 深度剖析
嗨,我是浪花科技的資深工程師 Eric。今天來聊一個每個電商網站主都躲不掉的痛點:金流。你可能花了大把心力設計了精美的商品頁、優化了結帳流程,結果使用者在最後一步付款時卡關、跳轉失敗、或是付款了訂單狀態卻沒更新… 這些鳥事,不只會搞掉你的訂單,更會一點一滴侵蝕掉顧客對你的信任。這簡直是工程師的惡夢。
市面上有很多現成的金流外掛,點幾下就能裝好,聽起來很美好對吧?但身為一個有點龜毛的工程師,我總覺得「方便」的背後,往往藏著你看不到的魔鬼。外掛更新不及時、與你的主題或其他外掛衝突、客製化彈性低落,甚至可能有效能或安全性的隱憂。所以今天,我們不當伸手牌,我們要捲起袖子,親手解剖並實作台灣最常見的 ECPay (綠界科技) 以及面向東南亞市場的 HitPay,搞懂 第三方支付 API 串接實作 的核心邏輯。
為什麼不裝外掛就好?工程師的堅持與考量
「Eric,有輪子就用,幹嘛自己重造?」這問題我被問過不下數百次。答案很簡單:掌控權。當金流掌握在自己手上時,你擁有的是:
- 更高的客製化彈性: 你可以完美整合結帳流程與你的品牌視覺,甚至串接更複雜的商業邏輯,例如依據會員等級給予不同的付款選項。
- 更強的系統穩定性: 你不必擔心外掛作者停止維護,或是某次 WordPress 核心更新後,你的金流就直接原地爆炸。自己的 Code 自己負責,睡得也比較安穩。
- 更透徹的除錯能力: 當金流出問題時,你不是只能回報外掛作者然後癡癡地等。你可以直接追蹤 Log、看 API Request/Response,精準定位問題,快速修復。
- 更佳的網站效能: 有些肥大的金流外掛會載入一堆用不到的 CSS 和 JavaScript,拖慢你的網站速度。自己串接,只載入必要的東西,乾淨俐落。
當然,這條路需要你對 PHP 和 WordPress Hooks 有一定的了解。但相信我,投資這個技能點,絕對是值回票價的。
決戰支付之巔:ECPay vs. HitPay 快速預覽
在我們深入程式碼之前,先快速了解一下今天兩位主角的背景:
- ECPay (綠界科技): 台灣電商金流的龍頭,幾乎支援所有你想得到的付款方式(信用卡、超商代碼、ATM、條碼…)。串接方式比較「傳統」,採用 Form Post 的方式傳遞資料。如果你主要經營台灣市場,ECPay 幾乎是必選項。
- HitPay: 來自新加坡的金流服務商,強項在於整合東南亞各國的本地支付(例如 PayNow, GrabPay)。採用的是更現代化的 RESTful API,對於習慣 JSON 和 Webhook 的開發者來說會更親切。如果你有跨境電商的需求,HitPay 值得你關注。
ECPay API 串接實戰:傳統但穩定的老大哥
ECPay 的串接核心概念是「建立一個自動提交的 HTML 表單」。聽起來有點 old school,但它就是這麼運作的。我們要把所有訂單資訊、商店資訊,加上一個最重要的「簽名」,包成一個表單,然後把使用者「送」到 ECPay 的結帳頁面。
第一步:取得你的金庫鑰匙 (API 金鑰)
首先,你必須到 ECPay 申請成為特約商店,審核通過後,登入到廠商後台,在「系統開發管理」>「系統介接設定」中,你會找到三個至關重要的資訊:
- 商店代號 (MerchantID): 你的商店唯一識別碼。
- HashKey: 用來產生簽名 (CheckMacValue) 的金鑰。
- HashIV: 用來產生簽名的初始向量。
工程師的囉嗦: 請務必、絕對、不要把 HashKey 和 HashIV 寫死在你的程式碼或存在資料庫裡。最好的作法是將它們定義在 `wp-config.php` 檔案中,這是 WordPress 最安全的設定檔之一。
// 在 wp-config.php 中加入以下程式碼
define('ECPAY_MERCHANT_ID', '你的商店代號');
define('ECPAY_HASH_KEY', '你的 HashKey');
define('ECPAY_HASH_IV', '你的 HashIV');
第二步:打造訂單資料與簽名 (CheckMacValue)
當使用者在 WooCommerce 點擊「下單購買」後,我們要攔截這個動作,準備好要送去 ECPay 的資料。核心就是產生那個名為 `CheckMacValue` 的簽章,這是 ECPay 用來驗證這筆訂單是不是真的由你發出的機制。
它的產生規則有點繁瑣:將所有必要參數按照字母順序排序,串接成一個字串,頭尾再加上 HashKey 和 HashIV,最後進行 SHA256 加密並轉成大寫。聽起來很複雜?沒關係,直接看 Code 最快。
function generate_ecpay_checkout_form($order_id) {
$order = wc_get_order($order_id);
// 1. 準備基本參數
$params = [
'MerchantID' => ECPAY_MERCHANT_ID,
'MerchantTradeNo' => 'YOUR_PREFIX' . $order_id . time(), // 商店訂單編號,務必唯一
'MerchantTradeDate' => date('Y/m/d H:i:s'),
'PaymentType' => 'aio',
'TotalAmount' => $order->get_total(),
'TradeDesc' => '網站商品一批',
'ItemName' => '商品名稱1#商品名稱2', // 用 # 分隔
'ReturnURL' => 'https://你的網站.com/checkout/order-received/', // 前端返回網址
'ChoosePayment' => 'ALL',
'EncryptType' => 1, // 表示使用 SHA256
'ClientBackURL' => $order->get_cancel_order_url(),
'OrderResultURL' => 'https://你的網站.com/ecpay-notify' // 後端通知網址,非常重要!
];
// 2. 核心:產生 CheckMacValue 簽章
uksort($params, 'strcasecmp'); // 依 key 做字母排序
$mac_string = 'HashKey=' . ECPAY_HASH_KEY;
foreach ($params as $key => $value) {
$mac_string .= '&' . $key . '=' . $value;
}
$mac_string .= '&HashIV=' . ECPAY_HASH_IV;
// URL Encode 後轉小寫
$mac_string = urlencode($mac_string);
$mac_string = strtolower($mac_string);
// 特殊字元處理 (ECPay 的奇妙規則)
$mac_string = str_replace('%2d', '-', $mac_string);
$mac_string = str_replace('%5f', '_', $mac_string);
$mac_string = str_replace('%2e', '.', $mac_string);
$mac_string = str_replace('%21', '!', $mac_string);
$mac_string = str_replace('%2a', '*', $mac_string);
$mac_string = str_replace('%28', '(', $mac_string);
$mac_string = str_replace('%29', ')', $mac_string);
$params['CheckMacValue'] = strtoupper(hash('sha256', $mac_string));
// 3. 產生 HTML 表單
$html_form = '<form id="ecpay-form" method="post" action="https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5">';
foreach ($params as $key => $value) {
$html_form .= '<input type="hidden" name="' . $key . '" value="' . $value . '" />';
}
$html_form .= '</form><script>document.getElementById("ecpay-form").submit();</script>';
echo $html_form;
exit;
}
第三步:處理 Webhook (OrderResultURL),驗證付款結果
這是整個流程中最關鍵的一步。當使用者付款成功後,ECPay 的伺服器會悄悄地、在後端發送一個 POST 請求到你指定的 `OrderResultURL`。這個請求包含了付款結果,我們必須在這裡驗證簽章,確認付款無誤後,才更新我們資料庫裡的訂單狀態。
千萬記住:絕對不能相信 `ReturnURL` 帶回來的參數! `ReturnURL` 只是給使用者看的,任何人都可以偽造參數送到這個網址。只有通過後端 `OrderResultURL` 並成功驗證 `CheckMacValue` 的通知,才是可信的。
// 註冊一個自訂的 API 端點來接收通知
add_action('init', function() {
add_rewrite_rule('^ecpay-notify/?', 'index.php?is_ecpay_notify=1', 'top');
});
add_action('parse_request', function($wp) {
if (isset($wp->query_vars['is_ecpay_notify'])) {
handle_ecpay_notify();
exit;
}
});
function handle_ecpay_notify() {
$response = $_POST;
// 再次產生 CheckMacValue 來比對
$received_mac = $response['CheckMacValue'];
unset($response['CheckMacValue']);
uksort($response, 'strcasecmp');
// ... (省略與前面相同的簽章產生邏輯) ...
$calculated_mac = strtoupper(hash('sha256', $mac_string));
if ($received_mac === $calculated_mac && $response['RtnCode'] == '1') {
// 簽章正確 && 付款成功
$order_id = ...; // 從 $response['MerchantTradeNo'] 解析出你的訂單 ID
$order = wc_get_order($order_id);
if ($order) {
$order->payment_complete(); // 更新訂單狀態為「已付款」
$order->add_order_note('ECPay 付款成功,交易碼:' . $response['TradeNo']);
}
echo '1|OK'; // 必須回傳這個字串給 ECPay
} else {
// 驗證失敗或付款失敗,記錄錯誤
error_log('ECPay Notify failed: ' . print_r($response, true));
echo '0|ERROR';
}
}
HitPay API 串接實戰:擁抱 RESTful 的現代化流程
相較於 ECPay,HitPay 的串接方式對現代開發者來說更直覺。它採用的是標準的 RESTful API,我們透過 HTTP Request 傳送 JSON 格式的資料,然後接收 JSON 格式的回應。
第一步:取得 API Key 與 Salt
登入 HitPay Dashboard,在「Settings」>「Payment Gateway」>「API Keys」中,你可以產生一組 API Key 和 Salt。這兩個值同樣非常機密,請務必存放在 `wp-config.php` 中。
第二步:發送 Create Payment Request
使用者下單後,我們不再是產生表單,而是透過 WordPress 的 `wp_remote_post()` 函式,向 HitPay 的 API 端點發送一個建立付款請求。
function create_hitpay_payment($order_id) {
$order = wc_get_order($order_id);
$api_key = defined('HITPAY_API_KEY') ? HITPAY_API_KEY : '';
$body = [
'email' => $order->get_billing_email(),
'amount' => $order->get_total(),
'currency' => $order->get_currency(),
'reference_number' => 'ORDER_' . $order_id,
'webhook' => 'https://你的網站.com/hitpay-webhook',
'redirect_url' => $order->get_checkout_order_received_url(),
];
$response = wp_remote_post('https://api.hit-pay.com/v1/payment-requests', [
'method' => 'POST',
'headers' => [
'X-BUSINESS-API-KEY' => $api_key,
'Content-Type' => 'application/json'
],
'body' => json_encode($body),
'timeout' => 30
]);
if (is_wp_error($response)) {
// 請求失敗,處理錯誤
return false;
}
$response_body = json_decode(wp_remote_retrieve_body($response), true);
if (isset($response_body['url'])) {
// 成功取得付款頁面網址,將使用者導向過去
wp_redirect($response_body['url']);
exit;
} else {
// API 回傳錯誤,記錄下來
error_log('HitPay API Error: ' . print_r($response_body, true));
return false;
}
}
第三步:驗證 HitPay Webhook
HitPay 的 Webhook 驗證機制採用 HMAC (Hash-based Message Authentication Code)。當 HitPay 發送通知到你的 Webhook URL 時,它會在 HTTP Header 中附上一個 `X-Signature`。我們需要用收到的 Payload 和我們預先存好的 Salt,用同樣的 HMAC-SHA256 演算法算一次,比對結果是否相符。
function handle_hitpay_webhook() {
$payload = file_get_contents('php://input');
$received_hmac = isset($_SERVER['HTTP_X_SIGNATURE']) ? $_SERVER['HTTP_X_SIGNATURE'] : '';
$salt = defined('HITPAY_SALT') ? HITPAY_SALT : '';
if (empty($received_hmac) || empty($salt)) {
http_response_code(400);
echo 'Invalid request.';
return;
}
// 核心:計算 HMAC 並比對
$calculated_hmac = hash_hmac('sha256', $payload, $salt);
if (hash_equals($calculated_hmac, $received_hmac)) {
// 驗證成功
$data = json_decode($payload, true);
if ($data['status'] === 'completed') {
$order_id = str_replace('ORDER_', '', $data['reference_number']);
$order = wc_get_order($order_id);
if ($order && !$order->is_paid()) {
$order->payment_complete($data['payment_id']);
$order->add_order_note('HitPay 付款成功,Payment ID: ' . $data['payment_id']);
}
}
http_response_code(200);
echo 'Webhook processed.';
} else {
// 驗證失敗
http_response_code(401);
echo 'Signature verification failed.';
error_log('HitPay Webhook signature mismatch.');
}
}
工程師的囉嗦時間:金流串接的魔鬼細節
不管你用哪家金流,有些原則是共通的,忽略了就等於在網站上埋了不定時炸彈:
- 日誌記錄 (Logging) 是你的救世主: 把每一次的 API 請求、回應、Webhook 內容全都記錄下來。當發生掉單、客戶說付了錢但訂單沒更新時,這些 Log 就是你唯一的破案線索。
- idempotency (冪等性): 你的 Webhook 處理邏輯必須是冪等的。意思是,就算金流商因為網路問題重複發送了同一個成功通知,你的系統也不能重複處理訂單(例如重複扣庫存或給客戶兩次點數)。處理前務必檢查訂單是否已經是「已付款」狀態。
- 安全性,老生常談但最重要: 再次強調,API 金鑰絕對不能進 Git 版控。使用 `wp-config.php` 或環境變數來管理。所有來自外部的輸入都要做適當的清理 (Sanitize)。
- 使用者體驗 (UX) 不能忘: 在 `ReturnURL` 頁面,要給使用者明確的回饋。不要只顯示一個空白頁或「謝謝購買」。清楚地告訴他們「我們正在確認您的付款結果,請稍後…」或是「付款成功!訂單 #12345 已成立」。
搞懂 第三方支付 API 串接實作(ECPay / HitPay) 的底層邏輯,不僅能讓你打造出更穩定、更客製化的電商網站,更是身為一個專業 WordPress 開發者不可或缺的技能。雖然過程比裝外掛複雜,但那種一切盡在掌握的安心感,是無可取代的。
相關閱讀
- 告別手動上架地獄!WooCommerce 商品 API 終極實戰,讓你的庫存、ERP 同步自動化!
- 告別手動複製貼上!WooCommerce Webhook 終極指南:打造零失誤、全自動的訂單處理流程
- 你的 WordPress 網站是駭客的提款機?SQL Injection 終極防禦聖經,滴水不漏守護你的資料庫!
需要專業的金流串接服務嗎?
如果你覺得以上的程式碼太過複雜,或者你的商業邏輯需要更深度的客製化整合,別擔心,這正是浪花科技的專業所在。我們有豐富的 WordPress 與 WooCommerce 金流 API 串接經驗,能為你打造安全、穩定且高效的電子商務解決方案。立即聯繫我們,讓專業的團隊為你的事業保駕護航!
常見問題 (FAQ)
Q1: 為什麼要手動串接金流 API,而不是直接用現成的外掛?
A: 手動串接能提供最大的客製化彈性、更好的系統穩定性與效能,並且讓你擁有完全的掌控權。當金流出問題時,你能直接追蹤程式碼與 Log 進行除錯,而不必依賴外掛開發者的更新。對於追求極致穩定與客製化的企業級網站來說,這是更專業的作法。
Q2: ReturnURL (前端返回網址) 和 Webhook/NotifyURL (後端通知) 有什麼根本上的不同?
A: 這是金流串接中最重要的觀念。ReturnURL 是給使用者看的,主要用於引導使用者回到你的網站,提升使用者體驗,但它的資料是不可信的,因為可能被偽造。Webhook/NotifyURL 是金流服務商的伺服器在背景直接與你的伺服器溝通的管道,並透過簽章機制驗證,只有這裡收到的通知才是確認付款狀態、更新資料庫的唯一可靠依據。
Q3: 如何安全地儲存我的 API 金鑰 (例如 ECPay 的 HashKey 或 HitPay 的 Salt)?
A: 最佳實踐是將這些機敏資訊存放在 WordPress 網站根目錄的 `wp-config.php` 檔案中,使用 PHP 的 `define()` 常數來定義。千萬不要將它們直接寫在佈景主題或外掛的程式碼中,更不要儲存在資料庫的 options 表格裡,以避免它們被包含在版本控制系統 (如 Git) 或資料庫備份中而外洩。
Q4: 我在測試 ECPay 時,CheckMacValue 簽章一直驗證錯誤,該檢查哪些地方?
A: ECPay 的簽章錯誤是新手最常見的坑。請依序檢查:1. 參數名稱的大小寫是否正確? 2. 參數是否已按照 Key 的字母順序排序? 3. 組合字串時,頭尾是否正確加上了 `HashKey=` 和 `&HashIV=`? 4. 字串在進行 SHA256 加密前,是否已經過 URL Encode 並轉為全小寫? 5. 是否有處理 ECPay 規定的那幾個特殊字元轉換?一步一步對照官方文件,通常就能找到問題所在。






