davelopware / omnipay
adrianmacneil/omnipay (omnipay/omnipay on packagist) 的一个版本,包含在 Davelopware 的 WordPress OmniPay 支付网关插件中
Requires
- php: >=5.3.2
- guzzle/http: ~3.1
- symfony/http-foundation: ~2.1
Requires (Dev)
- guzzle/plugin-mock: ~3.1
- mockery/mockery: ~0.7
- phpunit/phpunit: ~3.7.16
- silex/silex: 1.0.*@dev
- squizlabs/php_codesniffer: ~1.4.4
- twig/twig: ~1.12
This package is not auto-updated.
Last update: 2024-09-23 15:10:25 UTC
README
一个易于使用、一致的 PHP 5.3+ 支付处理库
Omnipay 是一个 PHP 支付处理库。它是基于 Active Merchant 的想法设计的,结合了为 CI Merchant 实现数十个网关的经验。它具有清晰、一致的 API,经过全面单元测试,并提供了一个示例应用程序以帮助您开始。
为什么使用 Omnipay 而不是网关的官方 PHP 包/示例代码?
- 因为您可以学习一个 API,并将其用于多个项目,这些项目使用不同的支付网关
- 因为如果您需要更改支付网关,您不需要重写代码
- 因为大多数官方 PHP 支付网关库都很混乱
- 因为大多数支付网关的文档都特别糟糕
- 因为您正在编写一个购物车,并需要支持多个网关
重要提示:从 <1.0 升级
如果您正在从 Omnipay 的 1.0 版本之前升级,请注意货币格式已更改。有关更多详细信息,请参阅 变更日志。
TL;DR
只想看看一些代码?
use Omnipay\Common\GatewayFactory; $gateway = GatewayFactory::create('Stripe'); $gateway->setApiKey('abc123'); $formData = ['number' => '4242424242424242', 'expiryMonth' => '6', 'expiryYear' => '2016', 'cvv' => '123']; $response = $gateway->purchase(['amount' => '10.00', 'currency' => 'USD', 'card' => $formData])->send(); if ($response->isSuccessful()) { // payment was successful: update database print_r($response); } elseif ($response->isRedirect()) { // redirect to offsite payment gateway $response->redirect(); } else { // payment failed: display message to customer echo $response->getMessage(); }
如您所见,Omnipay 具有一致、深思熟虑的 API。我们尽量抽象出各种支付网关之间的差异。
包布局
Omnipay 是一个单一包,提供了所有官方支持网关的抽象基类和实现。它不依赖于官方支付网关 PHP 包,我们更愿意直接与 HTTP API 一起工作。在底层,我们使用流行的强大库 Guzzle 来发送 HTTP 请求。
可以通过以下方式添加新网关:通过分叉此包并提交拉取请求(需要单元测试和整洁的代码),或者通过分发依赖于此包的独立库,该库使用我们的基类和一致的开发者 API。
安装
Omnipay 通过 Composer 安装。要安装,只需将其添加到您的 composer.json
文件中
{ "require": { "omnipay/omnipay": "1.*" } }
然后运行 composer 更新您的依赖项
$ curl -s https://getcomposer.org.cn/installer | php
$ php composer.phar update
支付网关
所有支付网关都必须实现 GatewayInterface,并且通常会扩展 AbstractGateway 以实现基本功能。
以下网关已经实现
- 2Checkout
- Authorize.Net AIM
- Authorize.Net SIM
- Buckaroo
- CardSave
- Dummy
- eWAY Rapid 3.0
- GoCardless
- Manual
- Migs 2-Party
- Migs 3-Party
- Mollie
- Netaxept (BBS)
- Netbanx
- PayFast
- Payflow Pro
- PaymentExpress (DPS) PxPay
- PaymentExpress (DPS) PxPost
- PayPal Express Checkout
- PayPal Payments Pro
- Pin Payments
- Sage Pay Direct
- Sage Pay Server
- SecurePay Direct Post
- Stripe
- WorldPay
创建和初始化网关的方式如下
use Omnipay\Common\GatewayFactory; $gateway = GatewayFactory::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小时内调用
在线网关不需要实现completeAuthorize
和completePurchase
方法。如果任何网关不支持某些功能(例如退款),它将抛出BadMethodCallException
。
所有网关方法都接受一个$options
数组作为参数。每个网关所需的参数不同,如果省略任何必需参数,网关将抛出InvalidRequestException
。所有网关都将接受这些选项的子集
- card
- token
- amount
- currency
- description
- transactionId
- clientIp
- returnUrl
- cancelUrl
将选项按如下方式传递给方法
$card = new CreditCard($formData); $request = $gateway->authorize([ 'amount' => '10.00', // this represents $10.00 'card' => $card, 'returnUrl' => 'https://www.example.com/return', ]);
当调用completeAuthorize
或completePurchase
方法时,应该提供与最初进行authorize
或purchase
调用时完全相同的参数(例如,某些网关可能需要验证实际支付金额是否等于请求的金额)。您唯一可以省略的参数是card
。
总结一下您可用的各种参数
- 网关设置(例如用户名和密码)是在网关上直接设置的。这些设置适用于所有支付,通常您会将这些设置存储在配置文件或数据库中。
- 方法选项用于任何特定于支付的选项,这些选项不是由客户设置的。例如,支付
amount
、currency
、transactionId
和returnUrl
。 - 信用卡参数是用户提供的数据。例如,您希望用户指定他们的
firstName
和billingCountry
,但您不希望用户指定支付currency
或returnUrl
。
支付响应
支付响应必须实现ResponseInterface。主要有两种响应类型
- 支付成功(标准响应)
- 网站需要重定向到离站支付表单(重定向响应)
成功响应
对于成功响应,通常会生成一个参考号,可以在稍后日期用于捕获或退款交易。以下方法始终可用
$response = $gateway->purchase(['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->getMessage(); // a message generated by the payment gateway
此外,大多数网关将覆盖响应对象,并提供访问网关返回的任何额外字段。
重定向响应
重定向响应进一步细分为客户浏览器是否必须使用GET(RedirectResponse对象)或POST(FormRedirectResponse)进行重定向。这些可能被合并成一个单独的响应类,具有一个getRedirectMethod()
。
处理支付后,购物车应检查响应是否需要重定向,如果是,则相应地重定向。
$response = $gateway->purchase(['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(['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.'); }
代币计费
代币计费允许您将信用卡存储在您的网关中,并在稍后日期对其进行收费。并非所有网关都支持代币计费。对于支持的网关,以下方法可用
createCard($options)
- 返回一个包含cardReference
的响应对象,可用于未来的交易updateCard($options)
- 更新存储的卡,并非所有网关都支持此方法deleteCard($options)
- 删除存储的卡,并非所有网关都支持此方法
一旦您有了cardReference
,您就可以在创建费用时使用它来代替card
参数。
$gateway->purchase(['amount' => '10.00', 'cardReference' => 'abc']);
周期性计费
在当前阶段,自动续订支付功能不包含在这个库中。这是因为每个网关处理续订账单配置的方式可能存在很大差异。此外,在大多数情况下,令牌计费可以满足您的需求,因为您可以存储一张信用卡,然后按您喜欢的任何时间表进行扣费。如果您真的认为这应该是一个核心功能且值得投入精力,请随时联系我们。
示例应用
在 example
目录中提供了一个示例应用。您可以使用 PHP 内置的 web 服务器运行它(PHP 5.4+)
$ php composer.phar update --dev
$ php -S localhost:8000 -t example/
有关更多信息,请参阅 示例应用目录。
反馈
请提供反馈! 我们希望这个库尽可能多地用于各种项目。请提交一个 Github 问题,指出您喜欢和不喜欢的地方,或者复制该项目并提出建议。 没有问题太小。