Add remaining project files (exclude ignored folders)
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
use Exception;
|
||||
/**
|
||||
* Send request to Midtrans API
|
||||
* Better don't use this class directly, please use CoreApi, Snap, and Transaction instead
|
||||
*/
|
||||
|
||||
class ApiRequestor
|
||||
{
|
||||
|
||||
/**
|
||||
* Send GET request
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $server_key
|
||||
* @param mixed[] $data_hash
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function get($url, $server_key, $data_hash)
|
||||
{
|
||||
return self::remoteCall($url, $server_key, $data_hash, 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send POST request
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $server_key
|
||||
* @param mixed[] $data_hash
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function post($url, $server_key, $data_hash)
|
||||
{
|
||||
return self::remoteCall($url, $server_key, $data_hash, 'POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send PATCH request
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $server_key
|
||||
* @param mixed[] $data_hash
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function patch($url, $server_key, $data_hash)
|
||||
{
|
||||
return self::remoteCall($url, $server_key, $data_hash, 'PATCH');
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually send request to API server
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $server_key
|
||||
* @param mixed[] $data_hash
|
||||
* @param bool $post
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function remoteCall($url, $server_key, $data_hash, $method)
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
if (!$server_key) {
|
||||
throw new Exception(
|
||||
'The ServerKey/ClientKey is null, You need to set the server-key from Config. Please double-check Config and ServerKey key. ' .
|
||||
'You can check from the Midtrans Dashboard. ' .
|
||||
'See https://docs.midtrans.com/en/midtrans-account/overview?id=retrieving-api-access-keys ' .
|
||||
'for the details or contact support at support@midtrans.com if you have any questions.'
|
||||
);
|
||||
} else {
|
||||
if ($server_key == "") {
|
||||
throw new Exception(
|
||||
'The ServerKey/ClientKey is invalid, as it is an empty string. Please double-check your ServerKey key. ' .
|
||||
'You can check from the Midtrans Dashboard. ' .
|
||||
'See https://docs.midtrans.com/en/midtrans-account/overview?id=retrieving-api-access-keys ' .
|
||||
'for the details or contact support at support@midtrans.com if you have any questions.'
|
||||
);
|
||||
} elseif (preg_match('/\s/',$server_key)) {
|
||||
throw new Exception(
|
||||
'The ServerKey/ClientKey is contains white-space. Please double-check your API key. Please double-check your ServerKey key. ' .
|
||||
'You can check from the Midtrans Dashboard. ' .
|
||||
'See https://docs.midtrans.com/en/midtrans-account/overview?id=retrieving-api-access-keys ' .
|
||||
'for the details or contact support at support@midtrans.com if you have any questions.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$curl_options = array(
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'User-Agent: midtrans-php-v2.5.2',
|
||||
'Authorization: Basic ' . base64_encode($server_key . ':')
|
||||
),
|
||||
CURLOPT_RETURNTRANSFER => 1
|
||||
);
|
||||
|
||||
// Set append notification to header
|
||||
if (Config::$appendNotifUrl) Config::$curlOptions[CURLOPT_HTTPHEADER][] = 'X-Append-Notification: ' . Config::$appendNotifUrl;
|
||||
// Set override notification to header
|
||||
if (Config::$overrideNotifUrl) Config::$curlOptions[CURLOPT_HTTPHEADER][] = 'X-Override-Notification: ' . Config::$overrideNotifUrl;
|
||||
// Set payment idempotency-key to header
|
||||
if (Config::$paymentIdempotencyKey) Config::$curlOptions[CURLOPT_HTTPHEADER][] = 'Idempotency-Key: ' . Config::$paymentIdempotencyKey;
|
||||
|
||||
// merging with Config::$curlOptions
|
||||
if (count(Config::$curlOptions)) {
|
||||
// We need to combine headers manually, because it's array and it will no be merged
|
||||
if (Config::$curlOptions[CURLOPT_HTTPHEADER]) {
|
||||
$mergedHeaders = array_merge($curl_options[CURLOPT_HTTPHEADER], Config::$curlOptions[CURLOPT_HTTPHEADER]);
|
||||
$headerOptions = array(CURLOPT_HTTPHEADER => $mergedHeaders);
|
||||
} else {
|
||||
$mergedHeaders = array();
|
||||
$headerOptions = array(CURLOPT_HTTPHEADER => $mergedHeaders);
|
||||
}
|
||||
|
||||
$curl_options = array_replace_recursive($curl_options, Config::$curlOptions, $headerOptions);
|
||||
}
|
||||
|
||||
if ($method != 'GET') {
|
||||
|
||||
if ($data_hash) {
|
||||
$body = json_encode($data_hash);
|
||||
$curl_options[CURLOPT_POSTFIELDS] = $body;
|
||||
} else {
|
||||
$curl_options[CURLOPT_POSTFIELDS] = '';
|
||||
}
|
||||
|
||||
if ($method == 'POST') {
|
||||
$curl_options[CURLOPT_POST] = 1;
|
||||
} elseif ($method == 'PATCH') {
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
|
||||
}
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, $curl_options);
|
||||
|
||||
// For testing purpose
|
||||
if (class_exists('\Midtrans\MT_Tests') && MT_Tests::$stubHttp) {
|
||||
$result = self::processStubed($curl_options, $url, $server_key, $data_hash, $method);
|
||||
} else {
|
||||
$result = curl_exec($ch);
|
||||
// curl_close($ch);
|
||||
}
|
||||
|
||||
|
||||
if ($result === false) {
|
||||
throw new Exception('CURL Error: ' . curl_error($ch), curl_errno($ch));
|
||||
} else {
|
||||
try {
|
||||
$result_array = json_decode($result);
|
||||
} catch (Exception $e) {
|
||||
throw new Exception("API Request Error unable to json_decode API response: ".$result . ' | Request url: '.$url);
|
||||
}
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
if (isset($result_array->status_code) && $result_array->status_code >= 401 && $result_array->status_code != 407) {
|
||||
throw new Exception('Midtrans API is returning API error. HTTP status code: ' . $result_array->status_code . ' API response: ' . $result, $result_array->status_code);
|
||||
} elseif ($httpCode >= 400) {
|
||||
throw new Exception('Midtrans API is returning API error. HTTP status code: ' . $httpCode . ' API response: ' . $result, $httpCode);
|
||||
} else {
|
||||
return $result_array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function processStubed($curl, $url, $server_key, $data_hash, $method)
|
||||
{
|
||||
MT_Tests::$lastHttpRequest = array(
|
||||
"url" => $url,
|
||||
"server_key" => $server_key,
|
||||
"data_hash" => $data_hash,
|
||||
$method => $method,
|
||||
"curl" => $curl
|
||||
);
|
||||
|
||||
return MT_Tests::$stubHttpResponse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
/**
|
||||
* Midtrans Configuration
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
|
||||
/**
|
||||
* Your merchant's server key
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $serverKey;
|
||||
/**
|
||||
* Your merchant's client key
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $clientKey;
|
||||
/**
|
||||
* True for production
|
||||
* false for sandbox mode
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $isProduction = false;
|
||||
/**
|
||||
* Set it true to enable 3D Secure by default
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $is3ds = false;
|
||||
/**
|
||||
* Set Append URL notification
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $appendNotifUrl;
|
||||
/**
|
||||
* Set Override URL notification
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $overrideNotifUrl;
|
||||
/**
|
||||
* Set Payment IdempotencyKey
|
||||
* for details (http://api-docs.midtrans.com/#idempotent-requests)
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $paymentIdempotencyKey;
|
||||
/**
|
||||
* Enable request params sanitizer (validate and modify charge request params).
|
||||
* See Midtrans_Sanitizer for more details
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $isSanitized = false;
|
||||
/**
|
||||
* Default options for every request
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
public static $curlOptions = array();
|
||||
|
||||
const SANDBOX_BASE_URL = 'https://api.sandbox.midtrans.com';
|
||||
const PRODUCTION_BASE_URL = 'https://api.midtrans.com';
|
||||
const SNAP_SANDBOX_BASE_URL = 'https://app.sandbox.midtrans.com/snap/v1';
|
||||
const SNAP_PRODUCTION_BASE_URL = 'https://app.midtrans.com/snap/v1';
|
||||
|
||||
/**
|
||||
* Get baseUrl
|
||||
*
|
||||
* @return string Midtrans API URL, depends on $isProduction
|
||||
*/
|
||||
public static function getBaseUrl()
|
||||
{
|
||||
return Config::$isProduction ?
|
||||
Config::PRODUCTION_BASE_URL : Config::SANDBOX_BASE_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get snapBaseUrl
|
||||
*
|
||||
* @return string Snap API URL, depends on $isProduction
|
||||
*/
|
||||
public static function getSnapBaseUrl()
|
||||
{
|
||||
return Config::$isProduction ?
|
||||
Config::SNAP_PRODUCTION_BASE_URL : Config::SNAP_SANDBOX_BASE_URL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Provide charge and capture functions for Core API
|
||||
*/
|
||||
class CoreApi
|
||||
{
|
||||
/**
|
||||
* Create transaction.
|
||||
*
|
||||
* @param mixed[] $params Transaction options
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function charge($params)
|
||||
{
|
||||
$payloads = array(
|
||||
'payment_type' => 'credit_card'
|
||||
);
|
||||
|
||||
if (isset($params['item_details'])) {
|
||||
$gross_amount = 0;
|
||||
foreach ($params['item_details'] as $item) {
|
||||
$gross_amount += $item['quantity'] * $item['price'];
|
||||
}
|
||||
$payloads['transaction_details']['gross_amount'] = $gross_amount;
|
||||
}
|
||||
|
||||
$payloads = array_replace_recursive($payloads, $params);
|
||||
|
||||
if (Config::$isSanitized) {
|
||||
Sanitizer::jsonRequest($payloads);
|
||||
}
|
||||
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/charge',
|
||||
Config::$serverKey,
|
||||
$payloads
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture pre-authorized transaction
|
||||
*
|
||||
* @param string $param Order ID or transaction ID, that you want to capture
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function capture($param)
|
||||
{
|
||||
$payloads = array(
|
||||
'transaction_id' => $param,
|
||||
);
|
||||
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/capture',
|
||||
Config::$serverKey,
|
||||
$payloads
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do `/v2/card/register` API request to Core API
|
||||
*
|
||||
* @param $cardNumber
|
||||
* @param $expMoth
|
||||
* @param $expYear
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function cardRegister($cardNumber, $expMoth, $expYear)
|
||||
{
|
||||
$path = "/card/register?card_number=" . $cardNumber
|
||||
. "&card_exp_month=" . $expMoth
|
||||
. "&card_exp_year=" . $expYear
|
||||
. "&client_key=" . Config::$clientKey;
|
||||
|
||||
return ApiRequestor::get(
|
||||
Config::getBaseUrl() . "/v2" . $path,
|
||||
Config::$clientKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do `/v2/token` API request to Core API
|
||||
*
|
||||
* @param $cardNumber
|
||||
* @param $expMoth
|
||||
* @param $expYear
|
||||
* @param $cvv
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function cardToken($cardNumber, $expMoth, $expYear, $cvv)
|
||||
{
|
||||
$path = "/token?card_number=" . $cardNumber
|
||||
. "&card_exp_month=" . $expMoth
|
||||
. "&card_exp_year=" . $expYear
|
||||
. "&card_cvv=" . $cvv
|
||||
. "&client_key=" . Config::$clientKey;
|
||||
|
||||
return ApiRequestor::get(
|
||||
Config::getBaseUrl() . "/v2" . $path,
|
||||
Config::$clientKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do `/v2/point_inquiry/<tokenId>` API request to Core API
|
||||
*
|
||||
* @param string tokenId - tokenId of credit card (more params detail refer to: https://api-docs.midtrans.com)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function cardPointInquiry($tokenId)
|
||||
{
|
||||
return ApiRequestor::get(
|
||||
Config::getBaseUrl() . '/v2/point_inquiry/' . $tokenId,
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create `/v2/pay/account` API request to Core API
|
||||
*
|
||||
* @param string create pay account request (more params detail refer to: https://api-docs.midtrans.com/#create-pay-account)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function linkPaymentAccount($param)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/pay/account',
|
||||
Config::$serverKey,
|
||||
$param
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do `/v2/pay/account/<accountId>` API request to Core API
|
||||
*
|
||||
* @param string accountId (more params detail refer to: https://api-docs.midtrans.com/#get-pay-account)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getPaymentAccount($accountId)
|
||||
{
|
||||
return ApiRequestor::get(
|
||||
Config::getBaseUrl() . '/v2/pay/account/' . $accountId,
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbind `/v2/pay/account/<accountId>/unbind` API request to Core API
|
||||
*
|
||||
* @param string accountId (more params detail refer to: https://api-docs.midtrans.com/#unbind-pay-account)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function unlinkPaymentAccount($accountId)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/pay/account/' . $accountId . '/unbind',
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create `/v1/subscription` API request to Core API
|
||||
*
|
||||
* @param string create subscription request (more params detail refer to: https://api-docs.midtrans.com/#create-subscription)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function createSubscription($param)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v1/subscriptions',
|
||||
Config::$serverKey,
|
||||
$param
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do `/v1/subscription/<subscription_id>` API request to Core API
|
||||
*
|
||||
* @param string get subscription request (more params detail refer to: https://api-docs.midtrans.com/#get-subscription)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getSubscription($SubscriptionId)
|
||||
{
|
||||
return ApiRequestor::get(
|
||||
Config::getBaseUrl() . '/v1/subscriptions/' . $SubscriptionId,
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do disable `/v1/subscription/<subscription_id>/disable` API request to Core API
|
||||
*
|
||||
* @param string disable subscription request (more params detail refer to: https://api-docs.midtrans.com/#disable-subscription)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function disableSubscription($SubscriptionId)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v1/subscriptions/' . $SubscriptionId . '/disable',
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do enable `/v1/subscription/<subscription_id>/enable` API request to Core API
|
||||
*
|
||||
* @param string enable subscription request (more params detail refer to: https://api-docs.midtrans.com/#enable-subscription)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function enableSubscription($SubscriptionId)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v1/subscriptions/' . $SubscriptionId . '/enable',
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do update subscription `/v1/subscription/<subscription_id>` API request to Core API
|
||||
*
|
||||
* @param string update subscription request (more params detail refer to: https://api-docs.midtrans.com/#update-subscription)
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function updateSubscription($SubscriptionId, $param)
|
||||
{
|
||||
return ApiRequestor::patch(
|
||||
Config::getBaseUrl() . '/v1/subscriptions/' . $SubscriptionId,
|
||||
Config::$serverKey,
|
||||
$param
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
/**
|
||||
* Read raw post input and parse as JSON. Provide getters for fields in notification object
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
*
|
||||
* namespace Midtrans;
|
||||
*
|
||||
* $notif = new Notification();
|
||||
* echo $notif->order_id;
|
||||
* echo $notif->transaction_status;
|
||||
* ```
|
||||
*/
|
||||
class Notification
|
||||
{
|
||||
private $response;
|
||||
|
||||
public function __construct($input_source = "php://input")
|
||||
{
|
||||
$raw_notification = json_decode(file_get_contents($input_source), true);
|
||||
$status_response = Transaction::status($raw_notification['transaction_id']);
|
||||
$this->response = $status_response;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
if (isset($this->response->$name)) {
|
||||
return $this->response->$name;
|
||||
}
|
||||
}
|
||||
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
/**
|
||||
* Request params filters.
|
||||
*
|
||||
* It truncate fields that have length limit, remove not allowed characters from other fields
|
||||
*
|
||||
* This feature is optional, you can control it with Config::$isSanitized (default: false)
|
||||
*/
|
||||
class Sanitizer
|
||||
{
|
||||
private $filters;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->filters = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and modify data
|
||||
*
|
||||
* @param mixed[] $json
|
||||
*/
|
||||
public static function jsonRequest(&$json)
|
||||
{
|
||||
$keys = array('item_details', 'customer_details');
|
||||
foreach ($keys as $key) {
|
||||
if (!isset($json[$key])) continue;
|
||||
$camel = static::upperCamelize($key);
|
||||
$function = "field$camel";
|
||||
static::$function($json[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
private static function fieldItemDetails(&$items)
|
||||
{
|
||||
foreach ($items as &$item) {
|
||||
$id = new self;
|
||||
$item['id'] = $id
|
||||
->maxLength(50)
|
||||
->apply($item['id']);
|
||||
$name = new self;
|
||||
$item['name'] = $name
|
||||
->maxLength(50)
|
||||
->apply($item['name']);
|
||||
}
|
||||
}
|
||||
|
||||
private static function fieldCustomerDetails(&$field)
|
||||
{
|
||||
if (isset($field['first_name'])) {
|
||||
$first_name = new self;
|
||||
$field['first_name'] = $first_name->maxLength(255)->apply($field['first_name']);
|
||||
}
|
||||
|
||||
if (isset($field['last_name'])) {
|
||||
$last_name = new self;
|
||||
$field['last_name'] = $last_name->maxLength(255)->apply($field['last_name']);
|
||||
}
|
||||
|
||||
if (isset($field['email'])) {
|
||||
$email = new self;
|
||||
$field['email'] = $email->maxLength(255)->apply($field['email']);
|
||||
}
|
||||
|
||||
if (isset($field['phone'])) {
|
||||
$phone = new self;
|
||||
$field['phone'] = $phone->maxLength(255)->apply($field['phone']);
|
||||
}
|
||||
|
||||
if (!empty($field['billing_address']) || !empty($field['shipping_address'])) {
|
||||
$keys = array('billing_address', 'shipping_address');
|
||||
foreach ($keys as $key) {
|
||||
if (!isset($field[$key])) continue;
|
||||
|
||||
$camel = static::upperCamelize($key);
|
||||
$function = "field$camel";
|
||||
static::$function($field[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function fieldBillingAddress(&$field)
|
||||
{
|
||||
$fields = array(
|
||||
'first_name' => 255,
|
||||
'last_name' => 255,
|
||||
'address' => 255,
|
||||
'city' => 255,
|
||||
'country_code' => 3
|
||||
);
|
||||
|
||||
foreach ($fields as $key => $value) {
|
||||
if (isset($field[$key])) {
|
||||
$self = new self;
|
||||
$field[$key] = $self
|
||||
->maxLength($value)
|
||||
->apply($field[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($field['postal_code'])) {
|
||||
$postal_code = new self;
|
||||
$field['postal_code'] = $postal_code
|
||||
->whitelist('A-Za-z0-9\\- ')
|
||||
->maxLength(10)
|
||||
->apply($field['postal_code']);
|
||||
}
|
||||
if (isset($field['phone'])) {
|
||||
static::fieldPhone($field['phone']);
|
||||
}
|
||||
}
|
||||
|
||||
private static function fieldShippingAddress(&$field)
|
||||
{
|
||||
static::fieldBillingAddress($field);
|
||||
}
|
||||
|
||||
private static function fieldPhone(&$field)
|
||||
{
|
||||
$plus = substr($field, 0, 1) === '+';
|
||||
$self = new self;
|
||||
$field = $self
|
||||
->whitelist('\\d\\-\\(\\) ')
|
||||
->maxLength(19)
|
||||
->apply($field);
|
||||
|
||||
if ($plus) $field = '+' . $field;
|
||||
$self = new self;
|
||||
$field = $self
|
||||
->maxLength(19)
|
||||
->apply($field);
|
||||
}
|
||||
|
||||
private function maxLength($length)
|
||||
{
|
||||
$this->filters[] = function ($input) use ($length) {
|
||||
return substr($input, 0, $length);
|
||||
};
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function whitelist($regex)
|
||||
{
|
||||
$this->filters[] = function ($input) use ($regex) {
|
||||
return preg_replace("/[^$regex]/", '', $input);
|
||||
};
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function apply($input)
|
||||
{
|
||||
foreach ($this->filters as $filter) {
|
||||
$input = call_user_func($filter, $input);
|
||||
}
|
||||
return $input;
|
||||
}
|
||||
|
||||
private static function upperCamelize($string)
|
||||
{
|
||||
return str_replace(' ', '', ucwords(str_replace('_', ' ', $string)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Create Snap payment page and return snap token
|
||||
*/
|
||||
class Snap
|
||||
{
|
||||
/**
|
||||
* Create Snap payment page
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
*
|
||||
* namespace Midtrans;
|
||||
*
|
||||
* $params = array(
|
||||
* 'transaction_details' => array(
|
||||
* 'order_id' => rand(),
|
||||
* 'gross_amount' => 10000,
|
||||
* )
|
||||
* );
|
||||
* $paymentUrl = Snap::getSnapToken($params);
|
||||
* ```
|
||||
*
|
||||
* @param array $params Payment options
|
||||
* @return string Snap token.
|
||||
* @throws Exception curl error or midtrans error
|
||||
*/
|
||||
public static function getSnapToken($params)
|
||||
{
|
||||
return (Snap::createTransaction($params)->token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Snap URL payment
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
*
|
||||
* namespace Midtrans;
|
||||
*
|
||||
* $params = array(
|
||||
* 'transaction_details' => array(
|
||||
* 'order_id' => rand(),
|
||||
* 'gross_amount' => 10000,
|
||||
* )
|
||||
* );
|
||||
* $paymentUrl = Snap::getSnapUrl($params);
|
||||
* ```
|
||||
*
|
||||
* @param array $params Payment options
|
||||
* @return string Snap redirect url.
|
||||
* @throws Exception curl error or midtrans error
|
||||
*/
|
||||
public static function getSnapUrl($params)
|
||||
{
|
||||
return (Snap::createTransaction($params)->redirect_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Snap payment page, with this version returning full API response
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```php
|
||||
* $params = array(
|
||||
* 'transaction_details' => array(
|
||||
* 'order_id' => rand(),
|
||||
* 'gross_amount' => 10000,
|
||||
* )
|
||||
* );
|
||||
* $paymentUrl = Snap::getSnapToken($params);
|
||||
* ```
|
||||
*
|
||||
* @param array $params Payment options
|
||||
* @return object Snap response (token and redirect_url).
|
||||
* @throws Exception curl error or midtrans error
|
||||
*/
|
||||
public static function createTransaction($params)
|
||||
{
|
||||
$payloads = array(
|
||||
'credit_card' => array(
|
||||
// 'enabled_payments' => array('credit_card'),
|
||||
'secure' => Config::$is3ds
|
||||
)
|
||||
);
|
||||
|
||||
if (isset($params['item_details'])) {
|
||||
$gross_amount = 0;
|
||||
foreach ($params['item_details'] as $item) {
|
||||
$gross_amount += $item['quantity'] * $item['price'];
|
||||
}
|
||||
$params['transaction_details']['gross_amount'] = $gross_amount;
|
||||
}
|
||||
|
||||
if (Config::$isSanitized) {
|
||||
Sanitizer::jsonRequest($params);
|
||||
}
|
||||
|
||||
$params = array_replace_recursive($payloads, $params);
|
||||
|
||||
return ApiRequestor::post(
|
||||
Config::getSnapBaseUrl() . '/transactions',
|
||||
Config::$serverKey,
|
||||
$params
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
/**
|
||||
* Send request to Snap API
|
||||
* Better don't use this class directly, use Snap
|
||||
* @deprecated this class already deprecated. We will deleted on the next major release. We have been centralized the
|
||||
* requestor via ApiRequestor.php
|
||||
*/
|
||||
|
||||
class SnapApiRequestor
|
||||
{
|
||||
/**
|
||||
* Send GET request
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $server_key
|
||||
* @param mixed[] $data_hash
|
||||
*/
|
||||
public static function get($url, $server_key, $data_hash)
|
||||
{
|
||||
return self::remoteCall($url, $server_key, $data_hash, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send POST request
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $server_key
|
||||
* @param mixed[] $data_hash
|
||||
*/
|
||||
public static function post($url, $server_key, $data_hash)
|
||||
{
|
||||
return self::remoteCall($url, $server_key, $data_hash, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually send request to API server
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $server_key
|
||||
* @param mixed[] $data_hash
|
||||
* @param bool $post
|
||||
*/
|
||||
public static function remoteCall($url, $server_key, $data_hash, $post = true)
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
$curl_options = array(
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
'Authorization: Basic ' . base64_encode($server_key . ':')
|
||||
),
|
||||
CURLOPT_RETURNTRANSFER => 1,
|
||||
// CURLOPT_CAINFO => dirname(__FILE__) . "/../data/cacert.pem"
|
||||
);
|
||||
|
||||
// merging with Config::$curlOptions
|
||||
if (count(Config::$curlOptions)) {
|
||||
// We need to combine headers manually, because it's array and it will no be merged
|
||||
if (Config::$curlOptions[CURLOPT_HTTPHEADER]) {
|
||||
$mergedHeders = array_merge($curl_options[CURLOPT_HTTPHEADER], Config::$curlOptions[CURLOPT_HTTPHEADER]);
|
||||
$headerOptions = array( CURLOPT_HTTPHEADER => $mergedHeders );
|
||||
} else {
|
||||
$mergedHeders = array();
|
||||
}
|
||||
|
||||
$curl_options = array_replace_recursive($curl_options, Config::$curlOptions, $headerOptions);
|
||||
}
|
||||
|
||||
if ($post) {
|
||||
$curl_options[CURLOPT_POST] = 1;
|
||||
|
||||
if ($data_hash) {
|
||||
$body = json_encode($data_hash);
|
||||
$curl_options[CURLOPT_POSTFIELDS] = $body;
|
||||
} else {
|
||||
$curl_options[CURLOPT_POSTFIELDS] = '';
|
||||
}
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, $curl_options);
|
||||
|
||||
// For testing purpose
|
||||
if (class_exists('\Midtrans\VT_Tests') && VT_Tests::$stubHttp) {
|
||||
$result = self::processStubed($curl_options, $url, $server_key, $data_hash, $post);
|
||||
$info = VT_Tests::$stubHttpStatus;
|
||||
} else {
|
||||
$result = curl_exec($ch);
|
||||
$info = curl_getinfo($ch);
|
||||
// curl_close($ch);
|
||||
}
|
||||
|
||||
if ($result === false) {
|
||||
throw new \Exception('CURL Error: ' . curl_error($ch), curl_errno($ch));
|
||||
} else {
|
||||
try {
|
||||
$result_array = json_decode($result);
|
||||
} catch (\Exception $e) {
|
||||
$message = "API Request Error unable to json_decode API response: ".$result . ' | Request url: '.$url;
|
||||
throw new \Exception($message);
|
||||
}
|
||||
if ($info['http_code'] != 201) {
|
||||
$message = 'Midtrans Error (' . $info['http_code'] . '): '
|
||||
. $result . ' | Request url: '.$url;
|
||||
throw new \Exception($message, $info['http_code']);
|
||||
} else {
|
||||
return $result_array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function processStubed($curl, $url, $server_key, $data_hash, $post)
|
||||
{
|
||||
VT_Tests::$lastHttpRequest = array(
|
||||
"url" => $url,
|
||||
"server_key" => $server_key,
|
||||
"data_hash" => $data_hash,
|
||||
"post" => $post,
|
||||
"curl" => $curl
|
||||
);
|
||||
|
||||
return VT_Tests::$stubHttpResponse;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Midtrans;
|
||||
|
||||
use Exception;
|
||||
/**
|
||||
* API methods to get transaction status, approve and cancel transactions
|
||||
*/
|
||||
class Transaction
|
||||
{
|
||||
|
||||
/**
|
||||
* Retrieve transaction status
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @return mixed[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function status($id)
|
||||
{
|
||||
return ApiRequestor::get(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/status',
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve B2B transaction status
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @return mixed[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function statusB2b($id)
|
||||
{
|
||||
return ApiRequestor::get(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/status/b2b',
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approve challenge transaction
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function approve($id)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/approve',
|
||||
Config::$serverKey,
|
||||
false
|
||||
)->status_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel transaction before it's settled
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function cancel($id)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/cancel',
|
||||
Config::$serverKey,
|
||||
false
|
||||
)->status_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire transaction before it's setteled
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @return mixed[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function expire($id)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/expire',
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction status can be updated into refund
|
||||
* if the customer decides to cancel completed/settlement payment.
|
||||
* The same refund id cannot be reused again.
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @param $params
|
||||
* @return mixed[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function refund($id, $params)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/refund',
|
||||
Config::$serverKey,
|
||||
$params
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction status can be updated into refund
|
||||
* if the customer decides to cancel completed/settlement payment.
|
||||
* The same refund id cannot be reused again.
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @return mixed[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function refundDirect($id, $params)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/refund/online/direct',
|
||||
Config::$serverKey,
|
||||
$params
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deny method can be triggered to immediately deny card payment transaction
|
||||
* in which fraud_status is challenge.
|
||||
*
|
||||
* @param string $id Order ID or transaction ID
|
||||
*
|
||||
* @return mixed[]
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function deny($id)
|
||||
{
|
||||
return ApiRequestor::post(
|
||||
Config::getBaseUrl() . '/v2/' . $id . '/deny',
|
||||
Config::$serverKey,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user