XenForo 2.3 的 OPay 歐付寶(與 ECPay 綠界科技 共用同一 AIO API)官方金流整合套件,提供完整的「使用者升級 / 商品付款」流程,並在後台提供訂單管理、手動成立 / 取消 / 退款,以及即時向 OPay 查詢訂單狀態等管理功能。
- 套件 ID:
YUCTS/Opay - 適用版本:XenForo 2.3.0 以上
- 開發者:YUCTS
- 授權:MIT
- 完全依照 XenForo 官方 Payment Provider 規範 撰寫,繼承
XF\Payment\AbstractProvider,可直接套用至:- 使用者升級(User Upgrade)
- 任何實作
XF\Purchasable\AbstractPurchasable的第三方付費商品
- 同時支援 OPay 歐付寶 與 ECPay 綠界科技(同一介面,僅 API 主機不同)。
- 同時支援 SHA256(推薦)與 MD5 兩種 CheckMacValue 加密方式,可在付款設定檔中切換。
- 後台「OPay 訂單管理」介面,可:
- 依訂單編號、會員、狀態進行搜尋
- 檢視單筆訂單詳情、原始回傳資料、相關交易記錄
- 手動成立訂單(觸發 XenForo 的升級開通或商品交付流程)
- 手動取消訂單
- 向 OPay 申請退刷 / 退款(信用卡走
DoAction(R)、ATM/CVS 走AioChargeback) - 即時向 OPay 查詢訂單狀態(
QueryTradeInfo),並自動回填 TradeNo / 自動同步「已付款」狀態
- 後台「連線測試」工具:以您的設定向 OPay 送出一筆刻意不存在的訂單編號,立即驗證 MerchantID / HashKey / HashIV / 加密類型 / API 端點是否全部正確,免去反覆送真實訂單測試。
- 後台訂單檢視頁附「診斷資訊」區塊:顯示該筆交易實際使用的服務商、環境、加密類型、API 端點、對應廠商後台連結,疑難排解一目了然。
- OPay 回傳明確失敗(
RtnCode != 1)且 CheckMacValue 驗證通過時,自動把訂單標記為failed,並寫入錯誤碼與訊息,後台不會卡在「待付款」。 - 完整的 CheckMacValue 雙向驗證(採
hash_equals常數時間比對,避免時序攻擊)。 - 自訂資料表
xf_yucts_opay_transaction,與 XenForo 內建xf_payment_provider_log互相對應。 - 內建每日 04:15 排程,自動清理過期的
pending/failed/cancelled紀錄,paid與refunded永久保留以利對帳。 - 除錯模式:開啟後將所有 OPay 通訊內容寫入專屬檔案
internal_data/yucts_opay_debug.log,不污染 XenForo 伺服器錯誤日誌。 - 全繁體中文介面與用語。
| 付款方式 | OPay 代號 | 後台手動退款 |
|---|---|---|
| 信用卡 | Credit |
退刷(DoAction(R)) |
| 網路 ATM | WebATM |
廠商通知退款(AioChargeback) |
| ATM 虛擬帳號 | ATM |
廠商通知退款(AioChargeback) |
| 超商代碼 | CVS |
廠商通知退款(AioChargeback) |
註:本版本不支援信用卡定期定額(Recurring)。若您僅以 XenForo 內建「使用者升級」做單次或可重複續購之升級,本套件已可完整支援。
- XenForo 2.3.0 以上
- PHP 7.4 以上(建議 8.0+)
- 必要 PHP 擴充:
curl,mbstring,hash,json - 一組有效的 OPay 或綠界 ECPay 特店帳號(含
MerchantID/HashKey/HashIV)
- 下載本倉庫的 ZIP(或 Release 包)。
- 將壓縮包中的
src/目錄解壓上傳至您 XenForo 站點的根目錄,會自動合併至既有的src/addons/結構。最終路徑必須為:<您的 XF 根目錄>/src/addons/YUCTS/Opay/addon.json - 進入 XenForo 後台:附加元件 → 安裝可用的附加元件,找到「OPay 歐付寶 (台灣金流)」並按下安裝。
cd /path/to/your-xenforo/src/addons
mkdir -p YUCTS
cd YUCTS
git clone https://github.com/PomeloSky/XenForo-Opay.git Opay
# 注意:此倉庫 src/addons/YUCTS/Opay 才是 addon 本體或更乾淨的作法:
git clone https://github.com/PomeloSky/XenForo-Opay.git /tmp/xf-opay
cp -r /tmp/xf-opay/src/addons/YUCTS /path/to/your-xenforo/src/addons/取得三個關鍵憑證:
- 特店編號
MerchantID HashKeyHashIV
測試環境請使用 OPay / 綠界提供的測試專用憑證;上線前請務必切換為正式環境並填入正式憑證。
進入 後台 → 設定 → 付款方式 → 新增付款設定檔,選擇「OPay 歐付寶 (台灣金流)」,依序填寫:
| 設定 | 說明 |
|---|---|
| 顯示標題 | 例如「信用卡 / ATM / 超商付款」 |
| 特店編號 (MerchantID) | OPay/綠界提供(系統會自動 trim 前後空白) |
| HashKey / HashIV | OPay/綠界提供(系統會自動 trim 前後空白) |
| 服務商 | OPay 或 ECPay(決定 API 主機) |
| 環境 | 上線前請以 Stage 測試環境完成端對端驗證 |
| CheckMacValue 加密方式 | 預設 SHA256(2017 年起所有新 OPay 帳號的標準)。若您是早期 OPay 帳號收到 CheckMacValue 不符錯誤,再切到 MD5 試試。 |
| 允許的付款方式 | 至少勾選 1 項。建議直接全選四種讓 OPay 顯示收銀台選單;僅勾 1 項則直接導向該付款方式 |
| ATM 繳費期限(天) | 1~60,預設 3 |
| 超商代碼繳費期限(分鐘) | 60 ~ 43200(30 天),預設 10080(7 天) |
後台 → 使用者 → 使用者升級,在升級項目中勾選剛才建立的 OPay 付款設定檔。
後台 → 設定 → 選項 → OPay 歐付寶:
- 交易記錄保留天數:超過此天數的
pending/failed/cancelled紀錄會在每日 04:15 自動清除(最少 7 天)。 - 啟用除錯模式:將每一次與 OPay 的請求、回應內容寫入
internal_data/yucts_opay_debug.log,可用於診斷 CheckMacValue 不符等問題;上線後請關閉。- 日誌不會寫入 XenForo「伺服器錯誤日誌」,僅寫入專屬檔案,避免污染錯誤頁面。
進入 後台 → OPay 歐付寶,可看到三個子頁面:
| 動作 | 說明 |
|---|---|
| 訂單列表 | 可依「商店訂單編號」、「會員」、「狀態」搜尋並分頁。 |
| 檢視訂單 | 顯示完整訂單欄位、診斷資訊區(本筆交易實際使用的服務商/環境/加密類型/API 端點/廠商後台連結)、最近一次 OPay 回傳資料、與該訂單相關的 XF 付款日誌。 |
| 編輯 | 可寫入後台備註(不影響 OPay 訂單本身)。 |
| 手動成立訂單 | 將狀態強制設為「已付款」,並透過 XF 標準流程觸發升級開通 / 商品交付。只能對 pending 或 failed 狀態執行。 |
| 手動取消訂單 | 將狀態改為「已取消」,並寫入交易記錄。只能對 pending 或 failed 狀態執行。 |
| 申請退款 | 對信用卡呼叫 DoAction(Action=R)、對 ATM/CVS 呼叫 AioChargeback。 |
| 查詢 OPay | 即時打 QueryTradeInfo,回傳結果會寫入 extra_info.last_query;若 OPay 已返回 TradeNo 但本機尚未保存會自動補上;若 OPay 已標記已付款但本機仍 pending(S2S callback 漏接)會自動同步狀態。 |
顯示 xf_payment_provider_log 中所有 provider_id = 'opay' 的紀錄,包括 OPay 主動 callback、後台手動操作。
最有用的排錯工具。選擇一個 OPay 付款設定檔,按下「送出測試查詢」:
- 後端自動產生一個刻意不存在的
MerchantTradeNo(PING + 11 hex) - 以您設定的 HashKey/HashIV/加密類型,向 OPay 送出
QueryTradeInfo/V5 - 顯示原始回應與 CheckMacValue 雙向驗證結果
正常結果:TradeStatus=10200047(查無此訂單)+ CheckMacValue 驗證通過 → 表示您的整合設定 完全正確。
失敗結果:「CheckMacValue 驗證失敗」或「找不到特店」→ 直接告訴您 MerchantID / HashKey / HashIV / 加密類型 哪裡有錯,免去反覆送真實訂單測試。
- 同步寫入
xf_payment_provider_log(與xf_yucts_opay_transaction.extra_info) - 帶上「執行者使用者名稱」與「備註」欄位
- 受
yuctsOpayManage管理員權限保護
[使用者] [XenForo] [OPay]
│
│ 1. 在 /account/upgrades 按下「購買」(AJAX POST)
│ ───────────────────────►│
│ │ 2. PurchaseController → initiatePayment()
│ │ 寫入 OpayTransaction (status=pending)
│ │ 回傳 Redirect → /opay-checkout/{key}/
│ ◄───────────────────────│
│
│ 3. XF AJAX 收到 Redirect → 整頁跳轉到 /opay-checkout/{key}/
│ ───────────────────────►│
│ │ 4. Pub\Controller\Checkout::actionIndex
│ │ 重建 Purchase → buildCheckoutFormData
│ │ 回傳極簡 HTML (跳過 PAGE_CONTAINER) +
│ │ auto-submit form
│ ◄───────────────────────│
│
│ 5. 表單 POST 到 OPay 收銀台
│ ──────────────────────────────────────────────►│
│ │ 使用者完成付款
│ │
│ │ 6a. server-to-server
│ │ ◄────────────────────│ ReturnURL POST 至
│ │ payment_callback.php (CheckMacValue 驗證)
│ │ → completeTransaction → 升級開通
│ │ 回應 1|OK ───────►│
│ │
│ │ 6b. 瀏覽器跨站 POST
│ ◄──────────────────────────────────────────────│ OrderResultURL
│ (/opay-return/{key})
│ 7. 瀏覽器在 /opay-return/{key}/ (公開頁,無需登入)
│ 回傳 HTML 含 meta refresh + JS 同源 GET 跳轉
│ ───────────────────────►│
│ │ → /account/upgrade-purchase (同源 GET,
│ │ cookies 帶得出 → 使用者保持登入)
│ ◄───────────────────────│
▼
為什麼要有 /opay-checkout/{key}/ 與 /opay-return/{key}/ 這兩個中介頁?
-
/opay-checkout/{key}/— XF 內建/account/upgrades的「購買」按鈕是 AJAX 提交並期待 JSON 回應。如果initiatePayment直接回傳含 OPay 表單的 View,AJAX 處理器只會把它當 overlay 處理,自動 submit 永遠不會觸發整頁跳轉。改成回傳 Redirect 後,XF AJAX 會整頁跳轉到這個中介 URL,該頁再用純 HTML form auto-submit 到 OPay。 -
/opay-return/{key}/— OPay 在使用者付款完成後,是用 跨站 POST 302 把瀏覽器導向OrderResultURL。瀏覽器套用SameSite=Lax政策時,不會送出 XF 的 session cookie,使用者會被當成未登入。若直接指向/account/upgrade-purchase就會看到「請先登入」即使使用者原本就有登入。本套件改把OrderResultURL指向「不需要登入」的公開頁/opay-return/{key}/,該頁回應一張極簡 HTML 用 JS / meta refresh 跳回/account/upgrade-purchase;此次跳轉為同源 GET,cookies 會正常送出,使用者保持登入狀態。
安全要點:
- 在第 6a 步(S2S callback)收到回傳時,第一件事就是
CheckMacValue驗證(採hash_equals常數時間比對)。驗證失敗將直接以 HTTP 400 拒絕並寫入交易記錄。 - 金額另以
validateCost()與xf_purchase_request.cost_amount比對,避免攻擊者以小額付款開通大額升級。 validateTransaction()確保同一筆 OPay TradeNo 不會被處理兩次。/opay-return/{key}/只負責跳轉,不更新付款狀態;實際結果以 S2S callback 為準。
src/addons/YUCTS/Opay/
├── addon.json
├── Setup.php # 安裝 / 解除安裝 / 升級
├── Admin/
│ └── Controller/
│ └── Order.php # 後台訂單管理控制器
├── Cron/
│ └── Cleanup.php # 每日清理舊記錄
├── Entity/
│ └── OpayTransaction.php # ORM Entity
├── Finder/
│ └── OpayTransaction.php
├── Install/
│ └── Data/
│ └── MySql.php # 資料表 schema 定義
├── Payment/
│ └── Opay.php # XF 付款服務提供者本體
├── Pub/
│ ├── Controller/
│ │ ├── Checkout.php # /opay-checkout/{key}/ 中介頁
│ │ └── Result.php # /opay-return/{key}/ 公開回傳頁
│ └── View/
│ └── Payment/
│ ├── Initiate.php # 自訂 View:純 HTML auto-submit 至 OPay
│ └── Result.php # 自訂 View:純 HTML 同源 JS 跳回 XF
├── Repository/
│ └── OpayTransaction.php
├── Util/
│ └── DebugLog.php # internal_data/yucts_opay_debug.log 寫入
├── Vendor/
│ ├── Sdk.php # OPay AIO API 輕量封裝
│ └── SdkException.php
├── _data/
│ ├── admin_navigation.xml
│ ├── admin_permission.xml
│ ├── cron.xml
│ ├── option_groups.xml
│ ├── options.xml
│ ├── phrases.xml
│ ├── routes.xml
│ └── templates.xml
└── hashes.json # 套件健康檢查用 SHA-256 清單
倉庫根目錄另附 build/generate-hashes.php:當您修改任何 addon 內檔案後,需要在 commit 前重新產生 hashes.json,否則 XenForo 安裝畫面會跳出「此插件的 hashes.json 文件丟失」或「健康檢查未通過」的警告。
php build/generate-hashes.php該腳本完全比照 XenForo 內建 \XF\Service\AddOn\HashGeneratorService 的演算法(SHA-256,計算前先移除 \r),輸出與官方一致。
xf_yucts_opay_transaction— 本套件建立。xf_payment_provider— 由Setup::installStep2()註冊('opay', 'YUCTS\Opay:Opay', 'YUCTS/Opay')。xf_payment_provider_log— XenForo 內建,本套件以provider_id = 'opay'寫入。
本套件設計時遵循以下原則:
- CheckMacValue 雙向驗證:所有對 OPay 發出與從 OPay 接收的請求,都會以 SHA256 / MD5(依設定)計算並驗證
CheckMacValue。回傳驗證採用hash_equals()進行常數時間比對,避免時序攻擊。 - 金額驗證:回呼處理時除 CheckMacValue 外,另以
validateCost()將TradeAmt與xf_purchase_request.cost_amount做整數比對。 - 防止重複處理:以 XF 內建
validateTransaction()機制(依xf_payment_provider_log之transaction_id+provider_id)防止同一筆 OPay TradeNo 被處理兩次。 - 管理介面權限:所有後台動作(檢視、編輯、手動成立 / 取消 / 退款 / 查詢、連線測試)皆強制
assertAdminPermission('yuctsOpayManage')。 - 表單 CSRF:所有 XF 後台 POST 動作均由
<xf:form>自動帶上 CSRF token。唯一例外是/opay-return/{key}/,明確 overridecheckCsrfIfNeeded()允許 OPay 跨站 POST;此頁不執行任何寫入「使用者升級狀態」的動作,僅依 OPay 回報 RtnCode 並驗證 CheckMacValue 後標記訂單failed,實際付款結果仍以 S2S callback 為準。 - HTTPS 強制:對 OPay API 的 cURL 呼叫啟用
CURLOPT_SSL_VERIFYPEER與CURLOPT_SSL_VERIFYHOST=2。 - SQL 注入防護:所有資料庫操作均透過 XF Entity / Finder / Schema Manager(參數化查詢)執行。
- HashKey / HashIV 防呆:在
verifyConfig與 SDK 兩端皆呼叫trim(),避免使用者貼上憑證時夾帶前/後空白導致 CheckMacValue 永遠對不上。 - 敏感資料:寫入交易日誌、
extra_info前會主動移除CheckMacValue等驗證字段;除錯日誌中 HashKey / HashIV 僅以「前 2 + 中間遮罩 + 後 2 + 長度」呈現。 - 除錯日誌獨立檔案:開啟除錯模式後資料寫入
internal_data/yucts_opay_debug.log,不會塞進 XF 「伺服器錯誤日誌」造成管理員誤判為錯誤。內部目錄internal_data/應已被 XenForo 預設.htaccess拒絕外部直接存取。 - 解除安裝清理:移除套件時,會同步刪除所屬資料表與
xf_payment_profile中以opay為 provider 的紀錄,避免後台殘留無效項目。
建議:上線前請先於測試環境完整跑過一輪「下單 → ATM 取號 → 繳費 → 後台手動成立 → 退款」流程。
Q1. OPay 與 ECPay 綠界差別? A:兩者共用同一 AIO API(甚至參數名稱、CheckMacValue 算法、回傳格式都完全相同),只是 API 主機網址不同。本套件以單一付款設定即可切換,請依您實際申請的服務商選擇。
Q2. 為什麼回呼後使用者沒有自動升級? A:請依序檢查:
- 連線測試先過:後台 → OPay → 連線測試,確認顯示「通過」+
TradeStatus=10200047。若失敗,先解決連線層問題。 - 後台 → OPay 歐付寶 → 訂單管理 → 點開該筆訂單。檢視頁的「診斷資訊」區會明確列出此筆交易實際使用的 API 端點與廠商後台連結,請確認與您要查的 OPay 後台是同一個。
- 若訂單狀態為
pending,按「查詢 OPay 訂單狀態」即時打 QueryTradeInfo;若回應TradeStatus=1(已付款)系統會自動同步狀態並開通升級。若回應TradeStatus=0+ 有 TradeNo,表示 OPay 端有單但使用者未完成付款;若TradeStatus=10200047,表示 OPay 端沒收到此單(請啟用除錯模式查internal_data/yucts_opay_debug.log看 OPay 的拒收原因,例如RtnCode=10100300 IgnorePayment Error)。 - 後台 → OPay 歐付寶 → 交易記錄,看有無
CheckMacValue verify fail之類錯誤;通常是 HashKey/HashIV 錯誤或正式 / 測試環境憑證錯置。
Q3. 可以對 ATM/CVS 退款嗎?
A:可以,但走的是「廠商通知 OPay 退款」(AioChargeback),款項自您的 OPay 餘額退回,不會自動回到買家帳戶——需您另行匯款給買家。信用卡退刷則由 OPay 直接退回原卡。
Q4. 為何不支援定期定額? A:XenForo 內建 User Upgrade 已可由使用者重複續購,且 OPay 定期定額有金額固定的限制,與 XF Recurring 規格契合度低,因此本版本暫不實作。如有需求歡迎於 GitHub 發 Issue 討論。
Q5. 我該選 SHA256 還是 MD5 加密類型? A:強烈推薦 SHA256。OPay 自 2017 年起,所有新申請的特店帳號都預設使用 SHA256,OPay 後台並無「切換 MD5/SHA256」的選項。僅有極少數 2017 年以前申請、且從未升級過的舊特店帳號需要選 MD5。若您不確定,先用 SHA256 試「連線測試」,若顯示「通過」就保持 SHA256;若顯示「CheckMacValue 驗證失敗」再切到 MD5 試。
Q6. 為什麼除錯日誌寫到專屬檔案而不是 XF 伺服器錯誤日誌?
A:先前版本曾把每次 OPay 通訊都用 \XF::logError() 寫入「伺服器錯誤日誌」,每筆都顯示為 ErrorException,會讓管理員以為發生致命錯誤。新版改寫入 internal_data/yucts_opay_debug.log,既能保留診斷資料又不污染錯誤日誌。internal_data/ 已被 XenForo 預設 .htaccess 拒絕外部存取。
- 確認
src/addons/YUCTS/Opay/addon.json存在且未損毀。 - 後台「附加元件」中本套件狀態須為 已啟用。
- 嘗試後台 → 工具 → 重建 → 重建主要快取。
- 進入後台「附加元件」,對本套件按下「升級」即會重新註冊
xf_payment_provider。
- 檢查
HashKey/HashIV是否與目前環境(Stage / Production)相符。 - 檢查您的 web server 是否在中間有對請求做任何 URL Rewrite / Body 改寫(如 mod_security 移除
+)。 - 後台 → 設定 → 選項 → OPay 歐付寶 → 啟用除錯模式;重新測試後檢查
internal_data/yucts_opay_debug.log,內含完整的請求 / 回應 raw 資料。
- 此情形多半發生在使用者瀏覽器套用
SameSite=Lax政策時,OPay 跨站 POST 不會帶出 XF session cookie。 - 本套件 v1.0.0 起預設將
OrderResultURL指向公開的/opay-return/{key}/,由該頁以同源 GET 跳轉回/account/upgrade-purchase,已可避免此問題。 - 若您升級自更舊版本,請:
- 後台 → 工具 → 重建 → 重建路由
- 在 OPay / ECPay 後台「結帳網址」設定中,確認沒有自行覆蓋 OrderResultURL。
這是最關鍵也最常見的情境:本套件「連線測試」可通過(CheckMacValue 演算法、HashKey/HashIV、加密類型、API 端點全部驗證 OK),但使用者點購買 → OPay 短暫顯示頁面 → 沒看到付款表單 → 跳回站內,OPay 後台也查不到訂單(TradeStatus=10200047)。
這代表 SDK 與基本身分驗證沒問題,OPay 是在「checkout 階段」拒收,常見原因:
-
信用卡功能尚未在 OPay 帳號上啟用 — 多數新申請的 OPay 特店帳號只有 ATM / CVS 預設可用,信用卡需另外向 OPay 申請。如果您的「允許的付款方式」只勾了「信用卡」,OPay 會拒收。
- 驗證方式:到後台 → 設定 → 付款方式 → 編輯該 OPay 設定檔 → 勾選 ATM 與 CVS → 儲存 → 重新測試購買,OPay 應該會顯示收銀台選單(ALL 模式)
- 若 ATM / CVS 可以正常進入付款頁、只有信用卡進不去,就是信用卡未啟用,請聯絡 OPay 客服開通
-
回傳 URL 沒有在 OPay 廠商後台白名單中 — 部分嚴格設定的特店帳號會限制 ReturnURL / OrderResultURL 必須事先註冊
- 解法:登入 OPay 廠商後台 → 「系統介接設定」或「回傳網址設定」→ 把您網站的網域(如
https://yourdomain.com)加入白名單
- 解法:登入 OPay 廠商後台 → 「系統介接設定」或「回傳網址設定」→ 把您網站的網域(如
-
特店帳號仍在「資料審核」階段 — 即便能成功收到 QueryTradeInfo 回應,正式環境的 AioCheckOut 必須等到帳號完成所有合約 / 簽證才會開放
- 解法:登入 OPay 廠商後台檢查帳號狀態,必要時聯絡 OPay 客服
-
正式環境用測試卡 — OPay 正式環境只接受真實的信用卡;用測試卡(如 4311-9522-2222-2222)會被銀行端拒絕,OPay 不會建立訂單。請用真實信用卡刷小額(例如 1 元)測試
請依下列順序排查:
- 後台 → OPay → 連線測試 → 確認通過 (✅ 您已通過)
- 修改付款設定檔的「允許的付款方式」→ 勾選所有四種(信用卡 + WebATM + ATM + CVS)→ 儲存
- 重新進入
/account/upgrades點購買 → 觀察 OPay 收銀台是否出現選單 - 分別選 ATM 或 CVS 試試取號(這兩種通常預設啟用且不需真實付款即可確認流程)
- 若 ATM/CVS 可取號但信用卡仍跳回,致電 OPay 客服 02-2655-1775,告知:
「我已完成 API 串接(使用 QueryTradeInfo 可正常驗證 CheckMacValue),但實際送出 AioCheckOut Credit 訂單後 OPay 端不建立訂單,請問是否帳號的信用卡功能尚未啟用?」
這是測試時最常見的「自以為失敗」狀況。請依下列流程排查:
- 後台是否真的查無? 進入後台 → OPay 歐付寶 → 訂單管理 → 點開該筆訂單 → 點「向 OPay 申請查詢 OPay 訂單狀態」(actionQuery)。
- 若回應
TradeStatus=10200047(查無此訂單):表示 OPay 端真的沒有此單,本套件送出時即被拒。請啟用除錯模式重新測試一次,並提供internal_data/yucts_opay_debug.log。 - 若回應
TradeStatus=0(尚未付款) 且TradeNo有值:表示 OPay 端有此單只是使用者尚未完成付款。OPay 廠商後台預設可能僅顯示「已付款」訂單,請:- 切換訂單狀態篩選為「全部」或「未付款」
- 或直接以 OPay 回傳的
TradeNo在 OPay 後台搜尋 - 或以「商店訂單編號」(我們的
YS......) 搜尋
- 若回應
- 後台連結是否正確? 訂單檢視頁右下的「診斷資訊」區會直接列出該筆交易實際使用的 API 端點與對應的廠商後台連結 (OPay 用
vendor.opay.tw、ECPay 用vendor.ecpay.com.tw)。請確認您登入的是同一個。 - 正式環境的信用卡測試: 若您在正式環境用「測試卡號」付款,OPay 會拒絕該筆交易,後台不會收到任何記錄。OPay 測試卡號只能在 Stage 測試環境使用。
- 本套件 v1.0.0 起,若
canPurchase()因「使用者已擁有」而擋下,會自動 fallback 以getPurchaseObject()重建 Purchase,讓使用者完成付款(XF 對重複升級多半是冪等延長到期日)。 - 若您仍卡住,請啟用除錯模式並檢查
internal_data/yucts_opay_debug.log。
核心
- 完整實作 XenForo 2.3
\XF\Payment\AbstractProvider,含initiatePayment/setupCallback/validate*/getPaymentResult/completeTransaction。 - 同時支援 OPay 歐付寶(
payment.opay.tw)與 ECPay 綠界(payment.ecpay.com.tw),可一鍵切換。 - 支援 SHA256(預設)與 MD5 兩種 CheckMacValue 加密類型。
- 支援信用卡 / WebATM / ATM / CVS 四種付款方式;自動依勾選數量決定
ChoosePayment(單選 → 直接該方式;多選 →ALL+ 正確的IgnorePayment)。
後台
- 訂單管理:搜尋、檢視(含診斷資訊區塊)、編輯備註、手動成立、手動取消、退款、即時 QueryTradeInfo 查詢、查詢結果自動回填 TradeNo 與已付款狀態。
- 交易記錄頁。
- 連線測試頁(送出測試 QueryTradeInfo 驗證設定完全正確)。
- 全繁體中文介面,含 OPay 回應欄位中英對照與 TradeStatus 代碼自動翻譯。
- 每日 04:15 排程自動清理過期
pending/failed/cancelled紀錄。
設計
- AJAX 攔截處理:
initiatePayment回傳 Redirect 到/opay-checkout/{key}/中介頁,由該頁吐出純 HTML auto-submit 表單到 OPay,避免被 XF AJAX 處理器當成 overlay 卡住。 - 跨站 cookie 處理:
OrderResultURL指向公開的/opay-return/{key}/,該頁不要求 cookie / 登入,並以同源 GET 跳轉回/account/upgrade-purchase,避免 SameSite=Lax 政策導致使用者「付款後變未登入」。 - OPay 失敗自動標記:當 OPay 透過 OrderResultURL 回報
RtnCode != 1且 CheckMacValue 驗證通過,自動把訂單標記為failed並寫入錯誤碼。 canPurchase()fallback:若使用者已擁有同款升級導致canPurchase失敗,自動改以getPurchaseObject()重建 Purchase,讓使用者完成付款。
安全
- CheckMacValue 雙向驗證(採
hash_equals常數時間比對)。 - HashKey / HashIV 兩端 trim,避免使用者貼上時夾帶空白導致永遠對不上。
- 金額用
validateCost()與xf_purchase_request.cost_amount整數比對。 validateTransaction()防止同筆 OPay TradeNo 被處理兩次。- 所有後台操作受
yuctsOpayManage管理員權限保護。 Pub\Controller\Result明確 overridecheckCsrfIfNeeded()允許 OPay 跨站 POST,不影響其它 XF 路由的 CSRF 保護。
除錯
- 開啟除錯模式時所有 OPay 通訊寫入
internal_data/yucts_opay_debug.log(不污染「伺服器錯誤日誌」)。 - CheckMacValue 計算過程的 raw 字串長度、HashKey/HashIV 遮罩、最終 hash 都會記入除錯日誌。
已知歷史 bug 與修正
IgnorePayment不可塞入 OPay 不認得的方法名(如BARCODE/ApplePay/TWQR,這些是新版 ECPay 才有),否則 OPay 會回RtnCode=10100300 IgnorePayment Error.並拒收訂單。修正後IgnorePayment僅在本套件提供的 4 種付款方式之間取差集。- Phrase 標題只能含一個
.;模板?:表達式必須在{{ }}雙花括號內;filter 名稱是to_upper而非upper。
- 主要支援平台:YUCTS 論壇 https://forum.yucts.com
- 程式問題請於 GitHub Issues 提出。
- 提報問題時請盡可能提供:
- XenForo 版本
- PHP 版本
- 本套件版本
- 是否為 OPay / ECPay、Stage / Production
- 後台 → OPay → 交易記錄 中的對應錯誤訊息(請先去除
MerchantID/HashKey/HashIV等敏感欄位)
本專案以 MIT License 授權釋出。
OPay AIO API 的歸屬及商標權屬於歐付寶第三方支付股份有限公司。ECPay 綠界 AIO API 的歸屬及商標權屬於綠界科技股份有限公司。本套件僅為與其官方 API 介接之第三方整合工具,與兩家公司無從屬關係。