hochstrasserio/wirecard

此包已被废弃且不再维护。未建议替换包。

Wirecard支付网关的现代客户端

v1.1.0 2017-03-09 22:08 UTC

This package is not auto-updated.

Last update: 2020-05-15 17:48:50 UTC


README

从2020年9月30日起,此SDK使用的方法不再由Wirecard支持。

因此,此存储库已存档,不再维护。您可以在许可证条款下自由分支此代码。

Wirecard

Latest Version on Packagist Software License Build Status Total Downloads

一个用于通过Wirecard进行支付的未官方SDK。

有关在您的应用程序中使用Wirecard进行支付的一般信息,请访问Wirecard Integration Wiki

通过免费注册Wiki的注册页面获得Integration Wiki的账户。

SDK覆盖范围

  • Wirecard Checkout Page
  • Wirecard无缝结账
  • 无缝后端操作
  • 结账页面后端操作

安装

在项目目录中使用Composer

$ composer require hochstrasserio/wirecard

使用

设置

此库不包含通过网络发送HTTP请求的功能。您需要获取一个库来完成此操作。任何符合PSR-7规范的库都可以工作,如Guzzle v6+Ivory HTTP Adapters库

$ composer require 'guzzlehttp/guzzle:^6.0.0'

然后,使用您的客户ID、客户密钥和可选的商店ID配置Wirecard Context。您应该从Wirecard或Integration Wiki收到这些信息。演示或测试凭据也在Integration Wiki中可用。

<?php

use Hochstrasser\Wirecard\Context;

// Constructor takes Customer ID, Customer Secret, Language code, and Shop ID:
$context = new Context([
    'customer_id' => 'D200001',
    'secret' => 'B8AKTPWBRMNBV455FG6M2DANE99WU2',
    'language' => 'de',
    'shop_id' => 'qmore',
    'hashing_method' => Context::HASHING_HMAC,
]);

Context还有一些您可以通过构造函数传递的选项

  1. customer_id: 您的客户ID,您可以从Wirecard或Integration Wiki获得
  2. secret: 您的客户密钥,您可以从Wirecard或Integration Wiki获得。不要与他人分享此信息
  3. language: Wirecard UI和错误消息的语言
  4. shop_id (可选): 如果多个商店使用一组凭据(如果Wirecard告诉您),请设置此选项
  5. javascript_script_version (可选): 启用PCI DSS SAQ A合规功能
  6. user_agent (可选): 用于HTTP请求的库用户代理,您可以可选地将此设置为您的站点名称
  7. hashing_method (可选): 用于计算指纹散列的使用的算法。如果省略,则出于兼容性原因使用旧方法Context::HASHING_SHA。新Wirecard客户应使用Context::HASHING_HMAC,因为它是目前Wirecard的默认值。不过,演示客户仍然使用Context::HASHING_SHA

SDK模式

请求

所有请求都是简单的类,它们实现了 WirecardRequestInterface 并可以直接构造。大多数类都有一个特定的命名构造函数,以 with* 开头,例如 withBasketwithOrderIdentAndReturnUrl。应优先使用这些构造函数,而不是简单的构造函数。

发送请求

请求通过 createHttpRequest 方法转换为 PSR-7 兼容的请求。必须在之前设置上下文。然后您可以使用您的 HTTP 客户端发送 PSR-7 兼容的请求消息。发送请求后,createResponse 方法将任何 PSR-7 兼容的响应对象转换为 WirecardResponseInterface。

<?php

$client = new \GuzzleHttp\Client;

$request = InitDataStorageRequest::withOrderIdentAndReturnUrl('1234', 'http://example.com')
    ->setContext($context);

$httpResponse = $client->send($request->createHttpRequest());
$response = $request->createResponse($httpResponse);

这看起来可能有点麻烦,但它有一个很大的好处,即让您摆脱对特定 HTTP 客户端库(如 Guzzle 或 Buzz)特定版本的依赖。您可以使用最适合您的客户端,或者提供最佳性能的客户端,这始终比这个库能提供的更好、更快,并且具有更多功能。此外,SDK 的依赖与您的应用程序发生冲突的风险很小。

使用 WirecardHelper

包含了一个小的实用工具,即 WirecardHelper,每次您发出请求时,它都可以为您节省几行代码。使用上下文初始化,并使用配置好的客户端发送请求。

您传递给它两件事:Wirecard 上下文和一个函数,该函数通过电线发送一个 Psr\Http\Message\RequestInterface 并返回一个 Psr\Http\Message\ResponseInterface

<?php

