From 2705ac7adbc9da006b68e50b34d1fc61659f1984 Mon Sep 17 00:00:00 2001 From: ZerosDev Date: Fri, 3 Mar 2023 08:38:24 +0700 Subject: [PATCH 01/14] add enableDebug() method --- src/Callback.php | 33 +++++++++++++++++++++++++-------- src/Support/Constant.php | 4 ++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/Callback.php b/src/Callback.php index 365a44d..2f6e867 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -5,6 +5,7 @@ use Exception; use UnexpectedValueException; use ZerosDev\TriPay\Exception\SignatureException; +use ZerosDev\TriPay\Support\Constant; class Callback { @@ -29,13 +30,20 @@ class Callback */ protected ?object $parsedJson; + /** + * Enable/disable debug mode + * + * @var boolean + */ + protected bool $debug = false; + /** * Callback instance * * @param Client $client * @param bool $verifyOnLoad */ - public function __construct(Client $client, bool $verifyOnLoad = true) + public function __construct(Client $client) { if (!function_exists('file_get_contents')) { throw new Exception('`file_get_contents` function is disabled on your system. Please contact your hosting provider'); @@ -44,10 +52,12 @@ public function __construct(Client $client, bool $verifyOnLoad = true) $this->client = $client; $this->json = (string) file_get_contents("php://input"); $this->parsedJson = json_decode($this->json); + } - if ($verifyOnLoad) { - $this->validate(); - } + public function enableDebug(): self + { + $this->debug = true; + return $this; } /** @@ -79,19 +89,26 @@ public function incomingSignature(): ?string */ public function validate(): bool { + $localSignature = $this->localSignature(); + $incomingSignature = $this->incomingSignature(); + $validSignature = hash_equals( - $this->localSignature(), - $this->incomingSignature() + $localSignature, + $incomingSignature ); if (!$validSignature) { - throw new SignatureException('Incoming signature does not match local signature'); + $message = 'Incoming signature does not match local signature'; + if ($this->debug) { + $message .= ': local(' . $localSignature . ') vs incoming(' . $incomingSignature . ')'; + } + throw new SignatureException($message); } $validData = !is_null($this->data()); if (!$validData) { - throw new UnexpectedValueException('Callback data is invalid'); + throw new UnexpectedValueException('Callback data is invalid. Invalid or empty JSON'); } return true; diff --git a/src/Support/Constant.php b/src/Support/Constant.php index 7924f5c..ee35c1c 100644 --- a/src/Support/Constant.php +++ b/src/Support/Constant.php @@ -9,4 +9,8 @@ class Constant public const MODE_DEVELOPMENT = 'development'; public const MODE_PRODUCTION = 'production'; + + public const LEVEL_LOW = 0; + public const LEVEL_MEDIUM = 1; + public const LEVEL_HIGH = 2; } From baadc99d3063b7b6de0ee15d68549958df42ccf3 Mon Sep 17 00:00:00 2001 From: ZerosDev Date: Fri, 3 Mar 2023 09:41:28 +0700 Subject: [PATCH 02/14] add example --- examples/callback-handling.php | 39 ++++++++++++++++++++++++++ examples/merchant-fee-calculator.php | 14 +++++++++ examples/merchant-payment-channel.php | 14 +++++++++ examples/merchant-transactions.php | 14 +++++++++ examples/open-payment-create.php | 18 ++++++++++++ examples/open-payment-detail.php | 14 +++++++++ examples/open-payment-transactions.php | 14 +++++++++ examples/payment-instruction.php | 14 +++++++++ examples/transaction-create.php | 32 +++++++++++++++++++++ examples/transaction-detail.php | 14 +++++++++ 10 files changed, 187 insertions(+) create mode 100644 examples/callback-handling.php create mode 100644 examples/merchant-fee-calculator.php create mode 100644 examples/merchant-payment-channel.php create mode 100644 examples/merchant-transactions.php create mode 100644 examples/open-payment-create.php create mode 100644 examples/open-payment-detail.php create mode 100644 examples/open-payment-transactions.php create mode 100644 examples/payment-instruction.php create mode 100644 examples/transaction-create.php create mode 100644 examples/transaction-detail.php diff --git a/examples/callback-handling.php b/examples/callback-handling.php new file mode 100644 index 0000000..4ba751e --- /dev/null +++ b/examples/callback-handling.php @@ -0,0 +1,39 @@ +enableDebug(); + +/** + * Run validation + * It will throws Exception when validation fail + */ +try { + $callback->validate(); +} catch (Exception $e) { + echo $e->getMessage(); + die; +} + +/** + * Get callback data as object + */ +$data = $callback->data(); + +print_r($data); diff --git a/examples/merchant-fee-calculator.php b/examples/merchant-fee-calculator.php new file mode 100644 index 0000000..85b0b49 --- /dev/null +++ b/examples/merchant-fee-calculator.php @@ -0,0 +1,14 @@ +feeCalculator(100000, 'BRIVA'); +echo $result->getBody()->getContents(); diff --git a/examples/merchant-payment-channel.php b/examples/merchant-payment-channel.php new file mode 100644 index 0000000..fececa2 --- /dev/null +++ b/examples/merchant-payment-channel.php @@ -0,0 +1,14 @@ +paymentChannels(); +echo $result->getBody()->getContents(); diff --git a/examples/merchant-transactions.php b/examples/merchant-transactions.php new file mode 100644 index 0000000..7bf633c --- /dev/null +++ b/examples/merchant-transactions.php @@ -0,0 +1,14 @@ +transactions([]); +echo $result->getBody()->getContents(); diff --git a/examples/open-payment-create.php b/examples/open-payment-create.php new file mode 100644 index 0000000..470e62c --- /dev/null +++ b/examples/open-payment-create.php @@ -0,0 +1,18 @@ +create([ + 'method' => 'BSIVAOP', + 'merchant_ref' => 'USER-123', + 'customer_name' => 'Nama Pelanggan', +]); +echo $result->getBody()->getContents(); diff --git a/examples/open-payment-detail.php b/examples/open-payment-detail.php new file mode 100644 index 0000000..2390f94 --- /dev/null +++ b/examples/open-payment-detail.php @@ -0,0 +1,14 @@ +detail('T1234OP234GDGT4'); +echo $result->getBody()->getContents(); diff --git a/examples/open-payment-transactions.php b/examples/open-payment-transactions.php new file mode 100644 index 0000000..0de84f7 --- /dev/null +++ b/examples/open-payment-transactions.php @@ -0,0 +1,14 @@ +transactions('T1234OP234GDGT4'); +echo $result->getBody()->getContents(); diff --git a/examples/payment-instruction.php b/examples/payment-instruction.php new file mode 100644 index 0000000..0ec40f9 --- /dev/null +++ b/examples/payment-instruction.php @@ -0,0 +1,14 @@ +instruction('BRIVA'); +echo $result->getBody()->getContents(); diff --git a/examples/transaction-create.php b/examples/transaction-create.php new file mode 100644 index 0000000..cd1bf4b --- /dev/null +++ b/examples/transaction-create.php @@ -0,0 +1,32 @@ +addOrderItem('Gula', 10000, 1) + ->addOrderItem('Kopi', 5000, 3) + ->addOrderItem('Teh', 3000, 1) + ->addOrderItem('Nasi', 15000, 1) + ->create([ + 'method' => 'BRIVA', + 'merchant_ref' => 'INV123', + 'customer_name' => 'Nama Pelanggan', + 'customer_email' => 'email@konsumen.id', + 'customer_phone' => '081234567890', + 'return_url' => 'https://example.com/return', + 'expired_time' => Helper::makeTimestamp('1 DAY') + ]); +echo $result->getBody()->getContents(); diff --git a/examples/transaction-detail.php b/examples/transaction-detail.php new file mode 100644 index 0000000..3c8533e --- /dev/null +++ b/examples/transaction-detail.php @@ -0,0 +1,14 @@ +detail('T11111111111'); +echo $result->getBody()->getContents(); From f9a5bc3de0a7842840aea0a09b24ac6b23be0b06 Mon Sep 17 00:00:00 2001 From: ZerosDev Date: Fri, 3 Mar 2023 09:43:10 +0700 Subject: [PATCH 03/14] update README.md --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4e95d7f..baf6094 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

## Requirements -- PHP v7.2+ +- PHP v7.2.5+ - PHP JSON Extension - PHP cURL Extension @@ -31,6 +31,7 @@ require 'path/to/your/vendor/autoload.php'; use ZerosDev\TriPay\Client as TriPayClient; use ZerosDev\TriPay\Support\Constant; +use ZerosDev\TriPay\Support\Helper; use ZerosDev\TriPay\Transaction; $merchantCode = 'T12345'; @@ -42,13 +43,21 @@ $guzzleOptions = []; // Your additional Guzzle options (https://docs.guzzlephp.o $client = new TriPayClient($merchantCode, $apiKey, $privateKey, $mode, $guzzleOptions); $transaction = new Transaction($client); +/** + * `amount` will be calculated automatically from order items + * so you don't have to enter it + * In this example, amount will be 40.000 + */ $result = $transaction ->addOrderItem('Gula', 10000, 1) - ->addOrderItem('Kopi', 6000, 1) + ->addOrderItem('Kopi', 6000, 5) ->create([ 'method' => 'BRIVA', + 'merchant_ref' => 'INV123', 'customer_name' => 'Nama Pelanggan', 'customer_email' => 'email@konsumen.id', + 'customer_phone' => '081234567890', + 'expired_time' => Helper::makeTimestamp('6 HOUR'), ]); echo $result->getBody()->getContents(); From 1e54d77524f59b7a574a2902b4068e71156b9728 Mon Sep 17 00:00:00 2001 From: ZerosDev Date: Fri, 3 Mar 2023 09:43:35 +0700 Subject: [PATCH 04/14] upgrade minimum php version to 7.2.5 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 929928c..3e2d260 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Unofficial TriPay.co.id Integration Kit for PHP", "type": "library", "require": { - "php": ">=7.2.0", + "php": ">=7.2.5", "ext-curl": "*", "ext-json": "*", "guzzlehttp/guzzle": "^6.5|^7.0" From 09d0a36b7ceee96abec5f460093fa5614878dcc0 Mon Sep 17 00:00:00 2001 From: ZerosDev Date: Fri, 3 Mar 2023 09:44:05 +0700 Subject: [PATCH 05/14] add comment to enableDebug() --- src/Callback.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Callback.php b/src/Callback.php index 2f6e867..8411e4b 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -54,6 +54,15 @@ public function __construct(Client $client) $this->parsedJson = json_decode($this->json); } + /** + * Enable debugging + * + * !! WARNING !! + * Only enable it while debugging. + * Leaving it enabled can lead to security vulnerabilities + * + * @return self + */ public function enableDebug(): self { $this->debug = true; From f92f0224ecd764f148ea421334f5c4437853328c Mon Sep 17 00:00:00 2001 From: ZerosDev Date: Fri, 3 Mar 2023 09:44:34 +0700 Subject: [PATCH 06/14] add makeTimestamp() --- src/Support/Helper.php | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/Support/Helper.php b/src/Support/Helper.php index b96214c..d6d28e9 100644 --- a/src/Support/Helper.php +++ b/src/Support/Helper.php @@ -70,4 +70,55 @@ public static function checkRequiredPayloads(array $requireds, array $payloads): } } } + + /** + * Make unix timestamp + * Supported unit: SECOND, MINUTE, HOUR, DAY + * i.e: "1 DAY", "13 HOUR", etc + * + * @param string $value + * @return integer + */ + public static function makeTimestamp(string $value): int + { + if (!preg_match('/^[0-9]+[\s][A-Z]+$/is', $value)) { + throw new InvalidArgumentException("Value must be in '[value] [unit]' format: i.e: 1 DAY"); + } + + [$value, $unit] = explode(' ', $value); + + $value = (int) $value; + + if ($value === 0) { + throw new InvalidArgumentException('Value must be greater than 0'); + } + + $unit = strtoupper($unit); + + $supportedUnits = ['SECOND', 'MINUTE', 'HOUR', 'DAY']; + + if (!in_array($unit, $supportedUnits)) { + throw new InvalidArgumentException('Unexpected unit. Supported: ' . implode(', ', $supportedUnits)); + } + + switch ($unit) { + case 'SECOND': + $timestamp = $value; + break; + + case 'MINUTE': + $timestamp = $value * 60; + break; + + case 'HOUR': + $timestamp = $value * 60 * 60; + break; + + case 'DAY': + $timestamp = $value * 24 * 60 * 60; + break; + } + + return (int) (time() + $timestamp); + } } From 2e0aa679bff23f3f792ec8cf65b2794c168c4506 Mon Sep 17 00:00:00 2001 From: Zeros Developer <33526722+zerosdev@users.noreply.github.com> Date: Fri, 3 Mar 2023 09:50:53 +0700 Subject: [PATCH 07/14] Update callback-handling.php --- examples/callback-handling.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/callback-handling.php b/examples/callback-handling.php index 4ba751e..8d63938 100644 --- a/examples/callback-handling.php +++ b/examples/callback-handling.php @@ -16,7 +16,7 @@ * * !! WARNING !! * Only enable it while debugging. - * Leaving it enabled can lead to security compromise + * Leaving it enabled can lead to security issue */ $callback->enableDebug(); From b36d2a7c2e20ee9311450a6f1206ae036c33ec75 Mon Sep 17 00:00:00 2001 From: Zeros Developer <33526722+zerosdev@users.noreply.github.com> Date: Mon, 6 Mar 2023 10:28:25 +0700 Subject: [PATCH 08/14] Fix return type incomingSignature() only return string --- src/Callback.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Callback.php b/src/Callback.php index 8411e4b..93c5400 100644 --- a/src/Callback.php +++ b/src/Callback.php @@ -82,9 +82,9 @@ public function localSignature(): string /** * Get incoming signature * - * @return string|null + * @return string */ - public function incomingSignature(): ?string + public function incomingSignature(): string { return (string) (isset($_SERVER['HTTP_X_CALLBACK_SIGNATURE']) ? $_SERVER['HTTP_X_CALLBACK_SIGNATURE'] : ""); } From 5ce068c49e740bb304aad3044877acf76c4795dc Mon Sep 17 00:00:00 2001 From: ZerosDev Date: Mon, 6 Mar 2023 10:41:54 +0700 Subject: [PATCH 09/14] Add comment, add type hint, make optional in post() --- src/Client.php | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Client.php b/src/Client.php index 45e08f7..1b82703 100644 --- a/src/Client.php +++ b/src/Client.php @@ -165,19 +165,40 @@ public function __construct(...$args) $this->client = $this->createHttpClient($options); } + /** + * Create HTTP client + * + * @param array $options + * @return HttpClient + */ private function createHttpClient(array $options): HttpClient { return new HttpClient($options); } - public function get($endpoint, array $headers = []): Response + /** + * Performe GET request + * + * @param string $endpoint + * @param array $headers + * @return Response + */ + public function get(string $endpoint, array $headers = []): Response { return $this->client->get($endpoint, [ 'headers' => $headers, ]); } - public function post($endpoint, array $payloads, array $headers = []): Response + /** + * Performe POST request + * + * @param string $endpoint + * @param array $payloads + * @param array $headers + * @return Response + */ + public function post(string $endpoint, array $payloads = [], array $headers = []): Response { return $this->client->post($endpoint, [ 'json' => $payloads, @@ -185,6 +206,11 @@ public function post($endpoint, array $payloads, array $headers = []): Response ]); } + /** + * Get debug data + * + * @return object + */ public function debugs(): object { return (object) $this->debugs; From a2b53956508058ff490dce74f74ade1bc0950515 Mon Sep 17 00:00:00 2001 From: Zeros Developer <33526722+zerosdev@users.noreply.github.com> Date: Sat, 25 Mar 2023 13:30:52 +0700 Subject: [PATCH 10/14] Remove unused code, fix unsupported time unit Remove unused code, fix unsupported time unit exception --- src/Support/Helper.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Support/Helper.php b/src/Support/Helper.php index d6d28e9..a0aed69 100644 --- a/src/Support/Helper.php +++ b/src/Support/Helper.php @@ -19,8 +19,7 @@ public static function makeSignature(Client $client, array $payloads): string { $merchantRef = isset($payloads['merchant_ref']) ? $payloads['merchant_ref'] : null; $amount = self::formatAmount($payloads['amount']); - - $payloads['amount'] = self::formatAmount($payloads['amount']); + return hash_hmac('sha256', $client->merchantCode . $merchantRef . $amount, $client->privateKey); } @@ -73,7 +72,7 @@ public static function checkRequiredPayloads(array $requireds, array $payloads): /** * Make unix timestamp - * Supported unit: SECOND, MINUTE, HOUR, DAY + * Supported time unit: SECOND, MINUTE, HOUR, DAY * i.e: "1 DAY", "13 HOUR", etc * * @param string $value @@ -98,7 +97,7 @@ public static function makeTimestamp(string $value): int $supportedUnits = ['SECOND', 'MINUTE', 'HOUR', 'DAY']; if (!in_array($unit, $supportedUnits)) { - throw new InvalidArgumentException('Unexpected unit. Supported: ' . implode(', ', $supportedUnits)); + throw new InvalidArgumentException('Unsupported time unit. Supported: ' . implode(', ', $supportedUnits)); } switch ($unit) { From 4c47d6dad773a202935dc5a4ecff1f7c852dc594 Mon Sep 17 00:00:00 2001 From: Zeros Developer <33526722+zerosdev@users.noreply.github.com> Date: Sat, 25 Mar 2023 13:38:40 +0700 Subject: [PATCH 11/14] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index baf6094..3e54be8 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ $result = $transaction 'customer_name' => 'Nama Pelanggan', 'customer_email' => 'email@konsumen.id', 'customer_phone' => '081234567890', - 'expired_time' => Helper::makeTimestamp('6 HOUR'), + 'expired_time' => Helper::makeTimestamp('6 HOUR'), // see Supported Time Units ]); echo $result->getBody()->getContents(); @@ -70,3 +70,10 @@ echo json_encode($debugs, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); ``` Please check the `/examples` for the other examples + +## Supported Time Units +> :exclamation: All time units are in a singular noun +- SECOND +- MINUTE +- HOUR +- DAY From 3107cfa9456ef20eef7c4c53f0939172ce627b5e Mon Sep 17 00:00:00 2001 From: AzniDev Date: Mon, 11 Nov 2024 17:27:02 +0700 Subject: [PATCH 12/14] fix development mode --- composer.json | 4 ++-- src/Client.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 3e2d260..fcbd491 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "zerosdev/tripay-sdk-php", + "name": "aznidev/tripay-sdk-php", "description": "Unofficial TriPay.co.id Integration Kit for PHP", "type": "library", "require": { @@ -21,4 +21,4 @@ "ZerosDev\\TriPay\\": "src/" } } -} +} \ No newline at end of file diff --git a/src/Client.php b/src/Client.php index 1b82703..93d419e 100644 --- a/src/Client.php +++ b/src/Client.php @@ -120,8 +120,8 @@ public function __construct(...$args) $this->merchantCode = (string) is_array($args[0]) ? $args[0]['merchant_code'] : $args[0]; $this->apiKey = (string) is_array($args[0]) ? $args[0]['api_key'] : $args[1]; - $this->privateKey = (string) is_array($args[0]) ? $args[0]['private_key'] : $args[1]; - $this->mode = (string) is_array($args[0]) ? $args[0]['mode'] : $args[2]; + $this->privateKey = (string) is_array($args[0]) ? $args[0]['private_key'] : $args[2]; + $this->mode = (string) is_array($args[0]) ? $args[0]['mode'] : $args[3]; $baseUri = ($this->mode == Constant::MODE_DEVELOPMENT) ? Constant::URL_DEVELOPMENT From 96898b3e7281c98e6328d9befe0e22ae97583388 Mon Sep 17 00:00:00 2001 From: Rony Wisnu Wardana <33526722+zerosdev@users.noreply.github.com> Date: Thu, 3 Apr 2025 21:00:38 +0700 Subject: [PATCH 13/14] Update user agent --- src/Client.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.php b/src/Client.php index 1b82703..7808d92 100644 --- a/src/Client.php +++ b/src/Client.php @@ -150,7 +150,7 @@ public function __construct(...$args) }, 'headers' => [ 'Authorization' => 'Bearer ' . $this->apiKey, - 'User-Agent' => 'zerosdev/tripay-sdk-php', + 'User-Agent' => 'github:zerosdev/tripay-sdk-php', ] ]; From 4322cf0eb4d26fd698b2528552094ea61ddd07f8 Mon Sep 17 00:00:00 2001 From: Rony Wisnu Wardana <33526722+zerosdev@users.noreply.github.com> Date: Thu, 3 Apr 2025 21:08:02 +0700 Subject: [PATCH 14/14] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index fcbd491..3e2d260 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "aznidev/tripay-sdk-php", + "name": "zerosdev/tripay-sdk-php", "description": "Unofficial TriPay.co.id Integration Kit for PHP", "type": "library", "require": { @@ -21,4 +21,4 @@ "ZerosDev\\TriPay\\": "src/" } } -} \ No newline at end of file +}