citypay/php-sdk

PHP CityPay SDK

1.0.7 2018-09-07 08:28 UTC

This package is auto-updated.

Last update: 2024-09-22 19:39:05 UTC


README

结构概览

PHP CityPay SDK 应用程序编程接口 ("API") 通常在提供请求对象、调用一些操作并接收可能被程序正常流程处理的响应对象方面进行结构化。

支持的支付处理流程

API 支持两种支付处理流程——

  1. 授权并完成” 支付流程,其中使用 API 发出的单个请求与可能需要的任何重定向(将客户浏览器重定向到托管表单)相结合,既实现了相关支付的授权,也完成了支付请求的必要步骤,以实现资金从客户转移到商家;
  2. 预授权” 支付流程,其中使用 API 发出的请求与可能需要的任何重定向(将客户浏览器重定向到托管表单)相结合,仅从收单方获得相关支付的预授权,随后必须执行一个后续完成步骤,才能实现资金从客户转移到商家。

在 PHP 项目中使用 API

API 是根据 PHP 标准建议开发的,特别是——

  1. PSR-1,基本编码标准;
  2. PSR-2,编码风格指南;
  3. PSR-3,记录器接口标准;以及
  4. PSR-4,类自动加载标准。

API 是使用 Composer 来管理依赖项开发的。要将 CityPay PHP SDK 导入您的项目,请在您的 composer.json 文件中指定以下内容——

{
    "require": {
        "citypay/php-sdk": "1.0.*"
    }
}

然后运行 php composer.phar install

托管表单支付处理

API 支持使用 PayLink 通过托管表单进行支付处理。API 需要商家应用程序——

  1. 使用新创建和初始化的 PayLinkRequest 类实例的 saleTransaction() 方法请求 PayLink 令牌;
  2. 接受包含令牌标识符和 URL 的 PayLinkToken 类实例;
  3. 将客户浏览器重定向到相关 PayLinkToken 提供的 URL;
  4. 接受通知,通知商家应用程序交易处理尝试的结果。此后的通知是通过以下方式之一或两种方式进行的——
    1. PayLink 向商家应用程序发出的 Postback HTTP 或 HTTPS 请求;
    2. PayLink 通过将客户浏览器从 PayLink 托管支付表单重定向到商家应用程序提供的 URL 终端点(当通过配置相关 PayLinkRequest 实例请求原始 PayLink 令牌时)进行的间接通知。

托管表单 "授权并完成" 流程

//
//  Create an appropriate PaymentRequest object, initialized with the
//  merchant identifier, the licence key associated with the merchant
//  identifier, the the amount for which the transaction is to be
//  processed together with the appropriate customer information,
//  payment card details, and token configuration.
//
$paylinkRequest = (new \CityPay\PayLink\PayLinkRequest())
    ->merchantId("<merchant-id>")
    ->licenceKey("<licence-key>")
    ->identifier("<transaction-identifier>")
    ->amount(5000)
    ->currency("GBP")
    ->cardholder(
        (new \CityPay\PayLink\Cardholder())
            ->title("<title>")
            ->firstName("<firstName>")
            ->lastName("<lastName>")
            ->address(
                (new Address())
                    ->address1("<addressLine1>")
                    ->address2("<addressLine2>")
                    ->area("<area>")
            )
        )
    ->configuration(
        (new \CityPay\PayLink\Configuration())
            ->postbackPolicy("sync")
            ->postback("http://postback/address")
            ->redirect("http://general/redirect")
            ->redirectSuccess("http://success/redirect")
            ->redirectFailure("http://failure/redirect")
            ->options(
                Option.BYPASS_CUSTOMER_EMAIL,
                Option.BYPASS_MERCHANT_EMAIL,
                Option.BYPASS_AVS_ADDRESS,
                Option.BYPASS_AVS_POSTCODE,
                Option.ENFORCE_CSC_REQUIRED
            )
        );

try {

   $apiMessage = $paylinkRequest->saleTransaction()

} catch (Exception $e) {


}

托管表单 "预授权" 流程

