xepan/omnipay

包含 Omnipay 支付处理库以及所有官方支持的网关

维护者

详细信息

github.com/xepan/omnipay

主页

源代码

安装量: 3,252

依赖者: 1

建议者: 0

安全性: 0

星标: 0

关注者: 3

分支: 928

类型:元包

v2.3.2 2016-05-07 13:59 UTC

README

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

Build Status Latest Stable Version Total Downloads

Omnipay 是一个 PHP 支付处理库。它基于来自 Active Merchant 的想法以及为 [CI Merchant] 实现数十个网关的经验而设计。它具有清晰且一致的 API,完全经过单元测试,并提供了一个示例应用程序以帮助您入门。

为什么使用 Omnipay 而不是网关的官方 PHP 包/示例代码?

  • 因为您可以学习一个 API 并将其用于使用不同支付网关的多个项目
  • 因为如果您需要更改支付网关,您不需要重写您的代码
  • 因为大多数官方 PHP 支付网关库都很混乱
  • 因为大多数支付网关的文档都特别糟糕
  • 因为您正在编写购物车并需要支持多个网关

重要提示:从 < 2.0 升级

如果您正在从 Omnipay 的预 2.0 版本升级,请注意该项目已拆分为多个包。网关实例的创建方式也进行了一些更改。有关更多详细信息,请参阅 完整发行说明

TL;DR

只想看一些代码吗?

use Omnipay\Omnipay;

$gateway = Omnipay::create('Stripe');
$gateway->setApiKey('abc123');

$formData = array('number' => '4242424242424242', 'expiryMonth' => '6', 'expiryYear' => '2016', 'cvv' => '123');
$response = $gateway->purchase(array('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 是一系列包的集合,它们都依赖于 omnipay/common 包以提供一致的用户界面。没有对官方支付网关 PHP 包的依赖 - 我们更喜欢直接与 HTTP API 一起工作。在底层,我们使用流行的强大库 Guzzle 来发送 HTTP 请求。

可以通过克隆现有包的布局来创建新的网关。在选择包名称时,请不要使用 omnipay 厂商前缀,因为这表示它受到官方支持。您应该使用自己的用户名作为厂商前缀,并在包名称前添加 omnipay- 以使其明确您的包与 Omnipay 兼容。例如,如果您的 GitHub 用户名是 santa,并且您正在实现 giftpay 支付库,则您的 composer 包的好名称可能是 santa/omnipay-giftpay

如果您想将您的网关转移到 omnipay GitHub 组织并将其添加到官方支持网关列表中,请在 omnipay/common 包上打开一个 pull request。在新的网关被接受之前,它们必须具有 100% 的单元测试代码覆盖率,并遵循其他 Omnipay 网关使用的约定和代码样式。

安装

Omnipay 通过 Composer 安装。对于大多数用途,您需要需要单个网关

composer require omnipay/paypal:~2.0

安装所有官方支持的网关

composer require omnipay/omnipay:~2.0

这将需要 所有 ~25 个 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
  • email

即使是离线网关,也使用了CreditCard对象,因为通常您需要通过网关传递客户的账单或配送详情。

可以通过构造函数使用不受信任的用户输入初始化CreditCard对象。传递给构造函数且未识别的字段将被忽略。

$formInputData = array(
    'firstName' => 'Bobby',
    'lastName' => 'Tables',
    'number' => '4111111111111111',
);
$card = new CreditCard($formInputData);

您还可以直接将表单数据数组传递给网关,并将为您创建一个CreditCard对象。

可以通过getters和setters访问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() - 将来自远程网关的传入请求转换为通用通知对象以供进一步处理

本地网关不需要实现 completeAuthorizecompletePurchase 方法。未接收支付通知的网关不需要实现 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',
));

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

为了总结您可用的各种参数

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

支付响应

支付响应必须实现 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

此外,大多数网关将覆盖响应对象,并提供访问网关返回的任何额外字段。

重定向响应

重定向响应根据客户的浏览器是否必须使用 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.');
}

令牌计费

令牌计费允许您将信用卡存储在您的网关中,并在以后日期进行扣费。并非所有网关都支持令牌计费。对于支持的网关,以下方法可供选择

  • createCard($options) - 返回一个响应对象,其中包含一个 cardReference,可用于未来的交易
  • updateCard($options) - 更新存储的卡片,并非所有网关都支持此方法
  • deleteCard($options) - 删除存储的卡片,并非所有网关都支持此方法

一旦您有了 cardReference,您可以在创建扣费时使用它代替 card 参数

$gateway->purchase(array('amount' => '10.00', 'cardReference' => 'abc'));

周期性计费

在此阶段,此库的范围不包括自动周期性支付功能。这是因为每个网关处理周期性计费配置文件的方式可能存在很大差异。此外,在大多数情况下,令牌计费将满足您的需求,因为您可以存储一张信用卡,然后按照您喜欢的任何时间表进行扣费。如果您真的认为这应该是一个核心功能,并且值得努力,请随时联系我们。

传入通知

某些网关(例如,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

示例应用

示例应用位于 omnipay/example 仓库中。您可以使用PHP内置的Web服务器(PHP 5.4+)运行它

$ php composer.phar update --dev
$ php -S localhost:8000

有关更多信息,请参阅 Omnipay示例应用

支持

如果您在使用Omnipay时遇到一般问题,我们建议在 Stack Overflow 上发布。请确保添加 omnipay标签,以便易于查找。

如果您想了解最新发布公告、讨论项目想法或提出更详细的问题,还有一个您可以订阅的 邮件列表

如果您认为发现了错误,请使用相应包的GitHub问题跟踪器报告它,或者更好的方法是,分叉库并提交拉取请求。

安全性

如果您发现任何与安全相关的问题,请通过电子邮件发送到 kayladnls@gmail.com 而不是使用问题跟踪器。

反馈

请提供反馈! 我们希望使此库尽可能多的项目有用。请前往 邮件列表 并指出您喜欢和不喜欢的内容,或者分叉项目并提出建议。 没有问题太小。