dalpras/omnipay-nexi

Nexi 付款处理库的驱动程序

1.0 2024-01-12 10:27 UTC

This package is auto-updated.

Last update: 2024-09-18 08:45:37 UTC


README

一个易于使用、一致的 PHP 付款处理库

Unit Tests Latest Stable Version Total Downloads

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

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

  • 因为你可以学习一个 API,然后在多个使用不同付款网关的项目中使用它
  • 因为如果你需要更改付款网关,你不需要重写你的代码
  • 因为大多数官方 PHP 付款网关库都是一团糟
  • 因为大多数付款网关的文档都非常糟糕
  • 因为你在编写购物车并需要支持多个网关

长话短说

只想看看一些代码吗?

use Omnipay\Omnipay;
use Omnipay\OmnipayNexi\Enums\CaptureType;

$gateway = Omnipay::create('Nexi');
$gateway->setTestMode(true);

$response = $gateway->purchase([
        'captureType' => CaptureType::Implicit, 
        'correlationId' => '4935e818-38e0-11ed-a261-0242ac120002',
        'orderId' => 'testOrder10',
        'amount' => '10.00', 
        'currency' => 'EUR', 
        'cancelUrl' => 'https://www.example.com/canceled', 
        'returnUrl' => 'https://www.example.com/acquired', 
        'notificationUrl' => 'https://www.example.com/info',
        'testMode' => true
    ])->send();

if ($response->isRedirect()) {
    // redirect to offsite payment gateway
    $response->redirect();
} elseif ($response->isSuccessful()) {
    // payment was successful: update database
    print_r($response);
} else {
    // payment failed: display message to customer
    echo $response->getMessage();
}

安装

Omnipay 和 Nexi 驱动通过 Composer 安装。对于大多数使用情况,您需要要求 league/omnipay 和一个单独的网关

composer require league/omnipay:^3 dalpras/omnipay-nexi

如果您想使用自己的 HTTP 客户端而不是 Guzzle(这是 league/omnipay 的默认设置),您可以使用 league/common 和任何 php-http/client-implementation(请参阅 PHP Http

composer require league/common:^3 dalpras/omnipay-nexi php-http/buzz-adapter

付款网关

所有付款网关都必须实现 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 对象。

可以使用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 - 获取可用于未来支付的卡引用。例如,这可能在月度账单场景中使用。

在线网关不需要实现 completeAuthorizecompletePurchase 方法。未收到支付通知的网关不需要实现 acceptNotification。如果任何网关不支持某些功能(例如退款),则将抛出 BadMethodCallException

除了 acceptNotification 之外的所有网关方法都接受一个 $options 数组作为参数。该 acceptNotification 方法不接受任何参数,并将隐式访问HTTP URL变量或POST数据。每个网关在所需参数方面都有所不同,如果省略了任何必需参数,网关将抛出 InvalidRequestException。所有网关都将接受这些选项的子集

  • 令牌
  • 金额
  • 货币
  • 描述
  • 交易ID
  • 客户端IP
  • 返回URL
  • 取消URL

将选项按如下方式传递给方法

$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,但您不希望用户指定支付 currencyreturnUrl

支付响应

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

注意:一些早期网关使用completeAuthorizecompletePurchase消息来处理入站通知。这些消息正在被转换,complete*消息已被弃用。它们不会在Omnipay 2.x中删除,但建议在方便时切换到acceptNotification消息。例如,Sage Pay Server completeAuthorize现在由acceptNotification处理,见此处

示例应用

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

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

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

支持

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

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

如果您认为您发现了一个bug,请使用相应包的GitHub问题跟踪器报告它,或者更好的是,分叉库并提交一个pull请求。

安全

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

反馈

请提供反馈!我们希望让这个库尽可能多地用于各种项目。请访问邮件列表并指出您喜欢和不喜欢的地方,或者分叉项目并提出建议。没有问题太小。