$paylinkRequest = (new \CityPay\PayLink\PayLinkRequest())
    ->merchantId("<merchant-id>")
    ->licenceKey("<licence-key>")
    ->identifier("<transaction-identifier>")
    ->amount(5000)
    ->currency("GBP")
    ->cardholder(
        (new \CityPay\PayLink\Cardholder())
            ->title("<title>")
            ->firstName("<firstName>")
            ->lastName("<lastName>")
            ->address(
                (new Address())
                    ->address1("<addressLine1>")
                    ->address2("<addressLine2>")
                    ->area("<area>")
            )
        )
    ->configuration(
        (new \CityPay\PayLink\Configuration())
            ->postbackPolicy("sync")
            ->postback("http://postback/address")
            ->redirect("http://general/redirect")
            ->redirectSuccess("http://success/redirect")
            ->redirectFailure("http://failure/redirect")
            ->options(
                Option.BYPASS_CUSTOMER_EMAIL,
                Option.BYPASS_MERCHANT_EMAIL,
                Option.BYPASS_AVS_ADDRESS,
                Option.BYPASS_AVS_POSTCODE,
                Option.ENFORCE_CSC_REQUIRED
            )
        );

try {

    $apiMessage = paylinkRequest->saleTransaction()

} catch (Exception $e) {


}

托管表单 Postback 处理

在 PHP 应用程序环境中处理 Postback 的方法尚未确定。

直接请求支付处理

直接请求 "授权并完成" 支付流程

通过直接请求进行“授权并完成”交易,涉及商户应用向PayPost提交支付卡详细信息,以获取交易授权,并从支付卡发行方提取授权金额,用于后续结算给商户。PayPost支持使用3D Secure技术进行认证的交易处理,以及不支持3D Secure的交易处理。

非3D Secure认证的支付处理

非3D Secure认证的支付处理数据和控制流程涉及以下步骤:

  1. 创建并初始化PayPostRequest类的实例;
  2. 调用新创建的PayPostRequest对象的saleTransaction()方法;
  3. 处理saleTransaction()调用返回的PayPostResponse对象。

此外,为了支持通过3D Secure认证的交易,商户应用必须在ACS将客户交互结果返回给商户应用后,公开一个端点URL,即“商户终端URL”。

PHP代码示例

//
//  Create an appropriate PayPostRequest object, initialized with the
//  merchant identifier, the licence key associated with the merchant
//  identifier, the the amount for which the transaction is to be
//  processed together with the appropriate customer information, and
//  payment card details.
//
$salePayPostRequest = (new \CityPay\PayPost\PayPostRequest())
    ->merchantId("<merchant-id>")
    ->licenceKey("<licence-key>")
    ->identifier("<transaction-identifier>")
    ->amount(<amountInLDF>)
    ->currency("<currency>")
    ->billToName("<customer-name>")
    ->billToPostCode("<postal-code>")
    ->cardNumber("<cardnumber>")
    ->expiryMonth(<expiryMonth>)
    ->expiryYear(<expiryYear>)
    ->csc(<card-security-code>);

//
//  Invoke the saleTransaction() method of the relevant PayPostRequest
//  object, and receive the ApiMessage returned.
//
$saleApiMessage = $salePayPostRequest->saleTransaction()

//
//  If the "sale transaction" operation was processed correctly, though
//  not necessarily successfully, the ApiMessage returned will be of type
//  PayPostResponse. Accordingly, the Merchant Application should test the
//  return type of the ApiMessage to correctly process the results generated
//  by the operation.
//
if (!($saleApiMessage instanceof \CityPay\PayPost\PayPostResponse)) {
    //
    //  Throw exception.
    //
}

//
//  Ascertain whether the sale transaction was successful by reference
//  to the salePayPostResponse object, and handle any reported
//  processing issues.
//
if ($saleApiMessage->isAuthorised()) {
    //
    //  The sale transaction was successfully authorized and, subject
    //  to whether sale transactions are authorized and completed by
    //  default, or pre-authorised by default, the Service Provider
    //  may seek settlement.
    //
} else {
    //
    //  The sale transaction was not successfully authorized.
    //
}

3D Secure认证的支付处理