use Hochstrasser\Wirecard\Helper\WirecardHelper;

// Guzzle 6
$guzzle = new Guzzle\Client;

$helper = new WirecardHelper($context, function ($request) use ($guzzle) {
    return $guzzle->send($request);
});

// Sets the context, converts the request and makes the http response to a
// WirecardResponseInterface
$response = $helper->send(InitDataStorageRequest::withOrderIdentAndReturnUrl(
    '1234', 'http://example.com'
));

$dataStorage = $response->toObject();

请注意,该辅助程序仅以同步方式发送请求。如果您想进行异步请求,您必须直接使用您的 HTTP 库。

必需参数

请求知道它们必需的参数。如果缺少已知的必需参数,则抛出 RequiredParameterMissingException

响应

所有响应都实现了 WirecardResponseInterface

获取结果

通过使用 toObjecttoArray 方法检索结果。通常使用 toObject 方法。此方法返回一个模型类,该类具有方便检索返回值的函数。这些函数定义在模型类中,因此您的 IDE 应该能够建议它们。

toArray 方法返回请求返回的原始响应参数。这对于调试和与官方文档核对很有用。

<?php

$a = $response->toArray();
var_dump($a['redirectUrl']);

$b = $response->toObject();
var_dump($b->getRedirectUrl());
错误

每个响应都有一个 hasErrors 方法,它检查是否有任何返回的错误。可以通过在响应对象上使用 getErrors 来检索所有返回的错误。

<?php

if ($response->hasErrors()) {
    foreach ($response->getErrors() as $error) {
        echo $error, "<br>";
    }
}

Wirecard 结账页面

使用 Wirecard 结账页面,您不必处理选择付款类型或存储信用卡数据的 UI。InitCheckoutPageRequest 在另一种方式上也是一个例外:它不能与客户端一起发送,您必须使用一个 HTML 表单,该表单必须由客户自己提交。

InitCheckoutPageRequest与Seamless Checkout中的InitPaymentRequest使用相同的参数,并且以相同的方式初始化。

唯一的区别是

  • confirmUrl不是必需的
  • paymentType不需要在请求对象中设置,可以在表单中设置

示例

<?php

use Hochstrasser\Wirecard\Context;
use Hochstrasser\Wirecard\Model\Common\PaymentType;
use Hochstrasser\Wirecard\Request\CheckoutPage\InitCheckoutPageRequest;

$context = new Context(['customer_id' => 'D200001', 'secret' =>  'B8AKTPWBRMNBV455FG6M2DANE99WU2', 'language' => 'de']);
$request = InitCheckoutPageRequest::with()
    ->setPaymentType(PaymentType::Select)
    ->setContext($context)
    ->setAmount('33.00')
    ->setCurrency('EUR')
    ->setOrderDescription("12345")
    ->setSuccessUrl("http://localhost:8001/")
    ->setFailureUrl("http://localhost")
    ->setCancelUrl("http://localhost")
    ->setServiceUrl("http://localhost")
    ;
?>

<form action="<?= $request->getEndpoint() ?>" method="POST">
    <?php foreach ($request->getRequestParameters() as $param => $value): ?>
    <input type="hidden" name="<?= $param ?>" value="<?= $value ?>"/>
    <?php endforeach ?>

    <input type="submit" value="Buy"/>
</form>

Checkout页面的另一个主要区别是,successUrl接收所有支付响应参数作为POST请求,就像confirmUrl一样。此外,confirmUrl还可以设置为在用户动作之外接收参数,以便您进行记录和参考。

您可以在这里了解更多信息: 在您的在线商店接收支付过程结果

Wirecard无缝结账

使用Wirecard无缝结账,您的客户将使用您自己定制的页面选择您已为网站启用的支付方式。此UI的外观和工作方式完全由您决定。

您需要发出一些请求

  1. InitDataStorageRequest:通常您不希望处理PCI合规性,并希望Wirecard来处理。此请求初始化一个数据存储,它在Wirecard的服务器上,并为您安全存储客户的信用卡数据。存储数据的唯一方法是使用JavaScript库。在成功调用后,InitDataStorageRequest返回包含库的URL。这仅在您接受信用卡付款时才是必要的,并且必须在请求付款之前进行。
  2. 可选的,ReadDataStorageRequest:您可以使用此请求显示客户输入的信用卡数据,同时移除所有敏感信息。您可以使用此功能在付款前让客户再次查看输入的支付数据。
  3. InitPaymentRequest:执行支付并返回一个URL。将客户重定向到该URL以完成请求的支付。如果成功,您的网站将收到Wirecard在确认URL处的POST请求,其中包含支付详情,如交易号。最后,客户将被重定向回您的网站。

