Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: globalpayments/php-sdk
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2.2.7
Choose a base ref
...
head repository: globalpayments/php-sdk
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Feb 25, 2021

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    30b7762 View commit details

Commits on Mar 11, 2021

  1. Copy the full SHA
    57994ad View commit details

Commits on Mar 23, 2021

  1. Copy the full SHA
    7cd1d5c View commit details

Commits on Apr 1, 2021

  1. Copy the full SHA
    94bffec View commit details

Commits on Apr 5, 2021

  1. Copy the full SHA
    196cfd2 View commit details

Commits on Apr 6, 2021

  1. Copy the full SHA
    04fc1fb View commit details

Commits on Apr 29, 2021

  1. Copy the full SHA
    97ba46c View commit details

Commits on May 11, 2021

  1. Copy the full SHA
    f53bb9d View commit details

Commits on May 18, 2021

  1. Copy the full SHA
    8833981 View commit details

Commits on May 20, 2021

  1. Copy the full SHA
    ebb2fb7 View commit details
  2. Copy the full SHA
    bed955a View commit details

Commits on May 27, 2021

  1. Copy the full SHA
    f116e18 View commit details

Commits on Jun 15, 2021

  1. Copy the full SHA
    ca2167b View commit details

Commits on Jul 8, 2021

  1. Copy the full SHA
    5c63eb0 View commit details

Commits on Jul 13, 2021

  1. Copy the full SHA
    1329d11 View commit details

Commits on Jul 20, 2021

  1. Copy the full SHA
    d54dd39 View commit details

Commits on Jul 27, 2021

  1. Copy the full SHA
    7b710dd View commit details

Commits on Aug 3, 2021

  1. Copy the full SHA
    aea2fc0 View commit details

Commits on Aug 19, 2021

  1. Copy the full SHA
    10f9e14 View commit details

Commits on Aug 26, 2021

  1. Copy the full SHA
    7fafe53 View commit details

Commits on Sep 9, 2021

  1. Copy the full SHA
    f49d0aa View commit details

Commits on Sep 23, 2021

  1. Copy the full SHA
    772327a View commit details

Commits on Sep 30, 2021

  1. Copy the full SHA
    ca910d0 View commit details

Commits on Oct 21, 2021

  1. Copy the full SHA
    a9bd99a View commit details

Commits on Nov 4, 2021

  1. Copy the full SHA
    0c0cc7c View commit details

Commits on Nov 11, 2021

  1. Copy the full SHA
    34dead5 View commit details

Commits on Nov 16, 2021

  1. Copy the full SHA
    3e936b4 View commit details

Commits on Nov 18, 2021

  1. Copy the full SHA
    641274b View commit details

Commits on Dec 7, 2021

  1. Copy the full SHA
    792fc4a View commit details

Commits on Dec 16, 2021

  1. Copy the full SHA
    8d313a9 View commit details

Commits on Jan 27, 2022

  1. Copy the full SHA
    a4febbe View commit details

Commits on Feb 17, 2022

  1. Copy the full SHA
    11ee864 View commit details

Commits on Mar 22, 2022

  1. Copy the full SHA
    8e4567b View commit details

Commits on Apr 12, 2022

  1. Copy the full SHA
    3f9e43e View commit details

Commits on Apr 21, 2022

  1. Copy the full SHA
    d7e63ea View commit details

Commits on May 5, 2022

  1. Copy the full SHA
    bf778a7 View commit details

Commits on May 17, 2022

  1. Copy the full SHA
    a150c33 View commit details

Commits on Jun 7, 2022

  1. Copy the full SHA
    7f34519 View commit details

Commits on Jun 9, 2022

  1. Copy the full SHA
    7bad2fe View commit details

Commits on Jun 14, 2022

  1. Copy the full SHA
    ccc28d9 View commit details

Commits on Jun 28, 2022

  1. Copy the full SHA
    0346d01 View commit details

Commits on Jul 14, 2022

  1. Copy the full SHA
    b92712f View commit details

Commits on Jul 28, 2022

  1. Copy the full SHA
    55dddb1 View commit details

Commits on Aug 23, 2022

  1. Copy the full SHA
    eb304e8 View commit details

Commits on Sep 8, 2022

  1. Copy the full SHA
    37b2c72 View commit details

Commits on Sep 29, 2022

  1. Copy the full SHA
    4dcb924 View commit details

Commits on Oct 4, 2022

  1. Copy the full SHA
    937b361 View commit details

Commits on Oct 20, 2022

  1. Copy the full SHA
    7f0765a View commit details

Commits on Nov 3, 2022

  1. Copy the full SHA
    4c56783 View commit details

Commits on Nov 17, 2022

  1. Copy the full SHA
    73983e3 View commit details
Showing 696 changed files with 66,353 additions and 16,443 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -9,3 +9,4 @@ composer
/docs-cache/

.idea
/.vscode
642 changes: 642 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<a href="https://github.com/globalpayments" target="_blank">
<img src="https://globalpayments.github.io/images/globapaymentsLogo.png" alt="Global Payments logo" title="Global Payments" align="right" width="225" />
<img src="https://developer.globalpay.com/static/media/logo.db1c4126172e20a5c31cf9d5150cc88a.svg" alt="Global Payments logo" title="Global Payments" align="right" width="225" />
</a>

# Heartland & Global Payments PHP SDK
# Global Payments & Heartland PHP SDK

This SDK makes it easy to integrate your PHP application with our Card Not Present and Card Present APIs.

@@ -32,7 +32,7 @@ This SDK makes it easy to integrate your PHP application with our Card Not Prese

## Requirements

- PHP 5.5.9+
- PHP 8.0.0+
- OpenSSL 1.0.1+
- PHP Curl extension
- PHP DOM extension
@@ -64,7 +64,7 @@ In addition you can find working examples in the our example code repository.