直接请求支付处理模型支持3D Secure交易和非3D Secure交易。非3D Secure支付处理的数据和控制流程涉及创建PayPostRequest对象,然后调用saleTransaction()方法以获取PayPostResponse对象,而3D Secure交易则需要以下步骤:

  1. 创建并初始化AcsPayPostRequest类的实例;
  2. 调用新创建的AcsPayPostRequest对象的saleTransaction()方法;
  3. 处理PayPostAuthenticationRequiredResponse对象或PayPostResponse对象,具体取决于支付卡发行方是否支持相关支付卡的3D Secure交易,以及支付卡是否已注册到适当的3D Secure方案。其中:
    1. 如果收到PayPostAuthenticationRequiredResponse对象,商户应用必须:
      1. 将客户浏览器重定向到支付卡发行方的访问控制服务器(ACS);
      2. 接受对由商家TermURL提供的URL的HTTPS POST调用,该URL接受ACS认证过程的结果并将它们转发给PayPost以获取交易授权;或者
    2. 收到PayPostResponse对象,商户应用处理交易结果。

此外,为了支持通过3D Secure认证的交易,商户应用必须在ACS将客户交互结果返回给商户应用后,公开一个端点URL,即“商户终端URL”。

AcsPayPostRequest初始化函数

AcsPayPostRequest类的实例属性与PayPostRequest类的实例属性相同,但以下属性是额外的。

PayPostAuthenticationRequiredResponse方法

如果saleTransaction()调用返回的ApiMessage对象是PayPostAuthenticationRequiredResponse类的实例,则销售交易必须使用3D Secure进行认证。

PayPostAuthenticationRequiredResponse对象公开以下属性:

为了获得认证,商户应用必须通过让客户浏览器提交以下表单来重定向客户浏览器到ACS,该表单包含在PayPostAuthenticationRequiredResponse对象中接收到的值,并提供与商户应用在原始PayPostRequest中提供的相同的商户终端URL。

<html>
    <head>
        <script type="text/javascript">
        <!--
        function OnLoadEvent() { document.acs.submit(); }
        // -->
        </script>
    </head>
    <body onload="OnLoadEvent();">
        <form name="acs" action="ACSURL" method="POST">
            <input type="hidden" name="PaReq" value="DATA PACKET" />
            <input type="hidden" name="TermUrl" value="Termination URL" />
            <input type="hidden" name="MD" value="Merchant Data" />
        </form>
    </body>
</html>

处理ACS重定向到merchantTermUrl端点的处理

如果商家应用程序要支持3D Secure认证支付,则商家应用程序会暴露一个端点以接受和处理HTTP POST操作,以完成3D Secure交易。随HTTP POST请求一起发送的有效负载使用application/x-www-form-url-encoded内容类型编码,并包含以下命名值:

PHP代码示例
//
//  Create an appropriate AcsPayPostRequest object, initialized with the
//  merchant identifier, the licence key associated with the merchant
//  identifier, the the amount for which the transaction is to be
//  processed together with the appropriate customer information, and
//  payment card details.
//
$saleAcsPayPostRequest = (new \CityPay\PayPost\AcsPayPostRequest())
    ->merchantId("<merchant-id>")
    ->licenceKey("<licence-key>")
    ->identifier("<transaction-identifier>")
    ->amount(<amountInLDF>)
    ->currency("<currency>")
    ->billToName("<customer-name>")
    ->billToPostCode("<postal-code>")
    ->cardNumber("<cardnumber>")
    ->expiryMonth(<expiryMonth>)
    ->expiryYear(<expiryYear>)
    ->csc(<card-security-code>)
    ->merchantTermUrl(<merchantTermUrl>)
    ->userAgent(<userAgent>)
    ->acceptHeaders(<acceptHeaders>);

//
//  Invoke the saleTransaction() method of the relevant PayPostRequest
//  object, and receive the ApiMessage returned.
//
$saleAcsApiMessage = saleAcsPayPostRequest->saleTransaction()

