ondrakoupil / csob-eapi-paygate
用于轻松集成ČSOB支付网关的PHP客户端库
Requires
- php: >=5.4.8
- ext-curl: *
- ext-openssl: *
- ondrakoupil/tools: ^1.2.4
Requires (Dev)
- nette/tester: 1.7.2
- ondrakoupil/testing-utils: ~0.0.7
This package is auto-updated.
Last update: 2024-09-13 16:34:01 UTC
README
使用本库可以方便地将ČSOB支付网关集成到您的电商店铺或其他PHP应用中,无需直接操作API、调用方法、验证签名等。
关于支付网关API、密钥生成和支付处理步骤的详细信息,请参阅https://github.com/csob/platebnibrana。测试卡信息在此处wiki
注意注意!很多人经常在这里遇到问题,我最好在这里提出来。 这里使用的是您的私钥和银行的公钥。 不是反过来。不是您的公钥。
更新
ČSOB API 1.9
2022年夏天,银行发布了API版本1.9,除了添加了一些新功能外,还进行了一些更改。因此,如果您在应用程序中使用此库并使用最新版本的地址 GatewayUrl::PRODUCTION_LATEST
,请注意,将库更新到1.9版本将导致API更新到1.9,因此某些功能可能会有所不同。
更新
- One click支付的函数已更改。现在必须调用
paymentOneClickInit()
然后调用paymentOneClickProcess()
- 对于
Payment
对象的paymentInit()
和paymentOneClickInit()
方法,现在可以传递关于客户和整个交易的大量数据。这些数据由银行传递给发卡行,发卡行根据其内部算法决定是否需要使用3D验证。通过传递这些辅助数据,据说可以增加客户的安全性,因为交易更有可能被批准为安全交易,因为它足够符合其先前的行为和在线支付习惯。所有这些新数据都可以通过$payment->setCustomer($customer)
和$payment->setOrder($order)
以及Metadata
命名空间中的类来设置。
默认地址是当前版本的测试支付网关(现在是1.9 - GatewayUrl::TEST_1_9
)。
建议使用包含各个版本API URL的 GatewayUrl 类常量。
$config->url = GatewayUrl::TEST_1_8;
$config->url = GatewayUrl::PRODUCTION_1_9;
$config->url = GatewayUrl::PRODUCTION_LATEST;
安装
最简单的方法是使用Composer安装
composer require ondrakoupil/csob-eapi-paygate
如果您不使用Composer,只需将 dist/csob-client.php
文件复制到某个地方并包含它即可 - 它包含所有必要的类。您可以直接从GitHub 下载此文件,在导出的包中不包含。
使用
除了这个库,您还需要
- 商户ID - 可以在keygen 页面上生成匿名ID,或者使用银行分配的ID
- 签名和验证签名的密钥 - 同样可以在 keygen 中获取。在实施过程中,您只需使用自己的私钥。公钥通过keygen发送给银行,然后您可以将其忽略。
- 银行公钥 - 可以从 ČSOB的GitHub 下载。请注意,测试和正式网关的公钥不同。
库由以下类组成
- Client - 我们将与之交互的主要类
- Config - 通信参数、密钥、Merchant ID等的设置,以及各种默认值
- Payment - 代表一笔支付
- Crypto - 负责签名和验证签名
- 扩展 - 表示扩展的类。可以直接使用 Extension 类,也可以使用各个专门的派生类。
所有类都在命名空间 OndraKoupil\Csob
中,因此需要在文件开头使用 use
,或者总是使用包括命名空间在内的完整类名。这里提供的示例假设您已经使用了 use
。
设置
首先需要创建一个 Config
对象,并设置其中所需值。然后,将此对象传递给 Client
对象,并调用其方法,这些方法对应于 API 通常提供的方法。
$config = new Config( "My Merchant ID", "path/to/my/private/key/file.key", "path/to/bank/public/key.pub", "My shop name", // Adresa, kam se mají zákazníci vracet poté, co zaplatí "https://www.my-eshop.cz/return-path.php", // URL adresa API - výchozí je adresa testovacího (integračního) prostředí, // až budete připraveni přepnout se na ostré rozhraní, sem zadáte // adresu ostrého API. Nezapomeňte také na ostrý veřejný klíč banky. GatewayUrl::TEST_LATEST ); $client = new Client($config);
注意 - 这里使用的是您的私钥和银行的公钥。 也要记住,测试和正式 API 有不同的公钥。
Config 允许设置其他参数和一些默认值,请参阅 文档。
连接测试
为了验证连接是否正常工作并且请求是否正确签名,可以使用 testGetConnection() 和 testPostConnection() 方法,这些方法调用 API 的 echo 方法。
try { $client->testGetConnection(); $client->testPostConnection(); } catch (Exception $e) { echo "Something went wrong: " . $e->getMessage(); }
创建新的支付(payment/init)
要创建新的支付,需要创建一个 Payment
对象,设置所需值,然后将其传递给 paymentInit()。如果一切正常,API 将为支付分配 PayID。这需要保存起来,以后调用其他方法时会用到。
使用 $payment->addCartItem()
添加商品到订单。在当前版本中,支付必须有一个或两个商品,在未来的版本中,这一限制将有所改变。
注意,所有字符串都应该是 UTF-8 编码。如果您使用其他编码,那么在存在变音符号的地方(特别是购物车中的商品名称),需要使用 iconv 函数进行转换。
$payment = new Payment("1234"); $payment->addCartItem("Zakoupená věcička", 1, 10000); $response = $client->paymentInit($payment); $payId = $payment->getPayId(); $payId = $response["payId"];
这是必需的最小值 - 在 $payment 对象中可以设置更多。注意,价格以基本货币单位(分或美分)的百分之一表示,即 10000 表示 100 Kč。
调用 paymentInit() 时,将给 $payment 对象设置其 PayID,可以通过 getter 读取,或者从返回的数组中获取。
可选地,从 API 1.9 开始,可以将包含用户元数据的 Payment 对象传递给 API,这可以简化发卡行对交易的审批。
$customer = new Customer();
$customer->name = 'John Rambo';
$customer->email = 'john@rambo.cz';
$payment->setCustomer($customer);
支付(payment/process)
在成功创建支付后,需要将客户浏览器重定向到由 getPaymentProcessUrl() 生成的支付网关地址。这里还有一个方法 redirectToGateway(),可以直接执行重定向。
$url = $client->getPaymentProcessUrl($payment); redirectBrowserTo($url); // fiktivní funkce pro přesměrování // NEBO $client->redirectToGateway($payment); terminateApp(); // fiktivní funkce pro ukončení skriptu
可以作为参数使用前面调用中使用的 $payment 对象,或者作为普通字符串的 PayID。
客户返回
客户在支付网关输入所需信息并验证和批准后,网关将客户返回到 Return URL,该 URL 您已在 Config 或 Payment 对象中设置。在这个 URL 上,您应该使用 paymentStatus() 验证支付状态,或者简单地使用 receiveReturningCustomer() 方法处理传入的数据,该方法将检查传入数据的签名并从中提取有用值。
$response = $client->receiveReturningCustomer(); if ($response["paymentStatus"] == 7) { // nebo také 4, záleží na nastavení closePayment echo "Platba proběhla, děkujeme za nákup."; } else { echo "Něco se pokazilo, sakra..."; }
支付状态的详细信息请参阅 支付网关 wiki。
验证支付状态(payment/status)
随时可以简单地了解支付当前状态
$status = $client->paymentStatus($payId);
如果需要比状态编号更多的详细信息,将第二个参数 $returnStatusOnly 设置为 false,方法将返回包含不同详细信息的数组。
确认、取消、退款
paymentReverse() 方法将取消尚未处理的支付,paymentClose() 确认支付,paymentRefund() 将已完成的支付退还给付款人。
请注意,支付必须处于正确的状态,否则将引发错误并抛出异常。如果将第二个参数 $ignoreWrongPaymentStatusError
设置为 true
,则将静默忽略此特定错误,并且该方法仅返回 null
。所有其他错误继续抛出异常。
$client->paymentReverse($payId); $client->paymentClose($payId); $client->paymentRefund($payId);
从API 1.5开始,支付网关允许通过 paymentRefund()
方法仅部分退款,或者通过 paymentClose()
方法确认小于最初授权金额的交易。这些方法的第三个参数可以设置要退回的金额,单位为基本货币的 setin(请注意!)
// Potvrdit transakci jen na 100 Kč $client->paymentClose($payId, false, 10000); // Vrátit 100 Kč $client->paymentRefund($payId, false, 10000);
paymentRefund()
在测试环境中有时会返回HTTP状态500,从而导致抛出异常。根据 此问题,这是支付网关测试环境中的bug,目前尚未解决。
客户信息(customer/info)
customerInfo()
方法检查具有指定ID(例如电子邮件)的客户是否曾经使用信用卡支付,如果是,则可以采取某些措施(例如打印个性化消息)。
$hasCards = $client->customerInfo($someCustomerId); if ($hasCards) { echo "Chcete zase zaplatit kartou?"; } else { echo "Nabízíme tyto možnosti platby: ..."; }
API 1.8将此方法重命名为 echo/customer
,库将自动选择合适的端点,但在PHP中始终调用 customerInfo()
支付/结账
这是一个尚未公开的功能。它允许在您的网站上显示一个简洁的iframe,并在其中完成整个支付和订单处理,而不是跳转到支付网关。
要激活此功能,您需要联系ČSOB并请求激活此功能。在此期间,您还将收到更详细的技术文档。
功能激活后,您可以调用 payment/checkout
而不是 payment/process
。
如果您的 merchantId
没有激活此功能,网关将显示错误消息。
$url = $client->getPaymentCheckoutUrl($payment, $oneClickPaymentCheckbox); redirect($url);
$payment
可以是 Payment 对象或简单的 PayID,与其他方法类似。
对于 $oneClickPaymentCheckbox
,请使用在PHPDoc中描述的方法的其中一个选项。
其他参数在方法文档中描述。
感谢 @rootpd。
支付按钮
对于API < 1.8,使用 paymentButton() 方法进行支付,对于API >= 1.8,使用 buttonInit() 方法。这两个方法的详细参数在各自的文档中。
这些方法返回一个包含不同数据的数组,包括 redirect
,其中包含要将用户重定向到的地址。因此,不要使用 redirectToGateway() 或类似方法,而是直接将用户重定向到银行返回的地址。
重复支付(一键支付)
从API 1.5开始,可以进行重复支付。具体如何操作,请参阅 ČSOB Wiki。在API 1.9版本中,操作大致如下
- 您将让客户授权支付模板,方法是在调用
paymentInit()
之前将 Payment 对象的$payment->setOneClickPayment(true)
设置为 true - 然后客户将输入卡号,密码并执行 3D 验证,就像普通支付一样
- 然后您将保存 PayID,以便您可以引用此授权交易。PayID 将在这里作为某种交易模板ID的作用,您可以稍后无需客户即可重复此交易。
- 从API版本 1.8开始,存在
paymentOneClickEcho()
用于验证原始 PayID 是否仍然有效。 - 然后您可以随时调用带有原始交易 PayID 和新 Payment 对象的
paymentOneClickInit()
方法。这将创建新的支付。随后调用paymentOneClickProcess()
(在API 1.8和更早版本中是paymentOneClickStart()
)以执行支付 - 新的支付将获得其自己的 PayID,可以像处理任何其他支付一样处理它
- 从API 1.9开始,可以通过
$payment->setCustomer()
和$payment->setOrder()
添加元数据,就像在paymentInit
中做的那样
日志记录
Client
内置简单日志记录。一个日志用于业务级别消息(例如:“XYZ付款成功”),另一个日志(traceLog)记录与API的详细通信和各种技术细节。
可以简单地输入要记录消息的文件路径,或者提供一个回调函数,将消息转发到应用程序使用的任何日志记录器。可以在Client对象的构造函数或setter中设置日志。
$client->setLog("some/file/log.txt"); $client->setTraceLog(function($message) use ($myLogger) { $myLogger->log($message); });
自定义请求
如果您需要发送请求到本库未特别实现API方法(例如,Masterpass、ApplePay或MallPay方法),可以使用customRequest()方法。只需要注意输入数据的顺序和响应数据在签名中的顺序。
$client->customRequest( // URL, jenom konec za společnou adresou API, např. "payment/init" $methodUrl, // Array se vstupními daty. Pořadí položek v array je důležité. // Na vhodná místa lze vložit prázdné dttm a merchantId, doplní se automaticky. $inputPayload, // Array s názvy políček v odpovědi v požadovaném pořadí dle dokumentace. // U vnořených objektů a polí lze pracovat s tečkou. // Například: array('payId', 'dttm', 'resultCode', 'resultMessage', 'redirect.method', 'redirect.url') $expectedOutputFields = array(), // Volitelně nějaké extensions $extensions = array(), $method = "POST", // Zalogovat vždy podrobně celou návratovou hodnotu z API? $logOutput = false, // Pokud z nějakého důvodu selhává ověření podpisu, lze ho takto úplně deaktivovat. // Nicméně pak je nutné ručně takovou situaci ošetřit. $ignoreInvalidReturnSignature = false )
在$expectedOutputFields
中,某个值可以以?开头,在这种情况下,它被视为非必需的,如果银行响应中没有包含,则不会包含在签名基础中。如果没有以?开头,签名基础可以包含空字符串。
扩展
扩展通过Extension类和可选的独立类(目前仅为EET)实现。可以将此类对象附加到每个调用的方法中。然后将附加数据添加到请求中,并自动验证响应签名。
每个扩展都有自己的扩展ID(由银行文档定义)。
如果扩展需要向请求添加更多数据,需要调用setInputData()
并作为数组将附加数据传递到请求中。数组中元素的顺序很重要,根据顺序将构造签名字符串和签名。请始终查阅文档,了解参数的顺序,并遵守该顺序。字段dttm
和extension
可以留空(false或null),值将自动填充,但需要将它们放置在数组中的适当位置。
作为替代,可以分离类并实现自己的getRequestSignatureBase()
方法,该方法应返回作为签名字符串基础的字符串。
如果扩展向API响应的响应添加数据,可以通过getResponseData()
方法访问这些数据。
可以通过setExpectedResponseKeysOrder()
设置验证响应签名的验证。向此方法传递一个包含响应字段名称的数组,这些字段在签名字符串中的顺序与签名的顺序相同。或者,可以将Extension分离到自己的类中并实现自己的verifySignature()
方法。
如果无法验证响应签名,可以通过setStrictSignatureVerification(false)
禁用特定扩展的签名验证。调用API方法后,可以通过isSignatureCorrect()
检查签名是否正确,如果不正确,可以自行解决。
对于单个方法调用,可以传递多个扩展,只需将Extension对象数组传递给Client对象的相应参数即可,而不仅仅是单个对象。
日期扩展
如果启用了trxDates扩展,可以在paymentStatus()方法中传递DatesExtension类的对象。调用该方法后,可以从DatesExtension读取所需数据作为DateTime对象。
$extension = new DatesExtension(); $status = $client->paymentStatus($payment, true, $extension); echo $extension->getCreatedDate()->format("j. n. Y");
可用方法有getCreatedDate()
、getSettlementDate()
和getAuthDate()
,它们返回DateTime或null,如果响应中没有提及该日期。请注意,settlementDate的精度仅到天,不是到秒。
卡号扩展
如果启用了maskClnRP扩展,可以在paymentStatus()方法中传递CardNumberExtension类的对象。调用该方法后,可以从CardNumberExtension读取卡号的掩码和其过期日期。但请注意,此扩展仅适用于“一键”支付。
$extension = new CardNumberExtension(); $status = $client->paymentStatus($payment, true, $extension); echo $extension->getMaskedCln() . ' ' . $extension->getExpiration();
可用方法有getMaskedCln()
、getLongMaskedCln()
和getExpiration()
EET
EET自API 1.9版本已取消。太好了 😀
如果出于某种原因需要使用,则需要使用API 1.8或1.7。
有问题?
如果您遇到了bug,某个功能不正常或者有改进建议,请添加问题或直接联系我,请放心 :-)