InitDataStorageRequest

响应模型: DataStorageInitResult

设置数据存储并返回JavaScript库的URL和存储ID。只有在您的客户打算通过信用卡付款时才需要发出此请求。存储ID可以用来从数据存储中读取掩码数据,并且稍后必须传递给InitPaymentRequest

要创建请求,请使用withOrderIdentAndReturnUrl命名构造函数。"订单标识"应该是结账的唯一值,"返回URL"作为第二个参数传递,用于旧版浏览器。

<?php

use Hochstrasser\Wirecard\Request\Seamless\Frontend\InitDataStorageRequest;

$request = InitDataStorageRequest::withOrderIdentAndReturnUrl('1234', 'http://example.com')
    ->setContext($context);

$response = $request->createResponse($client->send($request->createHttpRequest()));

// Store the storage ID for later usage with the payment request
$_SESSION['wirecardDataStorageId'] = $response->toObject()->getStorageId();

var_dump($response->hasErrors());
var_dump($response->toObject()->getStorageId());
var_dump($response->toObject()->getJavascriptUrl());

ReadDataStorageRequest

响应模型: DataStorageReadResult

读取数据存储并返回一个包含掩码的数组客户数据

<?php

use Hochstrasser\Wirecard\Request\Seamless\Frontend\ReadDataStorageRequest;

$request = ReadDataStorageRequest::withStorageId($_SESSION['wirecardDataStorageId'])
    ->setContext($context);

$response = $request->createResponse($client->send($request->createHttpRequest()));

var_dump($response->hasErrors());
var_dump($response->toObject()->getStorageId());

foreach ($response->toObject()->getPaymentInformation() as $paymentInformation) {
    var_dump($paymentInformation->getMaskedPan());
}

使用InitPaymentRequest进行支付

响应模型: InitPaymentResult

请求支付并返回一个重定向URL。将客户重定向到此URL以完成支付。

必需的支付参数
  • amount:货币的基本单位支付金额,例如 12.00。当使用 withBasket 时从购物车设置。设置为字符串以避免四舍五入错误,这可能会发生在浮点数上。
  • currency:ISO货币代码,例如 EUR。当使用 withBasket 时从购物车设置。
  • paymentType (PaymentType):客户选择的支付类型。您可以使用 PaymentType::isValid() 来验证请求的支付类型的标识符。
  • orderDescription:您的订单描述,可以是关于订单的结构化数据。
  • successUrl:如果支付成功,则客户将被Wirecard重定向到该URL。
  • failureUrl:如果在确认结账过程中发生某种类型的失败,则客户将被Wirecard重定向到该URL。
  • cancelUrl:如果在确认过程中支付被取消(例如,在PayPal屏幕上),则客户将被Wirecard重定向到该URL。
  • serviceUrl:列出您的服务条款和联系信息的页面,通常是您的“联系我们”或“印记”页面。
  • confirmUrl:您的网站上的一个端点,该端点通过Wirecard在客户成功确认支付后通过POST请求接收有关支付的详细信息。通常您在此端点发送订单确认电子邮件。
  • consumerUserAgentconsumerIpAddress:用于可选的防止重复支付。

这些参数可以是使用请求对象的 addParam 方法或它们的相应 set* 方法设置的,例如 setSuccessUrl

支付请求还有很多可选参数,例如创建周期性支付、设置信用卡账单上显示的声明等。有关更多信息,请参阅请求参数文档

添加购物车

支付请求使用一个填充了 BasketBasket Items 来在PayPal等结账屏幕上显示客户的商品。您也可以使用它轻松设置订单的金额和货币。在大多数情况下,您应该能够从您网站自己的购物车模型中推断出购物车。

注意:如果在支付请求上设置了购物车,Wirecard会在服务器上验证购物车商品的所有价格和总金额是否正确累加。否则,Wirecard会返回错误。

<?php

use Hochstrasser\Wirecard\Model\Common\Basket;
use Hochstrasser\Wirecard\Model\Common\BasketItem;

// Create the basket, this is optional for most payment methods, but probably
// can be automatically created from your shop’s cart model

$basket = new Basket();
$basket->setAmount('17.00');
$basket->setCurrency('EUR');
$basket->addItem((new BasketItem)
    ->setArticleNumber('A001')
    ->setDescription('Product A1')
    ->setQuantity(1)
    ->setUnitPrice('10.00')
    ->setTax('1.00')
);
$basket->addItem((new BasketItem)
    ->setArticleNumber('SHIPPING')
    ->setDescription('Shipping')
    ->setQuantity(1)
    ->setUnitPrice('5.00')
    ->setTax('1.00')
);
添加收货和账单信息