//
//  If the "sale transaction" operation was processed correctly, though
//  not necessarily successfully, the ApiMessage returned will be one of
//  two types depending on whether the relevant payment card issuer
//  supports 3DS authentication for the relevant payment card, and whether
//  the cardholder is enrolled in the relevant 3DS authentication scheme.
//  Accordingly, the Merchant Application should test the return type of
//  the ApiMessage to correctly process the results generated by the
//  operation.
//
if ($saleAcsApiMessage instanceof \CityPay\PayPost\PayPostAuthenticationRequiredResponse) {
    //
    //  Refer the Customer Browser to the ACS server by returning
    //  a HTML form that may be automatically submitted by the
    //  Customer Browser on receipt.
    //
} else if ($saleAcsApiMessage instanceof \CityPay\PayPost\PayPostResponse) {
    //
    //  Ascertain whether the sale transaction was successful by reference
    //  to the salePayPostResponse object, and handle any reported
    //  processing issues.
    //
    if ($salePayPostResponse->isAuthorised()) {
        //
        //  The sale transaction was successfully authorized and, subject
        //  to whether sale transactions are authorized and completed by
        //  default, or pre-authorised by default, the Service Provider
        //  may seek settlement.
        //
    } else {
        //
        //  The sale transaction was not successfully authorized.
        //
    }
} else {
    //
    //  Throw exception.
    //
}

直接请求预授权交易流程

预授权交易基本上与“授权和完成”交易相同。交易是以预授权交易还是以授权和完成交易执行,由服务提供商配置的商家配置文件决定。

直接请求完成交易流程

//
//  Determine the transaction number associated with the pre-authorised
//  transaction to be completed.
//
$transNo = <transNo>

//
//  Determine the amount for which the pre-authorised transaction is to
//  be completed in "lowest denomination form".
//
$amount = <amountInLDF>

//
//  Create an appropriate PayPostRequest object, initialized with the
//  merchant identifier, the licence key associated with the merchant
//  identifier, the transaction number and the amount for which the
//  transaction is to be completed.
//
$completePayPostRequest = (new \CityPay\PayPost\PayPostRequest())
    ->merchantId(<merchant_id>)
    ->licenceKey(<licence_key>)
    ->transNo($transNo)
    ->amount($amount);

//
//  Invoke the completeTransaction() method of the relevant
//  PayPostRequest object, and receive the ApiMessage returned.
//
$completeApiMessage = completePayPostRequest.completeTransaction();

//
//  If the "complete transaction" operation was processed correctly, though
//  not necessarily successfully, the ApiMessage returned will be of type
//  PayPostResponse. Accordingly, the Merchant Application should test the
//  return type of the ApiMessage to correctly process the results generated
//  by the operation.
//
if (!($completeApiMessage instanceof \CityPay\PayPost\PayPostResponse) {
    //
    //  Throw exception
    //
}

直接请求“取消”交易流程

//
//  Determine the transaction number associated with the pre-authorized
//  transaction to be cancelled.
//
$transNo = <transNo>

//
//  Create an appropriate PayPostRequest object, initialized with the
//  merchant identifier, the licence key associated with the merchant
//  identifier, and the transaction number of the pre-authorized
//  transaction to be cancelled.
//
$cancelPayPostRequest = (new \CityPay\PayPost\PayPostRequest())
    ->merchantId(<merchant_id>)
    ->licenceKey(<licence_key>)
    ->transNo($transNo);

//
//  Invoke the completeTransaction() method of the relevant
//  PayPostRequest object, and receive the ApiMessage returned.
//
$cancelApiMessage = cancelPayPostRequest.cancelTransaction();

//
// If the "cancel transaction" operation was processed correctly,
// though not necessarily successfully, the ApiMessage returned will
// be of type PayPostResponse. Accordingly, the Merchant
// Application should test the //  return type of the ApiMessage to
// correctly process the results generated //  by the operation.
//
if (!($cancelApiMessage instanceof \CityPay\PayPost\PayPostResponse) {
    //
    //  Throw exception
    //
}

支持PCI DSS合规日志记录

目前,API通过使用由PSR-3提供的标准日志接口,提供了对PCI DSS合规日志记录的有限、实验性支持。

不幸的是,PSR-3没有提出一个标准或指南,以告知支持API一个合适的PSR-3合规日志收集器。特别是,PSR-3并没有明确指出API是否应该使用单个日志收集器,或者是否应该使用结构化的层次结构,以便对API的日志行为进行细粒度控制。

预计,在适当的时候,将通过静态绑定调用\CityPay\Lib\Logger::setLoggerDelegate()来告知API一个合适的PSR-3合规日志收集器工厂,这样API就能通过后续调用\CityPay\Lib\Logger::getLogger()构建适当的从属日志记录器。