paidyet / omnipay
PaidYET 对 Omnipay 支付处理库的驱动程序
Requires
- php: ^7.2|^8.0
- omnipay/common: ^3.1
- php-http/discovery: ^1.14
- php-http/guzzle7-adapter: ^1
Requires (Dev)
- omnipay/tests: ^3|^4
This package is not auto-updated.
Last update: 2024-09-20 21:57:57 UTC
README
一个易于使用、一致的 PHP 支付处理库
Omnipay 是一个 PHP 支付处理库。它是基于来自 Active Merchant 的想法以及为 [CI Merchant] 实现的数十个网关的经验而设计的。它有一个清晰且一致的 API,完全经过单元测试,甚至还提供了一个示例应用程序,以便您开始。
为什么使用 Omnipay 而不是网关的官方 PHP 包/示例代码?
- 因为您可以学习一个 API,并在使用不同网关的多个项目中使用它
- 因为如果您需要更改网关,您不需要重写代码
- 因为大多数官方 PHP 支付网关库都很混乱
- 因为大多数网关的文档都非常好
- 因为您正在编写一个购物车并需要支持多个网关
安装
Omnipay 通过 Composer 安装。对于大多数用途,您需要要求 league/omnipay
和一个单独的网关
composer require paidyet/omnipay
支付网关
所有支付网关都必须实现 GatewayInterface,并且通常通过 AbstractGateway 扩展基本功能。
以下网关可用
创建和初始化网关的方式如下
use Omnipay\Omnipay; $gateway = Omnipay::create('PayPal_Express'); $gateway->setUsername('adrian'); $gateway->setPassword('12345');
大多数设置都是针对网关特定的。如果您需要查询网关以获取可用设置的列表,您可以调用 getDefaultParameters()
$settings = $gateway->getDefaultParameters(); // default settings array format: array( 'username' => '', // string variable 'testMode' => false, // boolean variable 'landingPage' => array('billing', 'login'), // enum variable, first item should be treated as default );
通常,大多数支付网关可以分为两种类型之一
- 离线网关,如 PayPal Express,其中客户被重定向到第三方网站以输入支付详情
- 在线(商家托管)网关,如 PayPal Pro,其中客户在您的网站上输入他们的信用卡详情
但是,有一些网关,如 Sage Pay Direct,您可以在网站上获取信用卡详情,然后可选地重定向,如果客户的卡支持 3D Secure 认证。因此,没有必要区分这两种类型的网关(除了它们支持的方法之外)。
信用卡/支付表单输入
用户表单输入被引导到 CreditCard 对象。这提供了一种安全的方式来接受用户输入。
CreditCard
对象有以下字段
- firstName
- lastName
- number
- expiryMonth
- expiryYear
- startMonth
- startYear
- cvv
- issueNumber
- type
- billingAddress1
- billingAddress2
- billingCity
- billingPostcode
- billingState
- billingCountry
- billingPhone
- shippingAddress1
- shippingAddress2
- shippingCity
- shippingPostcode
- shippingState
- shippingCountry
- shippingPhone
- company
即使离线网关也使用 CreditCard
对象,因为通常您需要将客户账单或运输详情传递给网关。
可以通过构造函数使用不受信任的用户输入来初始化CreditCard
对象。传递给构造函数的任何未识别的字段将被忽略。
$formInputData = array( 'firstName' => 'Bobby', 'lastName' => 'Tables', 'number' => '4111111111111111', ); $card = new CreditCard($formInputData);
您还可以直接将表单数据数组传递给网关,网关将为您创建一个CreditCard
对象。
可以使用getter和setter访问CreditCard字段。
$number = $card->getNumber(); $card->setFirstName('Adrian');
如果您提交显然无效的信用卡详情(缺少必填字段或通过Luhn检查失败的数量),将抛出InvalidCreditCardException。在将详情提交给网关之前,您应该使用框架的验证库验证卡详情,以避免不必要的API调用。
对于站内支付网关,以下卡字段通常是必需的
- firstName
- lastName
- number
- expiryMonth
- expiryYear
- cvv
您也可以通过调用Helper::validateLuhn($number)
来验证卡号是否使用Luhn算法。
网关方法
网关实现的主要方法有
authorize($options)
- 在客户的卡上授权一定金额completeAuthorize($options)
- 处理授权后的网关返回capture($options)
- 捕获之前授权的金额purchase($options)
- 授权并立即在客户的卡上捕获一定金额completePurchase($options)
- 处理购买后的网关返回refund($options)
- 退款已处理的交易void($options)
- 通常只能在提交交易后24小时内调用acceptNotification()
- 将来自站外网关的请求转换为用于进一步处理的通用通知对象createCard
- 获取一个可以用于未来支付的卡参考。例如,这可能在月度账单场景中使用。
站内网关不需要实现completeAuthorize
和completePurchase
方法。未接收支付通知的网关不需要实现acceptNotification
。如果任何网关不支持某些功能(如退款),它将抛出BadMethodCallException
。
除acceptNotification
之外的所有网关方法都接受一个$options
数组作为参数。该acceptNotification
方法不接受任何参数,并将隐式访问HTTP URL变量或POST数据。每个网关在所需的参数方面都有所不同,如果省略任何必需参数,网关将抛出InvalidRequestException
。所有网关都将接受这些选项的子集
- card
- token
- amount
- currency
- description
- transactionId
- clientIp
- returnUrl
- cancelUrl
将选项按如下方式传递到方法中
$card = new CreditCard($formData); $request = $gateway->authorize(array( 'amount' => '10.00', // this represents $10.00 'card' => $card, 'returnUrl' => 'https://www.example.com/return', ));
在调用completeAuthorize
或completePurchase
方法时,应提供与您最初进行authorize
或purchase
调用时完全相同的参数(例如,某些网关可能需要验证实际支付的金额等于请求的金额)。您可以省略的唯一参数是card
。
以下是对您可用的各种参数的总结
- 网关设置(例如用户名和密码)直接在网关上设置。这些设置适用于所有付款,通常您会将其存储在配置文件或数据库中。
- 方法选项用于任何付款特定的选项,这些选项不是由客户设置的。例如,付款
amount
、currency
、transactionId
和returnUrl
。 - CreditCard参数是用户提供的数据。例如,您希望用户指定他们的
firstName
和billingCountry
,但您不希望用户指定付款currency
或returnUrl
。
支付响应
支付响应必须实现 ResponseInterface 接口。响应主要有两种类型
- 支付成功(标准响应)
- 网站需要将用户重定向到站外支付表单(重定向响应)
成功响应
对于成功响应,通常会产生一个引用,该引用可以在以后用于捕获或退款交易。以下方法始终可用
$response = $gateway->purchase(array('amount' => '10.00', 'card' => $card))->send(); $response->isSuccessful(); // is the response successful? $response->isRedirect(); // is the response a redirect? $response->getTransactionReference(); // a reference generated by the payment gateway $response->getTransactionId(); // the reference set by the originating website if available. $response->getMessage(); // a message generated by the payment gateway
此外,大多数网关将覆盖响应对象,并提供访问网关返回的任何额外字段。如果支付授权可重用,网关将实现 $response->getCardReference();
。此方法从3.1.1版本开始始终可用(但可能返回NULL)
重定向响应
重定向响应进一步分为是否客户的浏览器必须使用GET(RedirectResponse对象)或POST(FormRedirectResponse)进行重定向。这些可能被合并为单个响应类,并具有一个 getRedirectMethod()
方法。
处理完支付后,购物车应该检查响应是否需要重定向,如果是,则相应地重定向
$response = $gateway->purchase(array('amount' => '10.00', 'card' => $card))->send(); if ($response->isSuccessful()) { // payment is complete } elseif ($response->isRedirect()) { $response->redirect(); // this will automatically forward the customer } else { // not successful }
客户不会自动被转发,因为通常购物车或开发者会希望自定义重定向方法(或者如果支付处理发生在AJAX调用中,他们可能希望返回JS到浏览器)。
要显示自己的重定向页面,只需在响应对象上调用 getRedirectUrl()
,然后相应地显示即可
$url = $response->getRedirectUrl(); // for a form redirect, you can also call the following method: $data = $response->getRedirectData(); // associative array of fields which must be posted to the redirectUrl
错误处理
您可以通过在响应对象上调用 isSuccessful()
来测试是否为成功响应。如果与网关通信出现错误,或者您的请求明显无效,则会抛出异常。通常,如果网关不抛出异常,但返回不成功的响应,则应该将此消息显示给客户。如果抛出异常,则可能是您的代码中的错误(缺少必填字段),或者与网关通信出现错误。
您可以通过将整个请求包裹在try-catch块中来处理这两种情况
try { $response = $gateway->purchase(array('amount' => '10.00', 'card' => $card))->send(); if ($response->isSuccessful()) { // mark order as complete } elseif ($response->isRedirect()) { $response->redirect(); } else { // display error to customer exit($response->getMessage()); } } catch (\Exception $e) { // internal error, log exception and display a generic message to the customer exit('Sorry, there was an error processing your payment. Please try again later.'); }
测试模式和开发者模式
大多数网关允许您设置一个沙盒或开发者账户,该账户使用不同的URL和凭据。其中一些还允许您对实时站点进行测试交易,这不会导致实时交易。
仅实现开发者账户的网关(大多数网关)将其称为testMode。但是,Authorize.net实现了两种模式,并将其称为developerMode。
在实现多个网关时,您应该使用类似以下的结构
if ($is_developer_mode) { if (method_exists($gateway, 'setDeveloperMode')) { $gateway->setDeveloperMode(TRUE); } else { $gateway->setTestMode(TRUE); } }
令牌计费
令牌计费允许您将信用卡存储在您的网关中,并在以后进行计费。并非所有网关都支持令牌计费。对于支持的网关,以下方法可用
createCard($options)
- 返回一个包含cardReference
的响应对象,该对象可用于未来的交易updateCard($options)
- 更新存储的信用卡,并非所有网关都支持此方法deleteCard($options)
- 删除存储的信用卡,并非所有网关都支持此方法
一旦您有了 cardReference
(应通过getCardReference从响应对象中获取),您可以使用它而不是 card
参数来创建计费
$gateway->purchase(array('amount' => '10.00', 'cardReference' => 'abc'));
在许多情况下,createCard操作也会同时处理初始支付。在这些情况下,您应该在createCard选项中传入'操作'('authorize'或'purchase')。
周期性计费
在此阶段,自动周期性支付功能不在此库的范围内。这是因为每个网关处理周期性账单配置可能存在很大差异。此外,在大多数情况下,令牌计费可以满足您的需求,您可以将信用卡存储起来,然后按您喜欢的任何时间表进行收费。如果您真的认为这应该是一个核心功能并且值得努力,请随时联系我们。
接收通知
一些网关(例如Cybersource,GoPay)提供HTTP通知来通知商户支付完成(或通常状态)。为了帮助处理此类通知,acceptNotification()
方法将从HTTP请求中提取交易参考和支付状态,并返回一个通用的NotificationInterface
。
$notification = $gateway->acceptNotification(); $notification->getTransactionReference(); // A reference provided by the gateway to represent this transaction $notification->getTransactionStatus(); // Current status of the transaction, one of NotificationInterface::STATUS_* $notification->getMessage(); // Additional message, if any, provided by the gateway // update the status of the corresponding transaction in your database
注意:一些早期的网关使用completeAuthorize
和completePurchase
消息来处理接收到的通知。这些正在被转换,complete*
消息已被弃用。它们将在OmniPay 2.x中不被移除,但建议在方便时切换到acceptNotification
消息。例如Sage Pay Server completeAuthorize现在由acceptNotification
处理,请参见acceptNotification。
示例应用
示例应用在omnipay/example仓库中提供。您可以使用PHP内置的Web服务器(PHP 5.4+)运行它。
$ php composer.phar update --dev
$ php -S localhost:8000
有关更多信息,请参阅Omnipay示例应用。
支持
如果您在Omnipay中遇到一般性问题,我们建议您在Stack Overflow上发帖。请务必添加omnipay标签,以便容易找到。
如果您想了解最新的发布公告,讨论项目的想法或提出更详细的问题,还有一个您可以订阅的邮件列表。
如果您认为您发现了一个bug,请使用相应包的GitHub问题跟踪器报告它,或者更好的是,fork库并提交pull请求。
安全
如果您发现任何与安全相关的问题,请通过barryvdh@gmail.com发送电子邮件,而不是使用问题跟踪器。
反馈
请提供反馈!我们希望使这个库尽可能多地应用于各种项目中。请前往邮件列表并指出您喜欢和不喜欢的地方,或者fork项目并提出建议。没有问题太小。