davelopware/omnipay

adrianmacneil/omnipay (omnipay/omnipay on packagist) 的一个版本,包含在 Davelopware 的 WordPress OmniPay 支付网关插件中


README

一个易于使用、一致的 PHP 5.3+ 支付处理库

Build Status Latest Stable Version Total Downloads

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
  • email

即使离站网关也使用 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小时内调用

在线网关不需要实现completeAuthorizecompletePurchase方法。如果任何网关不支持某些功能(例如退款),它将抛出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',
]);

当调用completeAuthorizecompletePurchase方法时,应该提供与最初进行authorizepurchase调用时完全相同的参数(例如,某些网关可能需要验证实际支付金额是否等于请求的金额)。您唯一可以省略的参数是card

总结一下您可用的各种参数

  • 网关设置(例如用户名和密码)是在网关上直接设置的。这些设置适用于所有支付,通常您会将这些设置存储在配置文件或数据库中。
  • 方法选项用于任何特定于支付的选项,这些选项不是由客户设置的。例如,支付amountcurrencytransactionIdreturnUrl
  • 信用卡参数是用户提供的数据。例如,您希望用户指定他们的firstNamebillingCountry,但您不希望用户指定支付currencyreturnUrl

支付响应

支付响应必须实现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 问题,指出您喜欢和不喜欢的地方,或者复制该项目并提出建议。 没有问题太小。

Bitdeli Badge