某些支付类型需要收货和账单信息。SDK提供ShippingInformationBillingInformation 类来帮助您完成这些操作。

<?php

use Hochstrasser\Wirecard\Model\Common\ShippingInformation;
use Hochstrasser\Wirecard\Model\Common\BillingInformation;

$shippingInformation = (new ShippingInformation)
    ->setFirstname('Max')
    ->setLastname('Mustermann')
    ->setAddress1('Musterstraße')
    ->setAddress2('2')
    ->setZipCode('1234')
    ->setState('Lower Austria')
    ->setCity('Musterstadt')
    ->setCountry('AT')
    ->setPhone('+431231231234')
    ->setFax('+431231231234');

如果客户的账单信息与收货信息相匹配,则BillingInformation 类提供了一个方便的命名构造函数。否则,BillingInformation 类具有与ShippingInformation 相同的方法。

<?php

$billingInformation = BillingInformation::fromShippingInformation($shippingInformation);

有效的账单信息需要两个附加参数:客户的电子邮件和他们的出生日期(作为 \DateTime 对象)

<?php

$billingInformation->setConsumerEmail("max@mustermann.com");
$billingInformation->setConsumerBirthDate(new \DateTime("Sept 1 1970"));

最后,您可以使用 setConsumerShippingInformationsetConsumerBillingInformation 方法将配送和账单信息添加到请求中。

请求支付

有了我们的购物车对象,我们现在可以初始化支付请求

<?php

use Hochstrasser\Wirecard\Model\Common\PaymentType;
use Hochstrasser\Wirecard\Request\Seamless\Frontend\InitPaymentRequest;

if (!PaymentType::isValid($_POST['paymentType'])) {
    // Show error and return
}

$request = InitPaymentRequest::withBasket($basket)
    // Set the payment type selected by the user in the frontend
    ->setPaymentType($_POST['paymentType'])
    ->setOrderDescription('Some test order')
    ->setSuccessUrl('http://example.com')
    ->setFailureUrl('http://example.com')
    ->setCancelUrl('http://example.com')
    ->setServiceUrl('http://example.com')
    // Your callback controller for handling the result of the payment, you will
    // receive a POST request at this URL
    ->setConfirmUrl('http://example.com')
    ->setConsumerShippingInformation($shippingInformation)
    ->setConsumerBillingInformation($billingInformation)
    ->setConsumerUserAgent($_SERVER['HTTP_USER_AGENT'])
    ->setConsumerIpAddress($_SERVER['REMOTE_IP'])
    ->setContext($context)
    ;

// Set the data storage ID if the data storage was initialized
if (isset($_SESSION['wirecardDataStorageId'])) {
    $request->setStorageId($_SESSION['wirecardDataStorageId']);
}

$response = $request->createResponse($client->send($request->createHttpRequest()));

使用响应模型,现在您可以重定向客户到 Wirecard 的支付确认流程。然后,此流程将连接到客户选择的支付服务提供商,例如 PayPal 或 3-D secure,在那里他们将确认支付。

<?php

if ($response->hasErrors()) {
    // Show errors in the UI
}

// Redirect if no errors happened
header('Location: '.$response->toObject()->getRedirectUrl());
处理响应参数

之后,Wirecard 将向作为 confirmUrl 传递的 URL 发送一个 POST 请求,并带有支付请求的响应参数。这些参数包含订单号等。存储这些参数以备参考。

您可以使用提供的 Fingerprint 类来验证提供的响应指纹

<?php

use Hochstrasser\Wirecard\Fingerprint;

$responseParameters = $_POST;
$fingerprint = Fingerprint::fromResponseParameters($responseParameters, $context);

if (!hash_equals($responseParameters['responseFingerprint'], (string) $fingerprint)) {
    // Fingerprint is not valid, abort
    exit;
}

// Fingerprint is valid. Go on and store the response parameters

变更日志

请参阅 CHANGELOG 了解最近有哪些变化。

测试

$ composer test

贡献

请参阅 CONTRIBUTING 了解详细信息。

安全

如果您发现任何安全相关的问题,请通过电子邮件 christoph@hochstrasser.io 联系我们,而不是使用问题跟踪器。

鸣谢

许可证

MIT 许可证(MIT)。请参阅 许可证文件 了解更多信息。