*Quick Tip*: The included [test suite](https://github.com/globalpayments/php-sdk/tree/master/test) can be a great source of code samples for using the SDK!

#### Process a Payment Example
### Process a Payment Example

```csharp
$card = new CreditCardData();
@@ -85,7 +85,7 @@ try {
}
```

#### Test Card Data
### Test Card Data

Name | Number | Exp Month | Exp Year | CVN
----------- | ---------------- | --------- | -------- | ----
@@ -97,7 +97,7 @@ Amex | 374101000000608 | 12 | 2025 | 1234
JCB | 3566000000000000 | 12 | 2025 | 123
Diners Club | 36256000000725 | 12 | 2025 | 123

#### Testing Exceptions
### Testing Exceptions

During your integration you will want to test for specific issuer responses such as 'Card Declined'. Because our sandbox environments do not actually reach out to issuing banks for authorizations, there are specific transaction amounts and/or card numbers that will trigger gateway and issuing bank responses. Please contact your support representative for a complete listing of values used to simulate transaction AVS/CVV results, declines, errors, and other responses that can be caught in your code. Example error handling code:

29 changes: 29 additions & 0 deletions autoload_standalone.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
spl_autoload_register(function ($class) {

// project-specific namespace prefix
$prefix = 'GlobalPayments\\Api\\';

// base directory for the namespace prefix
$base_dir = __DIR__ . '/src/';

// does the class use the namespace prefix?
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
// no, move to the next registered autoloader
return;
}

// get the relative class name
$relative_class = substr($class, $len);

// replace the namespace prefix with the base directory, replace namespace
// separators with directory separators in the relative class name, append
// with .php
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';

// if the file exists, require it
if (file_exists($file)) {
require $file;
}
});
13 changes: 7 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
@@ -11,18 +11,20 @@
}
],
"require": {
"php": ">= 5.5.9",
"php": ">= 8.0",
"ext-curl": "*",
"ext-dom": "*",
"ext-openssl": "*",
"ext-json": "*",
"ext-zlib": "*"
"ext-zlib": "*",
"ext-intl": "*",
"ext-mbstring": "*",
"ext-fileinfo": "*"
},
"require-dev": {
"phpunit/phpunit": "~5.0",
"brianium/paratest": "dev-master",
"phpunit/phpunit": "^7.5 || ^8.5 || ~9.4",
"squizlabs/php_codesniffer": "2.*",
"phpstan/phpstan-shim": "^0.8.4"
"phpstan/phpstan": "^0.12"
},
"autoload": {
"psr-4": {
@@ -37,7 +39,6 @@
"scripts": {
"docs": "@php sami.phar update docs-config.php",
"pretest": "@composer test:lint",
"test": "@composer pretest && paratest --coverage-html=coverage.html --colors -f --stop-on-failure",
"test:lint": "phpcs"
},
"config": {
4,654 changes: 1,669 additions & 2,985 deletions composer.lock

Large diffs are not rendered by default.

340 changes: 0 additions & 340 deletions examples/consumer-authentication/cruise.php

This file was deleted.

43 changes: 43 additions & 0 deletions examples/gp-api/alipay/GenerateToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

require_once('../../../autoload_standalone.php');

use GlobalPayments\Api\Entities\Enums\Channel;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig;
use GlobalPayments\Api\Services\GpApiService;

class GenerateToken
{
const APP_ID = 'bvKLJsu6vYC9zxX2BpOgNK95kbboP3Uw';
const APP_KEY = '7aH9QlA3yVFwpESQ';
const ACCOUNT_ID = 'TRA_1366cd0db8c14fffb130ab49be84d944';

private static $instance = null;
private string $accessToken;

private function __construct()
{
$config = new GpApiConfig();
$config->appId = self::APP_ID;
$config->appKey = self::APP_KEY;
$config->channel = Channel::CardNotPresent;
$config->permissions = ["PMT_POST_Create_Single","ACC_GET_Single"];

$accessTokenInfo = GpApiService::generateTransactionKey($config);
$this->accessToken = $accessTokenInfo->accessToken;
}

public static function getInstance()
{
if (!self::$instance) {
self::$instance = new GenerateToken();
}

return self::$instance;
}

public function getAccessToken()
{
return $this->accessToken;
}
}
44 changes: 44 additions & 0 deletions examples/gp-api/alipay/PRESENT-QR-CODE.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"id": "TRN_TkrpUT1M83f20231017125212740",
"time_created": "2023-10-17T12:52:13.968Z",
"type": "SALE",
"status": "INITIATED",
"channel": "CNP",
"capture_mode": "AUTO",
"amount": "102",
"currency": "MOP",
"country": "MO",
"merchant_id": "MER_fba638a644644c7ab1fb8c148289452d",
"merchant_name": "product_production_test",
"account_id": "TRA_2642234293e34e9b9a4c01b44deaeab7",
"account_name": "apm_ap",
"reference": "92293801",
"payment_method": {
"result": "S0000",
"message": "Waiting for user to make payment",
"entry_mode": "ECOM",
"apm": {
"provider": {
"result": "SUCCESS",
"message": "Success",
"brand": "WECHAT",
"action": "PAYMENT",
"time_created_reference": "2023-10-17T20:52:13Z",
"name": "WeChat_Pay",
"merchant_identifier": "141928866"
},
"category": "E_WALLET",
"seconds_to_expire": "900",
"next_action": "PRESENT_QR_CODE"
},
"qr_code": "weixin://wxpay/bizpayurl?pr=0gWQb9Zzz"
},
"action": {
"id": "ACT_GWvKXqwDEzT4XfVYzzPYv03TYHzgOF",
"type": "INITIATE",
"time_created": "2023-10-17T12:52:13.968Z",
"result_code": "SUCCESS",
"app_id": "pwgpvp0ictNp99MEZebNLy2wSHgKZ1Hd",
"app_name": "product_production_ap_apm"
}
}
32 changes: 32 additions & 0 deletions examples/gp-api/alipay/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
session_start();
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once('GenerateToken.php');
$accessToken = GenerateToken::getInstance()->getAccessToken();
$account = GenerateToken::ACCOUNT_ID;
?>
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Global Payments end-to-end with GP-API example</title>
<link rel="stylesheet" href="styles.css" />
<script src="https://js-cert.globalpay.com/2.1.2/globalpayments.js"></script>
<script>
let accessToken = "<?= $accessToken ?>";
let account = "<?= $account ?>";
</script>
<script defer src="main.js"></script>
</head>
<body>
<div class="container">
<p>Amount: 100 EUR</p>
<div id="digital-wallet-form"></div>
<!-- Target for the credit card form -->
<div id="credit-card"></div>
</div>
</body>
</html>
61 changes: 61 additions & 0 deletions examples/gp-api/alipay/initiatePayment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
session_start();
require_once('../../../autoload_standalone.php');
require_once('GenerateToken.php');

use GlobalPayments\Api\Entities\Enums\AlternativePaymentType;
use GlobalPayments\Api\Entities\Enums\Channel;
use GlobalPayments\Api\Entities\Enums\MerchantCategory;
use GlobalPayments\Api\Entities\Exceptions\ApiException;
use GlobalPayments\Api\PaymentMethods\AlternativePaymentMethod;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig;
use GlobalPayments\Api\ServicesContainer;
use GlobalPayments\Api\Utils\Logging\SampleRequestLogger;
use GlobalPayments\Api\Utils\Logging\Logger;
use GlobalPayments\Api\Entities\GpApi\AccessTokenInfo;

$provider = $_GET['provider'] ?? '';

if ($provider === 'WeChat') {
$provider = AlternativePaymentType::WECHAT_PAY;
} else {
$provider = strtolower($provider);
}

// configure client & request settings
$config = new GpApiConfig();
$config->appId = GenerateToken::APP_ID;
$config->appKey = GenerateToken::APP_KEY;
$config->channel = Channel::CardNotPresent;
$config->country = 'HK';
$config->accessTokenInfo = new AccessTokenInfo();
$config->accessTokenInfo->transactionProcessingAccountID = GenerateToken::ACCOUNT_ID;
$config->requestLogger = new SampleRequestLogger(new Logger("logs"));
ServicesContainer::configureService($config);

$paymentMethod = new AlternativePaymentMethod($provider);
$paymentMethod->returnUrl = $_SERVER['HTTP_ORIGIN'] . '/examples/gp-api/alipay/returnUrl';
$paymentMethod->statusUpdateUrl = $_SERVER['HTTP_ORIGIN'] . '/examples/gp-api/alipay/returnUrl';
$paymentMethod->country = 'HK';
$paymentMethod->accountHolderName = 'Jane Doe';

try {
$response = $paymentMethod->charge(19.99)
->withCurrency('HKD')
->withMerchantCategory(MerchantCategory::OTHER)
->execute();
} catch (ApiException $e) {
// TODO: add your error handling here
print_r($e);
}

// simple example of how to prepare the JSON string for JavaScript Library
$responseJson = array(
"seconds_to_expire" => $response->alternativePaymentResponse->secondsToExpire ?? '120',
"next_action" => $response->alternativePaymentResponse->nextAction ?? '',
"redirect_url" => $response->alternativePaymentResponse->redirectUrl ?? '',
"qr_code" => $response->alternativePaymentResponse->qrCodeImage ?? '',
"provider" => $response->alternativePaymentResponse->providerName ?? ''
);

echo json_encode($responseJson);
46 changes: 46 additions & 0 deletions examples/gp-api/alipay/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Configure account
GlobalPayments.configure({
accessToken,
env: "sandbox", // or "production"
apiVersion: "2021-03-22",
account: account,
// merchantId: merchantId,
apms: {
currencyCode: "USD",
allowedCardNetworks: [GlobalPayments.enums.CardNetwork.Visa, GlobalPayments.enums.CardNetwork.Mastercard, GlobalPayments.enums.CardNetwork.Amex, GlobalPayments.enums.CardNetwork.Discover],
qrCodePayments: {
enabled: true
}
}
});

// Create Form
const cardForm = GlobalPayments.creditCard.form(
'#credit-card',
{
amount: "20",
style: "gp-default",
apms: [
GlobalPayments.enums.Apm.QRCodePayments,
],
});

cardForm.on("token-success", function (resp) { console.log(resp); });
cardForm.on("token-error", function (resp) { console.log(resp); });

cardForm.on(GlobalPayments.enums.QRCodePaymentsMerchantInteractionEvents.PaymentMethodSelection, function (qrCodePaymentProviderData) {
const { provider } = qrCodePaymentProviderData;
let initiatePaymentResponse = null;
const xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function() {
initiatePaymentResponse = JSON.parse(this.responseText);
console.log(initiatePaymentResponse);
const merchantCustomEventProvideDetails = new CustomEvent(GlobalPayments.enums.QRCodePaymentsMerchantInteractionEvents.ProvideQRCodeDetailsMerchantEvent, {
detail: initiatePaymentResponse,
});
window.dispatchEvent(merchantCustomEventProvideDetails);
}

xmlhttp.open("GET", "initiatePayment.php?provider=" + provider);
xmlhttp.send();
});
13 changes: 13 additions & 0 deletions examples/gp-api/alipay/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.container {
background-color: #f2f2f2;
padding: 5px 20px 15px 20px;
border: 1px solid lightgrey;
border-radius: 10px;
max-width: 500px;
margin-left: auto;
margin-right: auto;
}

iframe[id^="secure-payment-field"] {
min-height: 66px !important;
}
42 changes: 42 additions & 0 deletions examples/gp-api/end-to-end/GenerateToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

require_once('../../../autoload_standalone.php');

use GlobalPayments\Api\Entities\Enums\Channel;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig;
use GlobalPayments\Api\Services\GpApiService;

class GenerateToken
{
const APP_ID = 'UJqPrAhrDkGzzNoFInpzKqoI8vfZtGRV';
const APP_KEY = 'zCFrbrn0NKly9sB4';

private static $instance = null;
private $accessToken;

private function __construct()
{
$config = new GpApiConfig();
$config->appId = self::APP_ID;
$config->appKey = self::APP_KEY;
$config->channel = Channel::CardNotPresent;
$config->permissions = ["PMT_POST_Create_Single"];

$accessTokenInfo = GpApiService::generateTransactionKey($config);
$this->accessToken = $accessTokenInfo->accessToken;
}

public static function getInstance()
{
if(!self::$instance) {
self::$instance = new GenerateToken();
}

return self::$instance;
}

public function getAccessToken()
{
return $this->accessToken;
}
}
124 changes: 124 additions & 0 deletions examples/gp-api/end-to-end/authorization.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once('../../../autoload_standalone.php');
require_once('GenerateToken.php');

use GlobalPayments\Api\Entities\Enums\Environment;
use GlobalPayments\Api\Entities\Enums\Channel;
use GlobalPayments\Api\Entities\Exceptions\ApiException;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig;
use GlobalPayments\Api\Services\Secure3dService;
use GlobalPayments\Api\ServicesContainer;
use GlobalPayments\Api\Entities\Enums\Secure3dStatus;
use GlobalPayments\Api\PaymentMethods\CreditCardData;

$requestData = $_REQUEST;
$serverTransactionId = $requestData['serverTransactionId'];
$paymentToken = $requestData['tokenResponse'];

console_log($serverTransactionId);
function console_log($data)
{
$data = htmlspecialchars($data, ENT_NOQUOTES);
echo '<script>';
echo 'if(' . $data . ') {';
echo 'console.log(' . json_encode($data) . ')';
echo '}';
echo '</script>';
}

// configure client & request settings
$config = new GpApiConfig();
$config->appId = GenerateToken::APP_ID;
$config->appKey = GenerateToken::APP_KEY;
$config->environment = Environment::TEST;
$config->country = 'GB';
$config->channel = Channel::CardNotPresent;
$config->merchantContactUrl = "https://www.example.com/about";
$config->methodNotificationUrl = $_SERVER['HTTP_ORIGIN'] . '/gp-api/end-to-end/methodNotificationUrl.php';
$config->challengeNotificationUrl = $_SERVER['HTTP_ORIGIN'] . '/gp-api/end-to-end/challengeNotificationUrl.php';
ServicesContainer::configureService($config);

try {
$secureEcom = Secure3dService::getAuthenticationData()
->withServerTransactionId($serverTransactionId)
->execute();
} catch (ApiException $e) {
//TODO: Add your error handling here
var_dump('Obtain Authentication error:', $e);
}

$authenticationValue = $secureEcom->authenticationValue;
$dsTransId = $secureEcom->directoryServerTransactionId;
$messageVersion = $secureEcom->messageVersion;
$eci = $secureEcom->eci;
?>
<!DOCTYPE html>
<html>

<head>
<title>3D Secure 2 Authentication</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
<h2>3D Secure 2 Authentication</h2>
<?php
$condition = ($secureEcom->liabilityShift != 'YES' ||
!in_array(
$secureEcom->status,
[
Secure3dStatus::SUCCESS_AUTHENTICATED,
Secure3dStatus::SUCCESS_ATTEMPT_MADE
]
));
if (empty($condition) && !$condition) {
echo "<p><strong>Hurray! Your trasaction was authenticated successfully!</strong></p>";
} else {
echo "<p><strong>Oh Dear! Your trasaction was not authenticated successfully!</strong></p>";
}
?>
<p>Server Trans ID: <?= !empty($serverTransactionId) ? htmlspecialchars($serverTransactionId, ENT_NOQUOTES) : "" ?></p>
<p>Authentication Value: <?= !empty($authenticationValue) ? $authenticationValue : "" ?></p>
<p>DS Trans ID: <?= $dsTransId ?></p>
<p>Message Version: <?= $messageVersion ?></p>
<p>ECI: <?= $eci ?></p>

<pre>
<?php
print_r(htmlspecialchars(json_encode($secureEcom), ENT_NOQUOTES));
?>
</pre>
<h2>Transaction details:</h2>
<?php
if (!$condition) {
$paymentMethod = new CreditCardData();
$paymentMethod->token = $paymentToken;
$paymentMethod->threeDSecure = $secureEcom;
// proceed to authorization with liability shift
try {
$response = $paymentMethod->charge(100)
->withCurrency('EUR')
->execute();
} catch (ApiException $e) {
// TODO: Add your error handling here
var_dump('Error message:', $e->getMessage());
}
if (!empty($response)) {
$transactionId = $response->transactionId;
$transactionStatus = $response->responseMessage;
}
}
?>
<p>Trans ID: <?= $transactionId ?? null ?></p>
<p>Trans status: <?= $transactionStatus ?? null ?></p>
<pre>
<?php
if (!empty($response)) {
print_r($response);
}
?>
</pre>
46 changes: 46 additions & 0 deletions examples/gp-api/end-to-end/challengeNotificationUrl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php
/*
* this sample code is not specific to the Global Payments SDK and is intended as a simple example and
* should not be treated as Production-ready code. You'll need to add your own message parsing and
* security in line with your application or website
*/
$cres = $_REQUEST['cres'];

/* $cres = "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImFmNjVjMzY5LTU5YjktNGY4ZC1iMmY2LTdkN2Q1ZjVjNjlkNSIsImF"
* . "jc1RyYW5zSUQiOiIxM2M3MDFhMy01YTg4LTRjNDUtODllOS1lZjY1ZTUwYThiZjkiLCJjaGFsbGVuZ2VDb21wbGV0a"
* . "W9uSW5kIjoiWSIsIm1lc3NhZ2VUeXBlIjoiQ3JlcyIsIm1lc3NhZ2VWZXJzaW9uIjoiMi4xLjAiLCJ0cmFuc"
* . "1N0YXR1cyI6IlkifQ==";
*/


try {
$decodedString = base64_decode($cres);
if (!empty($decodedString)) {
$convertedObject = json_decode(htmlspecialchars($decodedString, ENT_NOQUOTES), true);
}

date_default_timezone_set('Europe/Dublin');
$file = fopen("challengeNotificationUrl.log", "a") or die("Unable to open file!");
fwrite($file, "\n\n**************************\n");
fwrite($file, date('Y-m-d H:i:s') . " Request Log: \n");
fwrite($file, print_r($decodedString, true));
fwrite($file, "\n**************************\n\n");
fclose($file);

$serverTransID = htmlspecialchars($convertedObject['threeDSServerTransID'], ENT_NOQUOTES);
$acsTransID = $convertedObject['acsTransID'] ?? null;
$messageType = $convertedObject['messageType'] ?? null;
$messageVersion = $convertedObject['messageVersion'] ?? null;
$transStatus = $convertedObject['transStatus'];

// TODO: notify client-side that the Challenge step is complete, see below
} catch (Exception $exce) {
// TODO: Add your exception handling here
}
?>
<script src="globalpayments-3ds.js"></script>
<script>
GlobalPayments.ThreeDSecure.handleChallengeNotification({
"threeDSServerTransID": <?php echo '"' . (isset($serverTransID) ? htmlspecialchars($serverTransID, ENT_NOQUOTES) : "") . '"'; ?>,
"transStatus": <?php echo '"' . ($transStatus ? htmlspecialchars($transStatus, ENT_NOQUOTES) : "") . '"}'; ?>);
</script>
69 changes: 69 additions & 0 deletions examples/gp-api/end-to-end/check3dsVersion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
session_start();
require_once('../../../autoload_standalone.php');
require_once('GenerateToken.php');

use GlobalPayments\Api\Entities\Enums\Environment;
use GlobalPayments\Api\Entities\Enums\Channel;
use GlobalPayments\Api\Entities\Exceptions\ApiException;
use GlobalPayments\Api\PaymentMethods\CreditCardData;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig;
use GlobalPayments\Api\Services\Secure3dService;
use GlobalPayments\Api\ServicesContainer;
use \GlobalPayments\Api\Entities\Enums\Secure3dVersion;

// TODO: consume card data sent from the JS Library ($requestData)

$decodedData = json_decode(file_get_contents('php://input'));
$paymenttoken = $decodedData->tokenResponse;

// configure client & request settings
$config = new GpApiConfig();
$config->appId = GenerateToken::APP_ID;
$config->appKey = GenerateToken::APP_KEY;
$config->environment = Environment::TEST;
$config->country = 'GB';
$config->channel = Channel::CardNotPresent;
$config->methodNotificationUrl = $_SERVER['HTTP_ORIGIN'] . '/gp-api/end-to-end/methodNotificationUrl.php';;
$config->merchantContactUrl = "https://www.example.com/about";
$config->challengeNotificationUrl = $_SERVER['HTTP_ORIGIN'] . '/gp-api/end-to-end/challengeNotificationUrl.php';

ServicesContainer::configureService($config);

$card = new CreditCardData();
$card->token = $paymenttoken;

try {
$threeDSecureData = Secure3dService::checkEnrollment($card)
->withCurrency("EUR")
->withAmount(100)
->execute();
} catch (ApiException $e) {
// TODO: add your error handling here
print_r($e);
}

$enrolled = $threeDSecureData->enrolled; // ENROLLED
// if enrolled, the available response data
$serverTransactionId = $threeDSecureData->serverTransactionId;
$messageVersion = $threeDSecureData->getVersion();
$methodUrl = $threeDSecureData->issuerAcsUrl;
$encodedMethodData = $threeDSecureData->payerAuthenticationRequest; // Base64 encoded string
$payerAuthenticationRequest = $threeDSecureData->payerAuthenticationRequest;
$issuerAcsUrl = $threeDSecureData->issuerAcsUrl;

// simple example of how to prepare the JSON string for JavaScript Library
$responseJson = array(
"enrolled" => $enrolled,
"messageVersion" => $messageVersion
);

if ($enrolled === "ENROLLED" && $messageVersion === Secure3dVersion::TWO) {
$responseJson["serverTransactionId"] = $serverTransactionId;
$responseJson["methodUrl"] = $methodUrl;
$responseJson["methodData"] = $encodedMethodData;
}

$responseJson = json_encode($responseJson);

echo $responseJson;
1,824 changes: 1,824 additions & 0 deletions examples/gp-api/end-to-end/globalpayments-3ds.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions examples/gp-api/end-to-end/globalpayments-3ds.min.js.map

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions examples/gp-api/end-to-end/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
session_start();
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once('GenerateToken.php');
$accessToken = GenerateToken::getInstance()->getAccessToken();
?>
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Global Payments end-to-end with GP-API example</title>
<link rel="stylesheet" href="styles.css" />
<script src="https://js.globalpay.com/3.0.8/globalpayments.js"></script>
<script src="globalpayments-3ds.js"></script>
<script>
let accessToken = "<?= $accessToken ?>";
</script>
<script defer src="main.js"></script>
</head>
<body>
<div class="container">
<p>3DS test card with CHALLENGE_REQUIRED: 4012 0010 3848 8884</p>
<p>Amount: 100 EUR</p>
<form id="payment-form" method="post">
<!-- Target for the credit card form -->
<div id="credit-card"></div>
</form>
</div>
</body>
</html>
118 changes: 118 additions & 0 deletions examples/gp-api/end-to-end/initiateAuthentication.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

/**
* This sample code is not specific to the Global Payments SDK and is intended as a simple example and
* should not be treated as Production-ready code. You'll need to add your own message parsing and
* security in line with your application or website
*/

/**
* Merchant integration endpoint responsible for performing the authentication request
*/

require_once('../../../autoload_standalone.php');
require_once('GenerateToken.php');

use GlobalPayments\Api\Entities\Address;
use GlobalPayments\Api\Entities\BrowserData;
use GlobalPayments\Api\Entities\Enums\AddressType;
use GlobalPayments\Api\Entities\Enums\Channel;
use GlobalPayments\Api\Entities\Enums\Environment;
use GlobalPayments\Api\Entities\Enums\MethodUrlCompletion;
use GlobalPayments\Api\Entities\Exceptions\ApiException;
use GlobalPayments\Api\Entities\ThreeDSecure;
use GlobalPayments\Api\PaymentMethods\CreditCardData;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig;
use GlobalPayments\Api\Services\Secure3dService;
use GlobalPayments\Api\ServicesContainer;

$requestData = json_decode(file_get_contents('php://input'));

$config = new GpApiConfig();
$config->appId = GenerateToken::APP_ID;
$config->appKey = GenerateToken::APP_KEY;
$config->environment = Environment::TEST;
$config->country = 'GB';
$config->channel = Channel::CardNotPresent;
$config->merchantContactUrl = "https://www.example.com/contact-us";
$config->methodNotificationUrl = $_SERVER['HTTP_ORIGIN'] . '/gp-api/end-to-end/methodNotificationUrl.php';
$config->challengeNotificationUrl = $_SERVER['HTTP_ORIGIN'] . '/gp-api/end-to-end/challengeNotificationUrl.php';

ServicesContainer::configureService($config);

$billingAddress = new Address();
$billingAddress->streetAddress1 = "Apartment 852";
$billingAddress->streetAddress2 = "Complex 741";
$billingAddress->streetAddress3 = "Unit 4";
$billingAddress->city = "Chicago";
$billingAddress->state = "IL";
$billingAddress->postalCode = "50001";
$billingAddress->countryCode = "840";

$shippingAddress = new Address();
$shippingAddress->streetAddress1 = "Flat 456";
$shippingAddress->streetAddress2 = "House 789";
$shippingAddress->streetAddress3 = "Basement Flat";
$shippingAddress->city = "Halifax";
$shippingAddress->postalCode = "W5 9HR";
$shippingAddress->countryCode = "826";

// TODO: Add captured browser data from the client-side and server-side
$browserData = new BrowserData();
$browserData->acceptHeader = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : '';
$browserData->colorDepth = $requestData->browserData->colorDepth;
$browserData->ipAddress = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
$browserData->javaEnabled = $requestData->browserData->javaEnabled ?? false;
$browserData->javaScriptEnabled = $requestData->browserData->javascriptEnabled;
$browserData->language = $requestData->browserData->language;
$browserData->screenHeight = $requestData->browserData->screenHeight;
$browserData->screenWidth = $requestData->browserData->screenWidth;
$browserData->challengWindowSize = $requestData->challengeWindow->windowSize;
$browserData->timeZone = $requestData->browserData->timezoneOffset;
$browserData->userAgent = $requestData->browserData->userAgent;

$paymentMethod = new CreditCardData();
$paymentMethod->token = $requestData->tokenResponse;
$paymentMethod->cardHolderName = "James Mason";

$threeDSecureData = new ThreeDSecure();
$threeDSecureData->serverTransactionId = $requestData->serverTransactionId;
$methodUrlCompletion = MethodUrlCompletion::YES;
try {
$threeDSecureData = Secure3dService::initiateAuthentication($paymentMethod, $threeDSecureData)
->withAmount($requestData->order->amount)
->withCurrency($requestData->order->currency)
->withOrderCreateDate(date('Y-m-d H:i:s'))
->withAddress($billingAddress, AddressType::BILLING)
->withAddress($shippingAddress, AddressType::SHIPPING)
->withAddressMatchIndicator(false)
->withAuthenticationSource($requestData->authenticationSource)
->withBrowserData($browserData)
->withMethodUrlCompletion($methodUrlCompletion)
->execute();
} catch (ApiException $e) {
// TODO: add your error handling here
print_r($e);
}

$status = $threeDSecureData->status;
$response = array();
$response['liabilityShift'] = $threeDSecureData->liabilityShift;

if ($status !== "CHALLENGE_REQUIRED") {
// Frictionless flow
$response['result'] = $threeDSecureData->status;
$response['authenticationValue'] = $threeDSecureData->authenticationValue;
$response['serverTransactionId'] = $threeDSecureData->serverTransactionId;
$response['messageVersion'] = $threeDSecureData->messageVersion;
$response['eci'] = $threeDSecureData->eci;
} else {
//Challenge flow
$response['status'] = $threeDSecureData->status; // CHALLENGE_REQUIRED
$response['challengeMandated'] = $threeDSecureData->challengeMandated;
$response['challenge']['requestUrl'] = $threeDSecureData->issuerAcsUrl;
$response['challenge']['encodedChallengeRequest'] = $threeDSecureData->payerAuthenticationRequest;
$response['challenge']['messageType'] = $threeDSecureData->messageType;
}

echo htmlspecialchars(json_encode($response), ENT_NOQUOTES);
270 changes: 270 additions & 0 deletions examples/gp-api/end-to-end/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
// Configure account
GlobalPayments.configure({
accessToken,
env: "sandbox", // or "production"
apiVersion: "2021-03-22"
});

// Create Form
const cardForm = GlobalPayments.creditCard.form("#credit-card", {style: "gp-default"});
// form-level event handlers. examples:
cardForm.ready(() => {
console.log("Registration of all credit card fields occurred");
cardForm.addStylesheet({
'#secure-payment-field-wrapper': {
'display': 'block !important'
},
/* Card number Field error messages*/
/* Display error if card is not valid */
'#secure-payment-field.card-number.invalid + .extra-div-1::before': {
'content': '"The Card Number is not valid"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if card length is not reached*/
'#secure-payment-field.card-number.possibly-valid.invalid + .extra-div-1::before': {
'content': '"The Card Number is not valid"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if card used is Diners*/
'#secure-payment-field.card-number.valid.card-type-diners + .extra-div-1::before': {
'content': '"Cannot use Diners Card. Please enter another card"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if card used is Discover*/
'#secure-payment-field.card-number.valid.card-type-discover + .extra-div-1::before': {
'content': '"Cannot use Discover Card. Please enter another card"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if card used is JCB*/
'#secure-payment-field.card-number.valid.card-type-jcb + .extra-div-1::before': {
'content': '"Cannot use JCB Card. Please enter another card"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if card used is unknown*/
'#secure-payment-field.card-number.possibly-valid.invalid.card-type-unknown + .extra-div-1::before': {
'content': '"Cannot use unknown Card. Please enter another card"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},

/* Expiry Date error messages*/
/* Display error if expiry date is not valid*/
'#secure-payment-field.card-expiration.possibly-valid.invalid + .extra-div-1::before': {
'content': '"Please enter a valid month/year"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if expiry date is in past*/
'#secure-payment-field.card-expiration.invalid + .extra-div-1::before': {
'content': '"The Expiry Date is not valid"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},

/* Security Code error messages*/
/* Display error if security code is too short*/
'#secure-payment-field.card-cvv.possibly-valid.invalid + .extra-div-1::before': {
'content': '"Security Code is too short"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if security code too long for Visa*/
'#secure-payment-field.card-cvv.invalid.card-type-visa + .extra-div-1::before': {
'content': '"Security Code must be 3 digits"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if security code too long for MC*/
'#secure-payment-field.card-cvv.invalid.card-type-mastercard + .extra-div-1::before': {
'content': '"Security Code must be 3 digits"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
/* Display error if security code too short for Amex*/
'#secure-payment-field.card-cvv.card-type-amex.possibly-valid.invalid + .extra-div-1::before': {
'content': '"Security Code for Amex must be 4 digits"',
'color': 'red',
'height': '1em',
'min-height': '1em',
'width': '100%'
},
});
});

cardForm.on("token-success", async (resp) => {

//start 3DS2 Flow
await start3DS(resp.paymentReference);

// add payment token to form as a hidden input
const token = document.createElement("input");
token.type = "hidden";
token.name = "payment_token";
token.value = resp.paymentReference;

// Submit data to the integration's backend for processing
const form = document.getElementById("payment-form");
form.appendChild(token);
});

cardForm.on("token-error", (resp) => {
// show error to the consumer
console.log(resp);

});

async function start3DS(token){
const {
checkVersion,
getBrowserData,
initiateAuthentication,
AuthenticationSource,
AuthenticationRequestType,
MessageCategory,
ChallengeRequestIndicator,
ChallengeWindowSize,
postToIframe,
handleInitiateAuthentication,
} = GlobalPayments.ThreeDSecure;

try {
versionCheckData = await checkVersion('check3dsVersion.php', {
tokenResponse:token
});

console.log ('Version Check Data: ', versionCheckData)
}
catch (e) {
console.log ('Version Check error: ', e.reasons || e.message);
}
try {
// 3DS2 Flow
if (versionCheckData.messageVersion == 'TWO') {
console.log("3ds2 flow")
authenticateData = await initiateAuthentication('initiateAuthentication.php', {
challengeWindow: {
windowSize: ChallengeWindowSize.Windowed600x400,
displayMode: 'lightbox',
},
authenticationRequestType: AuthenticationRequestType.PaymentTransaction,
serverTransactionId: versionCheckData.serverTransactionId,
methodUrlComplete: true,
tokenResponse: token,
order: {
currency: 'EUR',
amount: '100'
}
});
console.log('Authentication Data:', authenticateData);
// frictionless authentication success and authorization success
if (authenticateData.result == "SUCCESS_AUTHENTICATED" && authenticateData.liabilityShift == 'YES') {
var form = document.getElementById("payment-form");
form.setAttribute("action", "authorization.php");
var formServerTransId = document.createElement("input");
formServerTransId.setAttribute("type", "hidden");
formServerTransId.setAttribute("name", "serverTransactionId");
formServerTransId.setAttribute("value", authenticateData.serverTransactionId);
var paymentToken = document.createElement("input");
paymentToken.setAttribute("type", "hidden");
paymentToken.setAttribute("name", "tokenResponse");
paymentToken.setAttribute("value", token);
console.log('PMT:', token);
form.appendChild(formServerTransId);
form.appendChild(paymentToken);
form.submit();
}

// frictionless authentication success and authorization failure
else if (authenticateData.result == "AUTHORIZATION_FAILURE") {
// TODO: proceed to failure page or display decline information
responseDiv.style.display = "block";
responseDiv.innerHTML+= "<strong>Oh Dear! Frictionless authentication but your transaction was not authorized successfully.</strong>";
responseDiv.innerHTML+= "<br><br>Server Trans ID :" + authenticateData.serverTransId;
responseDiv.innerHTML+= "<br><br>Authentication Value :" + authenticateData.authenticationValue;
responseDiv.innerHTML+= "<br><br>DS Trans ID :" + authenticateData.dsTransId;
responseDiv.innerHTML+= "<br><br>Message Version :" + authenticateData.messageVersion;
responseDiv.innerHTML+= "<br><br>ECI :" + authenticateData.eci;
responseDiv.innerHTML+= "<br><br>Result :" + authenticateData.resultCode;
responseDiv.innerHTML+= "<br><br>Message :" + authenticateData.resultMessage;
responseDiv.innerHTML+= "<br><br>Order ID :" + authenticateData.orderId;
responseDiv.innerHTML+= "<br><br>Pasref :" + authenticateData.pasref;
}

// frictionless authentication success and authorization failure
else if (authenticateData.result == "AUTHENTICATION_FAILURE") {
// TODO: proceed to failure page or display failed authentication information
responseDiv.style.display = "block";
responseDiv.innerHTML+= "<strong>Oh No! Your transaction failed authentication.</strong>";
responseDiv.innerHTML+= "<br><br>Server Trans ID: " + authenticateData.serverTransId;
if(authenticateData.authenticationValue) {responseDiv.innerHTML+= "<br><br>Authentication Value: " + authenticateData.authenticationValue;}
else{responseDiv.innerHTML+= "<br><br>The 3D Secure 2 Solution threw an error.";}
if(authenticateData.dsTransId){responseDiv.innerHTML+= "<br><br>DS Trans ID: " + authenticateData.dsTransId;}
if(authenticateData.messageVersion){responseDiv.innerHTML+= "<br><br>Message Version: " + authenticateData.messageVersion;}
if(authenticateData.eci){responseDiv.innerHTML+= "<br><br>ECI: " + authenticateData.eci;}
if(authenticateData.status){responseDiv.innerHTML+= "<br><br>Status: " + authenticateData.status;}
if(authenticateData.statusReason){responseDiv.innerHTML+= "<br><br>Status Reason: " + authenticateData.statusReason;}
}
// challenge success
else if (authenticateData.challenge.response.data.transStatus == "Y") {
var serverTransactionId = authenticateData.challenge.response.data.threeDSServerTransID;
console.log('Challenge:', serverTransactionId);
var form = document.getElementById("payment-form");
form.setAttribute("action", "authorization.php");

var formServerTransId = document.createElement("input");
formServerTransId.setAttribute("type", "hidden");
formServerTransId.setAttribute("name", "serverTransactionId");
formServerTransId.setAttribute("value", serverTransactionId);
var paymentToken = document.createElement("input");
paymentToken.setAttribute("type", "hidden");
paymentToken.setAttribute("name", "tokenResponse");
paymentToken.setAttribute("value", token);
console.log('PMT:', token);
form.appendChild(formServerTransId);
form.appendChild(paymentToken);
form.submit();
}
// challenge failure
else {
// TODO: proceed to failure page or display failed authentication information
console.log ('else error')
return false;
}
} else {
console.log('3DS version not implemented!')
return false;
}
}
catch (e) {
console.log('Initiate Authentication Error: ', e.reasons || e.message);
return;
}
return false;
};
30 changes: 30 additions & 0 deletions examples/gp-api/end-to-end/methodNotificationUrl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
/*
* this sample code is not specific to the Global Payments SDK and is intended as a simple example and
* should not be treated as Production-ready code. You'll need to add your own message parsing and
* security in line with your application or website
*/
$threeDSMethodData = $_REQUEST["threeDSMethodData"];

// sample ACS response for Method URL Response Notification
// $threeDSMethodData = "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImFmNjVjMzY5LTU5YjktNGY4ZC1iMmY2LTdkN2Q1ZjVjNjlkNSJ9";

try {
$decodedThreeDSMethodData = base64_decode($threeDSMethodData);
if (!empty($decodedThreeDSMethodData)) {
$convertedThreeDSMethodData = json_decode(htmlspecialchars($decodedThreeDSMethodData, ENT_NOQUOTES), true);
$serverTransID = htmlspecialchars($convertedThreeDSMethodData['threeDSServerTransID'], ENT_NOQUOTES);
}

// TODO: notify client-side that the Method URL step is complete
// optional to return decoded JSON string, see below
} catch (Exception $exce) {
// TODO: Add your exception handling here
}
?>
<script src="globalpayments-3ds.js"></script>
<script>
<?php if (isset($serverTransID)) { ?>
GlobalPayments.ThreeDSecure.handleMethodNotification(<?php echo '"' . $serverTransID . '"'; ?>);
<?php } ?>
</script>
13 changes: 13 additions & 0 deletions examples/gp-api/end-to-end/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.container {
background-color: #f2f2f2;
padding: 5px 20px 15px 20px;
border: 1px solid lightgrey;
border-radius: 10px;
max-width: 500px;
margin-left: auto;
margin-right: auto;
}

iframe[id^="secure-payment-field"] {
min-height: 66px !important;
}
56 changes: 56 additions & 0 deletions examples/gp-api/google-pay/charge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

require_once ('../.././../autoload_standalone.php');

use GlobalPayments\Api\Entities\Enums\EncyptedMobileType;
use GlobalPayments\Api\Entities\Enums\Environment;
use GlobalPayments\Api\Entities\Enums\Channel;
use GlobalPayments\Api\Entities\Enums\TransactionModifier;
use GlobalPayments\Api\PaymentMethods\CreditCardData;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpApiConfig;
use GlobalPayments\Api\ServicesContainer;
use GlobalPayments\Api\Utils\Logging\Logger;
use GlobalPayments\Api\Utils\Logging\SampleRequestLogger;

$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

/**
* The Google Pay token. If you have any input filtering on $_POST, you will need
* to use htmlspecialchars_decode, otherwise this will not be a valid JSON anymore
* and the API will throw an error
*/
$googlePayToken = htmlspecialchars_decode($_POST['googlePayToken']);

/**
* Replace the '\\' with '\' so the encoded characters won't be decoded.
* If your code adds extra backslashes ('\') the the string, you will need to manipulate it
* in order to look like the one from test/Integration/Gateways/GpApiConnector/GpApiDigitalWalletTest.php
*/
$googlePayToken = str_replace('\\\\', '\\', $googlePayToken);

$config = new GpApiConfig();
$config->appId = 'i872l4VgZRtSrykvSn8Lkah8RE1jihvT';
$config->appKey = '9pArW2uWoA8enxKc';
$config->environment = Environment::TEST;
$config->channel = Channel::CardNotPresent;
$config->requestLogger = new SampleRequestLogger(new Logger("logs"));

ServicesContainer::configureService($config);

$card = new CreditCardData();
$card->token = $googlePayToken;
$card->mobileType = EncyptedMobileType::GOOGLE_PAY;

try {
$transaction = $card->charge('10')
->withCurrency('GBP')
->withModifier(TransactionModifier::ENCRYPTED_MOBILE)
->execute();

echo '<b>Transaction successful, your transaction id is: </b>' . $transaction->transactionId;
echo '<br />';
echo '<b>Transaction status: </b>' . $transaction->responseMessage;
} catch (\Exception $e) {
echo 'Failure: ' . $e->getMessage();
exit;
}
19 changes: 19 additions & 0 deletions examples/gp-api/google-pay/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Global Payments Google Pay with GP-API example</title>
<link rel="stylesheet" href="styles.css" />
<script defer src="main.js"></script>
<script defer
src="https://pay.google.com/gp/p/js/pay.js"
onload="onGooglePayLoaded()"></script>
</head>
<body>
<div id="container"></div>
<p class="error hide">In order to process payments via Google Pay, please switch to HTTPS.</p>
<form id="form" action="charge.php" method="POST">
<input type="hidden" id="googlePayToken" name="googlePayToken" />
</form>
</body>
</html>
257 changes: 257 additions & 0 deletions examples/gp-api/google-pay/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
/**
* Config for Google Pay
*/
const config = {
googleMerchant: '12345678901234567890', // The Merchant id Provided by Google, it can be empty in Sandbox
globalPaymentsMerchant: 'gpapiqa1', // The Merchant Id provided by Global Payments
environment: 'TEST',
countryCode: 'GB',
currencyCode: 'GBP',
amount: '10.00',
buttonColor: 'black'
}

/**
* Define the version of the Google Pay API referenced when creating your
* configuration
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|apiVersion in PaymentDataRequest}
*/
const baseRequest = {
apiVersion: 2,
apiVersionMinor: 0
};

/**
* Card networks supported by your site and your gateway
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
* @todo confirm card networks supported by your site and gateway
*/
const allowedCardNetworks = ["AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"];

/**
* Card authentication methods supported by your site and your gateway
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
* @todo confirm your processor supports Android device tokens for your
* supported card networks
*/
const allowedCardAuthMethods = ["PAN_ONLY", "CRYPTOGRAM_3DS"];

/**
* Identify your gateway and your site's gateway merchant identifier
*
* The Google Pay API response will return an encrypted payment method capable
* of being charged by a supported gateway after payer authorization
*
* @todo check with your gateway on the parameters to pass
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#gateway|PaymentMethodTokenizationSpecification}
*/
const tokenizationSpecification = {
type: 'PAYMENT_GATEWAY',
parameters: {
'gateway': 'globalpayments',
'gatewayMerchantId': config.globalPaymentsMerchant
}
};

/**
* Describe your site's support for the CARD payment method and its required
* fields
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
*/
const baseCardPaymentMethod = {
type: 'CARD',
parameters: {
allowedAuthMethods: allowedCardAuthMethods,
allowedCardNetworks: allowedCardNetworks
}
};

/**
* Describe your site's support for the CARD payment method including optional
* fields
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#CardParameters|CardParameters}
*/
const cardPaymentMethod = Object.assign(
{},
baseCardPaymentMethod,
{
tokenizationSpecification: tokenizationSpecification
}
);

/**
* An initialized google.payments.api.PaymentsClient object or null if not yet set
*
* @see {@link getGooglePaymentsClient}
*/
let paymentsClient = null;

/**
* Configure your site's support for payment methods supported by the Google Pay
* API.
*
* Each member of allowedPaymentMethods should contain only the required fields,
* allowing reuse of this base request when determining a viewer's ability
* to pay and later requesting a supported payment method
*
* @returns {object} Google Pay API version, payment methods supported by the site
*/
function getGoogleIsReadyToPayRequest() {
return Object.assign(
{},
baseRequest,
{
allowedPaymentMethods: [baseCardPaymentMethod]
}
);
}

/**
* Configure support for the Google Pay API
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#PaymentDataRequest|PaymentDataRequest}
* @returns {object} PaymentDataRequest fields
*/
function getGooglePaymentDataRequest() {
const paymentDataRequest = Object.assign({}, baseRequest);
paymentDataRequest.allowedPaymentMethods = [cardPaymentMethod];
paymentDataRequest.transactionInfo = getGoogleTransactionInfo();
paymentDataRequest.merchantInfo = {
// @todo a merchant ID is available for a production environment after approval by Google
// See {@link https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist|Integration checklist}
merchantId: config.googleMerchant
};
return paymentDataRequest;
}

/**
* Return an active PaymentsClient or initialize
*
* @see {@link https://developers.google.com/pay/api/web/reference/client#PaymentsClient|PaymentsClient constructor}
* @returns {google.payments.api.PaymentsClient} Google Pay API client
*/
function getGooglePaymentsClient() {
if (paymentsClient === null) {
paymentsClient = new google.payments.api.PaymentsClient({environment: config.environment});
}
return paymentsClient;
}

/**
* Initialize Google PaymentsClient after Google-hosted JavaScript has loaded
*
* Display a Google Pay payment button after confirmation of the viewer's
* ability to pay.
*/
function onGooglePayLoaded() {
if (!deviceSupported()) {
showError();
return false;
}

const paymentsClient = getGooglePaymentsClient();
paymentsClient.isReadyToPay(getGoogleIsReadyToPayRequest())
.then(function(response) {
if (response.result) {
addGooglePayButton();
}
})
.catch(function(err) {
// show error in developer console for debugging
console.error(err);
});
}


/**
* Add a Google Pay purchase button alongside an existing checkout button
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#ButtonOptions|Button options}
* @see {@link https://developers.google.com/pay/api/web/guides/brand-guidelines|Google Pay brand guidelines}
*/
function addGooglePayButton() {
const paymentsClient = getGooglePaymentsClient();
const button = paymentsClient.createButton(
{
buttonColor: config.buttonColor,
onClick: onGooglePaymentButtonClicked
}
);
document.querySelector('#container').appendChild(button);
}

/**
* Provide Google Pay API with a payment amount, currency, and amount status
*
* @see {@link https://developers.google.com/pay/api/web/reference/request-objects#TransactionInfo|TransactionInfo}
* @returns {object} transaction info, suitable for use as transactionInfo property of PaymentDataRequest
*/
function getGoogleTransactionInfo() {
return {
countryCode: config.countryCode,
currencyCode: config.currencyCode,
totalPriceStatus: 'FINAL',
// set to cart total
totalPrice: config.amount
};
}

/**
* Show Google Pay payment sheet when Google Pay payment button is clicked
*/
function onGooglePaymentButtonClicked() {
const paymentDataRequest = getGooglePaymentDataRequest();
paymentDataRequest.transactionInfo = getGoogleTransactionInfo();

const paymentsClient = getGooglePaymentsClient();
paymentsClient.loadPaymentData(paymentDataRequest)
.then(function(paymentData) {
// handle the response
processPayment(paymentData);
})
.catch(function(err) {
// show error in developer console for debugging
console.error(err);
});
}

/**
* Process payment data returned by the Google Pay API
*
* @param {object} paymentData response from Google Pay API after user approves payment
* @see {@link https://developers.google.com/pay/api/web/reference/response-objects#PaymentData|PaymentData object reference}
*/
function processPayment(paymentData) {
/**
* Google sends a JSON with some characters encoded (which should not be).
* Parsing the JSON and then stringifying it again fixes the issue.
*/
var paymentToken = JSON.stringify(JSON.parse(paymentData.paymentMethodData.tokenizationData.token));
setToken(paymentToken);
submitForm();
}

/**
* Set the token received from Google to the form
* @param googleToken
*/
function setToken(googleToken) {
document.querySelector('#googlePayToken').value = googleToken;
}

function submitForm() {
document.querySelector('#form').submit();
}

function showError() {
document.querySelector('.error').classList.remove('hide');
}

function deviceSupported() {
return location.protocol === 'https:';
}
7 changes: 7 additions & 0 deletions examples/gp-api/google-pay/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.error {
color: red;
}

.hide {
display: none;
}
17 changes: 17 additions & 0 deletions examples/gp-ecom/3DS2-Challenge/challengeNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

if ('POST' !== $_SERVER['REQUEST_METHOD']) {
return;
}
if ('application/x-www-form-urlencoded' !== $_SERVER['CONTENT_TYPE']) {
return;
}

if (!isset($_POST['cres'])) {
return;
}

$decodedString = base64_decode($_POST['cres']);
echo "<script>
window.parent.postMessage({ data: " . isset($decodedString) ? htmlspecialchars($decodedString) : "" . "}, window.location.origin);
</script>";
126 changes: 126 additions & 0 deletions examples/gp-ecom/3DS2-Challenge/charge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once ('../../../autoload_standalone.php');

use GlobalPayments\Api\Entities\Enums\AddressType;
use GlobalPayments\Api\Entities\Enums\MethodUrlCompletion;
use GlobalPayments\Api\Entities\Enums\Secure3dVersion;
use GlobalPayments\Api\PaymentMethods\CreditCardData;
use GlobalPayments\Api\Services\Secure3dService;
use GlobalPayments\Api\ServicesContainer;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpEcomConfig;
use GlobalPayments\Api\Entities\Address;
use GlobalPayments\Api\Entities\BrowserData;
use GlobalPayments\Api\Entities\Enums\ColorDepth;
use GlobalPayments\Api\Entities\Enums\ChallengeWindowSize;
use GlobalPayments\Api\Entities\Enums\AuthenticationSource;
use GlobalPayments\Api\Utils\CountryUtils;

// configure client & request settings
$config = new GpEcomConfig();
$config->merchantId = 'myMerchantId';
$config->accountId = 'ecom3ds';
$config->sharedSecret = 'secret';
$config->methodNotificationUrl = 'https://www.example.com/methodNotificationUrl';
$config->challengeNotificationUrl = $_SERVER['HTTP_ORIGIN'] . '/examples/3DS2-Challenge/challengeNotification.php';
$config->secure3dVersion = Secure3dVersion::TWO;
$config->merchantContactUrl = 'https://www.example.com';

ServicesContainer::configureService($config);

$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

// add cardholder data
$card = new CreditCardData();
$card->number = $_POST['cardNumber'];
$card->cvn = $_POST['cardCvv'];
$expDate = explode('/',$_POST['cardExpiration']);
$card->expYear = $expDate[1];
$card->expMonth = $expDate[0];
$card->cardHolderName = 'Me me';

if (!isset($_POST['ThreeDSData'])) {
// Add the customer's billing address
$shippingAddress = new Address();
$shippingAddress->streetAddress1 = $_POST['address1'];
$shippingAddress->streetAddress2 = $_POST['address2'];
$shippingAddress->city = $_POST['city'];
$shippingAddress->postalCode = $_POST['zip'];
$shippingAddress->state = $_POST['state'];
$shippingAddress->countryCode = CountryUtils::getNumericCodeByCountry($_POST['country']);

// Add captured browser data from the client-side and server-side
$browserData = new BrowserData();
$browserData->acceptHeader = "text/html,application/xhtml+xml,application/xml;q=9,image/webp,img/apng,*/*;q=0.8";
$browserData->colorDepth = ColorDepth::TWENTY_FOUR_BITS;
$browserData->ipAddress = "123.123.123.123";
$browserData->javaEnabled = true;
$browserData->javaScriptEnabled = true;
$browserData->language = "en";
$browserData->screenHeight = 1080;
$browserData->screenWidth = 1920;
$browserData->challengWindowSize = ChallengeWindowSize::WINDOWED_600X400;
$browserData->timeZone = "0";
$browserData->userAgent = $_SERVER['HTTP_USER_AGENT'];
try {
$secureEcom = Secure3dService::checkEnrollment($card)
->execute('default', Secure3dVersion::TWO);

if ($secureEcom->enrolled === true) {
$secureEcom = Secure3dService::initiateAuthentication($card, $secureEcom)
->withAmount(10)
->withCurrency('USD')
->withAuthenticationSource(AuthenticationSource::BROWSER)
->withMethodUrlCompletion(MethodUrlCompletion::NO)
->withOrderCreateDate(date('Y-m-d H:i:s'))
->withAddress($shippingAddress, AddressType::SHIPPING)
->withAddress($shippingAddress, AddressType::BILLING)
->withBrowserData($browserData)
->execute();
if ($secureEcom->status == "CHALLENGE_REQUIRED")
{
echo json_encode($secureEcom);
} else {
echo json_encode(['error' => 'true', 'status' => $secureEcom->status, 'message' => 'No challenge required']);
}

} else {
echo json_encode(['error' => 'true', 'enrolled' => $secureEcom->enrolled, 'message' => 'Card not enrolled']);
}
} catch (Exception $e) {
echo json_encode(['error' => 'true', 'message' => $e->getMessage()]);
}
} else {
try {
$convertedObject = $_POST['ThreeDSData']['data'];

$serverTransID = $convertedObject['threeDSServerTransID'];
$acsTransID = $convertedObject['acsTransID'];
$messageType = $convertedObject['messageType'];
$messageVersion = $convertedObject['messageVersion'];
$transStatus = $convertedObject['transStatus'];
if ($transStatus == 'Y') {
$secureEcom = Secure3dService::getAuthenticationData()
->withServerTransactionId($serverTransID)
->execute();
// depending on the ECI value proceed to authorization
if (in_array($secureEcom->eci, ["05", "06", "01", "02"])) {
$card->threeDSecure = $secureEcom;
$response = $card->charge(10)
->withCurrency('USD')
->withAllowDuplicates(true)
->execute();
echo json_encode($response);
} else {
echo 'Secure ecom status: ' . $secureEcom->status;
}
}

} catch (Exception $exce) {
echo 'Fail:' . $exce->getMessage();
// TODO: Add your exception handling here
}
}
135 changes: 135 additions & 0 deletions examples/gp-ecom/3DS2-Challenge/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Global Payments 3DS2 GP-ECOM with challenge window Examples</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"/>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="main.js"></script>
</head>
<body>
<h2>Credit Card Form</h2>
<div class="row">
<div class="col-sm-7">
<form id="form" action="charge.php" method="POST">
<div class="form-group row">
<label for="address1" class="col-sm-2 control-label">Address1</label>
<div class="col-sm-10">
<input type="text" name="address1" id="address1" value="Apartment 852"/>
</div>
</div>
<div class="form-group row">
<label for="address2" class="col-sm-2 control-label">Address2</label>
<div class="col-sm-10">
<input type="text" name="address2" id="address2" value="Complex 741"/>
</div>
</div>
<div class="form-group row">
<label for="city" class="col-sm-2 control-label">City</label>
<div class="col-sm-10">
<input type="text" name="city" id="city" value="Chicago" />
</div>
</div>
<div class="form-group row">
<label for="state" class="col-sm-2 control-label">State</label>
<div class="col-sm-10">
<select name="state" id="state">
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<option value="CA">California</option>
<option value="CO">Colorado</option>
<option value="CT">Connecticut</option>
<option value="DE">Delaware</option>
<option value="DC">District Of Columbia</option>
<option value="FL">Florida</option>
<option value="GA">Georgia</option>
<option value="HI">Hawaii</option>
<option value="ID">Idaho</option>
<option value="IL" selected>Illinois</option>
<option value="IN">Indiana</option>
<option value="IA">Iowa</option>
<option value="KS">Kansas</option>
<option value="KY">Kentucky</option>
<option value="LA">Louisiana</option>
<option value="ME">Maine</option>
<option value="MD">Maryland</option>
<option value="MA">Massachusetts</option>
<option value="MI">Michigan</option>
<option value="MN">Minnesota</option>
<option value="MS">Mississippi</option>
<option value="MO">Missouri</option>
<option value="MT">Montana</option>
<option value="NE">Nebraska</option>
<option value="NV">Nevada</option>
<option value="NH">New Hampshire</option>
<option value="NJ">New Jersey</option>
<option value="NM">New Mexico</option>
<option value="NY">New York</option>
<option value="NC">North Carolina</option>
<option value="ND">North Dakota</option>
<option value="OH">Ohio</option>
<option value="OK">Oklahoma</option>
<option value="OR">Oregon</option>
<option value="PA">Pennsylvania</option>
<option value="RI">Rhode Island</option>
<option value="SC">South Carolina</option>
<option value="SD">South Dakota</option>
<option value="TN">Tennessee</option>
<option value="TX">Texas</option>
<option value="UT">Utah</option>
<option value="VT">Vermont</option>
<option value="VA">Virginia</option>
<option value="WA">Washington</option>
<option value="WV">West Virginia</option>
<option value="WI">Wisconsin</option>
<option value="WY">Wyoming</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="zip" class="col-sm-2 control-label">Zip</label>
<div class="col-sm-10">
<input type="text" name="zip" id="zip" value="50001"/>
</div>
</div>
<div class="form-group row">
<label for="country" class="col-sm-2 control-label">Country</label>
<div class="col-sm-10">
<select name="country" id="country">
<option value="US">United States of America</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="cardNumber" class="col-sm-2 control-label">Card Number</label>
<div class="col-sm-10">
<input type="text" name="cardNumber" id="cardNumber" value="4012001038488884"/>
</div>
</div>
<div class="form-group row">
<label for="cardCvv" class="col-sm-2 control-label">Card Cvv</label>
<div class="col-sm-10">
<input type="text" name="cardCvv" id="cardCvv" value="123" />
</div>
</div>
<div class="form-group row">
<label for="cardExpiration" class="col-sm-2 control-label">Card Expiration</label>
<div class="col-sm-10">
<input type="text" name="cardExpiration" id="cardExpiration" value="12/26" />
</div>
</div>
<div class="form-group row">
<div class="col-sm-5" align="center">
<button type="submit" class="btn btn-success">Pay</button>
</div>
</div>
</form>
</div>
<div class="col-sm-5">
<iframe id="challenge" name="challenge" width="500" height="500" style="border: none"></iframe>
</div>
</div>
</body>
</html>
68 changes: 68 additions & 0 deletions examples/gp-ecom/3DS2-Challenge/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
$(document).ready(function () {
$("form").submit(function (event) {
var formData = {
cardCvv: $("#cardCvv").val(),
cardExpiration: $("#cardExpiration").val(),
cardNumber: $("#cardNumber").val(),
address1: $("#address1").val(),
address2: $("#address2").val(),
city: $("#city").val(),
zip: $("#zip").val(),
state: $("#state").val(),
country: $("#country").val()
};

$.ajax({
type: "POST",
url: "charge.php",
data: formData,
dataType: "json",
encode: true,
}).done(function (data) {
if (data['error'] == "true") {
$("#challenge").contents().find('body').html(data['message']);
return;
}

let form = document.createElement("form");
form.setAttribute("method", "POST");
form.setAttribute("action", data.issuerAcsUrl);
form.setAttribute("target", "challenge");

let creqObj = document.createElement("input");
creqObj.setAttribute("type", "hidden");
creqObj.setAttribute("name", "creq");
creqObj.setAttribute("value", data.payerAuthenticationRequest);

form.appendChild(creqObj);
$("#challenge").append(form);
form.submit();
});

event.preventDefault();
});
window.addEventListener('message', function (e) {
// Get the sent data
const data = e.data;
let formData = {
cardCvv: $("#cardCvv").val(),
cardExpiration: $("#cardExpiration").val(),
cardNumber: $("#cardNumber").val(),
ThreeDSData: e.data
};
$("#challenge").css("visibility","hidden");
$.ajax({
type: "POST",
url: "charge.php",
data: formData,
dataType: "json",
encode: true,
}).done(function (data) {
if (data.responseCode == "00") {
document.write('Success! Transaction Id: ' + data.transactionReference.transactionId)
} else {
document.write('Fail!');
}
})
})
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once('../../../../../autoload_standalone.php');

use GlobalPayments\Api\Entities\Enums\Secure3dVersion;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpEcomConfig;
use GlobalPayments\Api\ServicesContainer;
use GlobalPayments\Api\PaymentMethods\CreditCardData;
use GlobalPayments\Api\Services\Secure3dService;

$config = new GpEcomConfig();
$config->merchantId = 'myMerchantId';
$config->accountId = 'ecom3ds';
$config->sharedSecret = 'secret';
$config->methodNotificationUrl = 'http://gp-sdk.localhost.com:8080/examples/3DS2-Challenge/methodNotificationUrl.php';
$config->challengeNotificationUrl = 'http://gp-sdk.localhost.com:8080/examples/3DS2-Challenge/challengeNotification.php';
$config->secure3dVersion = Secure3dVersion::ANY;
$config->merchantContactUrl = 'https://www.example.com';
ServicesContainer::configureService($config);

$requestData = json_decode(file_get_contents('php://input'));

$cardData = $requestData->card;
$card = new CreditCardData();
$card->number = $cardData->number;
$card->cvn = $cardData->securityCode;
$expDate = explode('/', $cardData->cardExpiration);
$card->expYear = $expDate[1];
$card->expMonth = $expDate[0];
$card->cardHolderName = $cardData->cardHolderName;
$config = ServicesContainer::instance()->getClient('default');

try {
$threeDSecureData = Secure3dService::checkEnrollment($card)
->execute('default', Secure3dVersion::TWO);

$response['enrolled'] = $threeDSecureData->enrolled;
$response['version'] = $threeDSecureData->getVersion();
$response['status'] = $threeDSecureData->status;
$response['serverTransactionId'] = $threeDSecureData->serverTransactionId;

if ($threeDSecureData->enrolled !== true) {
return $response;
}

$response['methodUrl'] = $threeDSecureData->issuerAcsUrl;
$response['methodData'] = $threeDSecureData->payerAuthenticationRequest;
} catch (\Exception $e) {
$response = [
'error' => true,
'message' => $e->getMessage(),
'enrolled' => 'NO_RESPONSE',
];
}
echo json_encode($response);
//print_r($response);
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?php
echo '*******************';
54 changes: 54 additions & 0 deletions examples/gp-ecom/3DS2-Challenge/with-GP-js-library/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
echo '<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Global Payments 3DS2 with challenge window Examples</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"/>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="https://unpkg.com/globalpayments-3ds@1.8.5/dist/globalpayments-3ds.js"></script>
<script src="main.js"></script>
</head>
<body>
<h2>Credit Card Form</h2>
<div class="row">
<div class="col-sm-5">r
<form id="form" action="charge.php" method="POST">
<div class="form-group row">
<label for="card-number" class="col-sm-2 control-label">Card Number</label>
<div class="col-sm-10">
<input type="text" name="card-number" id="card-number" value="4012001038488884"/>
</div>
</div>
<div class="form-group row">
<label for="securityCode" class="col-sm-2 control-label">Card Cvv</label>
<div class="col-sm-10">
<input type="text" name="securityCode" id="securityCode" value="123" />
</div>
</div>
<div class="form-group row">
<label for="cardExpiration" class="col-sm-2 control-label">Card Expiration</label>
<div class="col-sm-10">
<input type="text" name="cardExpiration" id="cardExpiration" value="12/26" />
</div>
</div>
<div class="form-group row">
<label for="cardHolderName" class="col-sm-2 control-label">Cardholder name</label>
<div class="col-sm-10">
<input type="text" name="cardHolderName" id="cardHolderName" value="Jhon Smith" />
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="button" class="btn btn-success" name="startButton" id="startButton">Pay</button>
</div>
</div>
</form>
</div>
<div class="col-sm-5">
<iframe id="challenge" name="challenge" width="500" height="500" style="border: none"></iframe>
</div>
</div>
</body>
</html>';
79 changes: 79 additions & 0 deletions examples/gp-ecom/3DS2-Challenge/with-GP-js-library/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
(function () {
const {
checkVersion,
initiateAuthentication,
} = GlobalPayments.ThreeDSecure;
// assign the button that will trigger authentication
document.addEventListener('DOMContentLoaded', () => {
const checkVersionButton = document.getElementById('startButton');
if (!checkVersionButton) {
return;
}
checkVersionButton.addEventListener('click', async (e) => {
e.preventDefault();
// check if the card is enrolled for 3D Secure 2
try {
versionCheckData = await checkVersion('./ThreeDSecure2/CheckVersion.php', {
card: {
number: document.getElementById('card-number').value,
cardExpiration: document.getElementById('cardExpiration').value,
securityCode: document.getElementById('securityCode').value,
cardHolderName: document.getElementById('cardHolderName').value
},
timeout: 50*1000
});
if (versionCheckData.error) {
// TODO: handle the scenario where the card is not enrolled for 3D Secure 2
return;
}
console.log(versionCheckData.serverTransactionId);
} catch (e) {
console.log(e.reasons);
}

try {
authenticationData = await initiateAuthentication('/ThreeDSecure2/InitiateAuthentication.php', {
serverTransactionId: versionCheckData.serverTransactionId,
methodUrlComplete: true,
card: {
number: document.getElementById('card-number').value,
cardExpiration: document.getElementById('cardExpiration').value,
securityCode: document.getElementById('securityCode').value,
cardHolderName: document.getElementById('cardHolderName').value
},
challengeWindow: {
windowSize: ChallengeWindowSize.FullScreen,
displayMode: 'lightbox',
}
});

if (authenticationData.result == "AUTHORIZATION_SUCCESS") {
}
else if (authenticationData.result == "AUTHORIZATION_FAILURE") {

}
else if (authenticationData.result == "AUTHENTICATION_FAILURE") {

}
else if (authenticationData.challenge.response.data.transStatus == "Y") {
var serverTransactionId = authenticationData.challenge.response.data.threeDSServerTransID;

var form = document.getElementById("myForm");
form.setAttribute("action", "/ThreeDSecure2/Authorization");

var formServerTransId = document.createElement("input");
formServerTransId.setAttribute("type", "hidden");
formServerTransId.setAttribute("name", "serverTransId");
formServerTransId.setAttribute("value", serverTransactionId);
form.appendChild(formServerTransId);
form.submit();
}
else {
return false;
}
} catch (e) {

}
});
});
})()
43 changes: 43 additions & 0 deletions examples/gp-ecom/hpp/example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<fieldset style="width: 30%;">
<legend style="font-style: italic"> Capture Billing and Shipping Information</legend>
<div>
<input type="checkbox" id="capture_address" name="capture_address">
<label for="capture_address">Enable Capture billing and shipping capability</label>
</div>
<div>
<input type="checkbox" id="remove_shipping" name="remove_shipping">
<label for="remove_shipping">Show only the billing address and payment forms.</label>
</div>
<div>
<input type="checkbox" id="not_return_address" name="not_return_address">
<label for="not_return_address">Do not return address information in HPP response</label>
</div>
</fieldset>
<br>
<button id="payButtonId">Click here to pay</button>

<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
<script src="rxp-hpp.js"></script>
<script>
$(document).ready(function() {
$("#payButtonId").click(function() {
const data = {
captureAddress: document.getElementById("capture_address").checked,
notReturnAddress: document.getElementById("not_return_address").checked,
removeShipping: document.getElementById("remove_shipping").checked
};
console.log(data);
$.getJSON("get-json.php", data, function (jsonFromRequestEndpoint) {
console.log(jsonFromRequestEndpoint);
RealexHpp.setHppUrl("https://pay.sandbox.realexpayments.com/pay");
/*
* if running this from localhost, for your response endpoint,
* you will need to expose your local server to the outside world
* you can use something like ngrok for it then access your local host via
* the ngrok link
*/
RealexHpp.lightbox.init("autoload", "response-endpoint.php", jsonFromRequestEndpoint);
});
});
});
</script>
109 changes: 109 additions & 0 deletions examples/gp-ecom/hpp/get-json.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once('../../../autoload_standalone.php');

use GlobalPayments\Api\Entities\Address;
use GlobalPayments\Api\Entities\Enums\AddressType;
use GlobalPayments\Api\Entities\Enums\RemittanceReferenceType;
use GlobalPayments\Api\PaymentMethods\BankPayment;
use GlobalPayments\Api\ServiceConfigs\Gateways\GpEcomConfig;
use GlobalPayments\Api\HostedPaymentConfig;
use GlobalPayments\Api\Entities\HostedPaymentData;
use GlobalPayments\Api\Entities\Enums\HppVersion;
use GlobalPayments\Api\Entities\Exceptions\ApiException;
use GlobalPayments\Api\Services\HostedService;
use GlobalPayments\Api\Entities\Enums\PhoneNumberType;
use GlobalPayments\Api\Entities\Enums\HostedPaymentMethods;
use GlobalPayments\Api\Entities\Enums\AlternativePaymentType;

// configure client, request and HPP settings
$config = new GpEcomConfig();
/* Credentials for OpenBanking HPP*/
//$config->merchantId = "openbankingsandbox";
//$config->accountId = "internet";
//$config->sharedSecret = "sharedsecret";

$config->merchantId = "heartlandgpsandbox";
$config->accountId = "hpp";
$config->sharedSecret = "secret";

$config->serviceUrl = "https://pay.sandbox.realexpayments.com/pay";
$config->enableBankPayment = true;
$config->hostedPaymentConfig = new HostedPaymentConfig();
$config->hostedPaymentConfig->version = HppVersion::VERSION_2;

$service = new HostedService($config);

// Add 3D Secure 2 Mandatory and Recommended Fields
$hostedPaymentData = new HostedPaymentData();
$hostedPaymentData->customerEmail = "james.mason@example.com";
$hostedPaymentData->customerPhoneMobile = "44|07123456789";
$hostedPaymentData->addressesMatch = false;
if (isset($_REQUEST['captureAddress'])) {
$hostedPaymentData->addressCapture = filter_var($_REQUEST['captureAddress'], FILTER_VALIDATE_BOOLEAN);
}
if (isset($_REQUEST['notReturnAddress'])) {
$hostedPaymentData->notReturnAddress = filter_var($_REQUEST['notReturnAddress'], FILTER_VALIDATE_BOOLEAN);
}
if (isset($_REQUEST['removeShipping'])) {
$hostedPaymentData->removeShipping = filter_var($_REQUEST['removeShipping'], FILTER_VALIDATE_BOOLEAN);
}

$hostedPaymentData->customerCountry = 'DE';
$hostedPaymentData->customerFirstName = 'James';
$hostedPaymentData->customerLastName = 'Mason';
$baseUrl = 'https://516b-2a02-2f0e-5e11-1500-3944-7324-2f8a-fbfd.ngrok-free.app';
$hostedPaymentData->transactionStatusUrl = "$baseUrl/examples/gp-ecom/hpp/status-endpoint.php";
$hostedPaymentData->merchantResponseUrl = "$baseUrl/examples/gp-ecom/hpp/response-endpoint.php";
$hostedPaymentData->presetPaymentMethods = [HostedPaymentMethods::CARDS, HostedPaymentMethods::OB, AlternativePaymentType::SOFORTUBERWEISUNG];

$billingAddress = new Address();
$billingAddress->streetAddress1 = "Flat 123";
$billingAddress->streetAddress2 = "House 456";
$billingAddress->streetAddress3 = "Unit 4";
$billingAddress->city = "Halifax";
$billingAddress->postalCode = "W5 9HR";
$billingAddress->country = "826";

$shippingAddress = new Address();
$shippingAddress->streetAddress1 = "Apartment 825";
$shippingAddress->streetAddress2 = "Complex 741";
$shippingAddress->streetAddress3 = "House 963";
$shippingAddress->city = "Chicago";
$shippingAddress->state = "IL";
$shippingAddress->postalCode = "50001";
$shippingAddress->country = "840";

$bankPayment = new BankPayment();
$bankPayment->accountNumber = '12345678';
$bankPayment->sortCode = '406650';
$bankPayment->accountName = 'AccountName';

$hostedPaymentData->bankPayment = $bankPayment;

try {
/* in case you want to test also a verify request you can use the example below
$hppJson = $service->verify()
->withCurrency('EUR')
->withHostedPaymentData($hostedPaymentData)
->withAddress($billingAddress, AddressType::BILLING)
->serialize();
*/
$hppJson = $service->charge(19.99)
->withCurrency("EUR")
->withHostedPaymentData($hostedPaymentData)
->withAddress($billingAddress, AddressType::BILLING)
->withAddress($shippingAddress, AddressType::SHIPPING)
->withPhoneNumber('44', '124 445 556', PhoneNumberType::WORK)
->withPhoneNumber('44', '124 444 333', PhoneNumberType::HOME)
->withRemittanceReference(RemittanceReferenceType::TEXT, 'Nike Bounce Shoes')
->serialize();
//with this, we can pass our json to the client side
echo $hppJson;
} catch (ApiException $e) {
print_r($e);
// TODO: Add your error handling here
}
Loading