Amazon Gift Card on Demand Incentives stand alone class

This commit is contained in:
2021-10-18 18:24:38 +09:00
commit b00d545a10
14 changed files with 1772 additions and 0 deletions

429
src/Amazon/AWS/AWS.php Normal file
View File

@@ -0,0 +1,429 @@
<?php
namespace Amazon\AWS;
use Amazon\Client\Client;
use Amazon\Config\Config;
use Amazon\Exceptions\AmazonErrors;
use Amazon\Debug\AmazonDebug;
use Amazon\Response\CancelResponse;
use Amazon\Response\CreateBalanceResponse;
use Amazon\Response\CreateResponse;
class AWS
{
public const SERVICE_NAME = 'AGCODService';
public const ACCEPT_HEADER = 'accept';
public const CONTENT_HEADER = 'content-type';
public const HOST_HEADER = 'host';
public const X_AMZ_DATE_HEADER = 'x-amz-date';
public const X_AMZ_TARGET_HEADER = 'x-amz-target';
public const AUTHORIZATION_HEADER = 'Authorization';
public const AWS_SHA256_ALGORITHM = 'AWS4-HMAC-SHA256';
public const KEY_QUALIFIER = 'AWS4';
public const TERMINATION_STRING = 'aws4_request';
public const CREATE_GIFT_CARD_SERVICE = 'CreateGiftCard';
public const CANCEL_GIFT_CARD_SERVICE = 'CancelGiftCard';
public const GET_AVAILABLE_FUNDS_SERVICE = 'GetAvailableFunds';
private $config;
/**
* @param Config $config
*/
public function __construct(Config $config)
{
$this->config = $config;
AmazonDebug::setFlag($config->getDebug());
AmazonDebug::setId();
AmazonDebug::writeLog([__METHOD__ => date('Y-m-d H:m:s.u')]);
}
/**
* @param float $amount
* @param string|null $creation_id
* @return CreateResponse
*
* @throws AmazonErrors
*/
public function getCode(float $amount, ?string $creation_id = null): CreateResponse
{
$service_operation = self::CREATE_GIFT_CARD_SERVICE;
$payload = $this->getGiftCardPayload($amount, $creation_id);
$canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest(
$payload,
$canonical_request,
$service_operation,
$date_time_string
), true);
return new CreateResponse($result);
}
/**
* @param string $creation_request_id
* @param string $gift_card_id
* @return CancelResponse
*
* @throws AmazonErrors
*/
public function cancelCode(string $creation_request_id, string $gift_card_id): CancelResponse
{
$service_operation = self::CANCEL_GIFT_CARD_SERVICE;
$payload = $this->getCancelGiftCardPayload($creation_request_id, $gift_card_id);
$canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest(
$payload,
$canonical_request,
$service_operation,
$date_time_string
), true);
return new CancelResponse($result);
}
/**
* @return CreateBalanceResponse
*
* @throws AmazonErrors
*/
public function getBalance(): CreateBalanceResponse
{
$service_operation = self::GET_AVAILABLE_FUNDS_SERVICE;
$payload = $this->getAvailableFundsPayload();
$canonical_request = $this->getCanonicalRequest($service_operation, $payload);
$date_time_string = $this->getTimestamp();
AmazonDebug::writeLog(['call' => __METHOD__]);
$result = json_decode($this->makeRequest(
$payload,
$canonical_request,
$service_operation,
$date_time_string
), true);
return new CreateBalanceResponse($result);
}
/**
* @param string $payload
* @param string $canonical_request
* @param string $service_operation
* @param string $date_time_string
* @return string
*/
public function makeRequest(
string $payload,
string $canonical_request,
string $service_operation,
string $date_time_string
): string {
// debug
AmazonDebug::writeLog([__METHOD__ => [
'Operation' => $service_operation,
'Payload' => $payload,
'Cannonical Request' => $canonical_request,
'Date Time String' => $date_time_string
]]);
$KEY_QUALIFIER = self::KEY_QUALIFIER;
$canonical_request_hash = $this->buildHash($canonical_request);
$string_to_sign = $this->buildStringToSign($canonical_request_hash);
$authorization_value = $this->buildAuthSignature($string_to_sign);
$secret_key = $this->config->getSecret();
$endpoint = $this->config->getEndpoint();
$region_name = $this->getRegion();
$SERVICE_NAME = 'AGCODService';
$service_target = 'com.amazonaws.agcod.' . $SERVICE_NAME . '.' . $service_operation;
$date_string = $this->getDateString();
$signature_aws_key = $KEY_QUALIFIER . $secret_key;
$k_date = $this->hmac($date_string, $signature_aws_key);
$k_date_hexis = $this->hmac($date_string, $signature_aws_key, false);
$k_region = $this->hmac($region_name, $k_date);
$k_region_hexis = $this->hmac($region_name, $k_date, false);
$k_service_hexis = $this->hmac($SERVICE_NAME, $k_region, false);
AmazonDebug::writeLog([__METHOD__ => [
'Date' => $k_date_hexis,
'Region' => $k_region_hexis,
'Service' => $k_service_hexis,
]]);
$url = 'https://' . $endpoint . '/' . $service_operation;
$headers = $this->buildHeaders($payload, $authorization_value, $date_time_string, $service_target);
return (new Client())->request($url, $headers, $payload);
}
/**
* @param string $payload
* @param string $authorization_value
* @param string $date_time_string
* @param string $service_target
* @return array
*/
public function buildHeaders(
string $payload,
string $authorization_value,
string $date_time_string,
string $service_target
): array {
$ACCEPT_HEADER = self::ACCEPT_HEADER;
$X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER;
$X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER;
$AUTHORIZATION_HEADER = self::AUTHORIZATION_HEADER;
return [
'Content-Type:' . $this->getContentType(),
'Content-Length: ' . strlen($payload),
$AUTHORIZATION_HEADER . ':' . $authorization_value,
$X_AMZ_DATE_HEADER . ':' . $date_time_string,
$X_AMZ_TARGET_HEADER . ':' . $service_target,
$ACCEPT_HEADER . ':' . $this->getContentType()
];
}
/**
* @param string $string_to_sign
* @return string
*/
public function buildAuthSignature(string $string_to_sign): string
{
$AWS_SHA256_ALGORITHM = self::AWS_SHA256_ALGORITHM;
$SERVICE_NAME = self::SERVICE_NAME;
$TERMINATION_STRING = self::TERMINATION_STRING;
$ACCEPT_HEADER = self::ACCEPT_HEADER;
$HOST_HEADER = self::HOST_HEADER;
$X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER;
$X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER;
$aws_key_id = $this->config->getAccessKey();
$region_name = $this->getRegion();
$date_string = $this->getDateString();
$derived_key = $this->buildDerivedKey();
// Calculate signature per http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
$final_signature = $this->hmac($string_to_sign, $derived_key, false);
// Assemble Authorization Header with signing information
// per http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html
$authorization_value =
$AWS_SHA256_ALGORITHM
. ' Credential=' . $aws_key_id
. '/' . $date_string . '/' . $region_name . '/' . $SERVICE_NAME . '/' . $TERMINATION_STRING . ','
. ' SignedHeaders='
. $ACCEPT_HEADER . ';' . $HOST_HEADER . ';' . $X_AMZ_DATE_HEADER . ';' . $X_AMZ_TARGET_HEADER . ','
. ' Signature='
. $final_signature;
return $authorization_value;
}
/**
* @param string $canonical_request_hash
* @return string
*/
public function buildStringToSign($canonical_request_hash): string
{
$AWS_SHA256_ALGORITHM = self::AWS_SHA256_ALGORITHM;
$TERMINATION_STRING = self::TERMINATION_STRING;
$SERVICE_NAME = self::SERVICE_NAME;
$region_name = $this->getRegion();
$date_time_string = $this->getTimestamp();
$date_string = $this->getDateString();
$string_to_sign = "$AWS_SHA256_ALGORITHM\n"
. "$date_time_string\n"
. "$date_string/$region_name/$SERVICE_NAME/$TERMINATION_STRING\n"
. "$canonical_request_hash";
return $string_to_sign;
}
/**
* @param bool $rawOutput
* @return string
*/
public function buildDerivedKey(bool $rawOutput = true): string
{
$KEY_QUALIFIER = self::KEY_QUALIFIER;
$TERMINATION_STRING = self::TERMINATION_STRING;
$SERVICE_NAME = self::SERVICE_NAME;
$aws_secret_key = $this->config->getSecret();
// Append Key Qualifier, "AWS4", to secret key per
// shttp://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html
$signature_aws_key = $KEY_QUALIFIER . $aws_secret_key;
$region_name = $this->getRegion();
$date_string = $this->getDateString();
$k_date = $this->hmac($date_string, $signature_aws_key);
$k_region = $this->hmac($region_name, $k_date);
$k_service = $this->hmac($SERVICE_NAME, $k_region);
// Derived the Signing key (derivedKey aka kSigning)
return $this->hmac($TERMINATION_STRING, $k_service, $rawOutput);
}
/**
* @return string
*/
public function getRegion(): string
{
$endpoint = $this->config->getEndpoint();
// default region
$region_name = 'us-east-1';
switch ($endpoint) {
case 'agcod-v2.amazon.com':
case 'agcod-v2-gamma.amazon.com':
$region_name = 'us-east-1';
break;
case 'agcod-v2-eu.amazon.com':
case 'agcod-v2-eu-gamma.amazon.com':
$region_name = 'us-west-1';
break;
case 'agcod-v2-fe.amazon.com':
case 'agcod-v2-fe-gamma.amazon.com':
$region_name = 'us-west-2';
break;
}
return $region_name;
}
/**
* @param float $amount
* @param string $creation_id
* @return string
*/
public function getGiftCardPayload(float $amount, ?string $creation_id = null): string
{
$amount = trim($amount);
$payload = [
'creationRequestId' => $creation_id ?: uniqid($this->config->getPartner() . '_'),
'partnerId' => $this->config->getPartner(),
'value' =>
[
'currencyCode' => $this->config->getCurrency(),
'amount' => (float)$amount
]
];
return json_encode($payload);
}
/**
* @param string $creation_request_id
* @param string $gift_card_id
* @return string
*/
public function getCancelGiftCardPayload(string $creation_request_id, string $gift_card_id): string
{
$gift_card_response_id = trim($gift_card_id);
$payload = [
'creationRequestId' => $creation_request_id,
'partnerId' => $this->config->getPartner(),
'gcId' => $gift_card_response_id
];
return json_encode($payload);
}
/**
* @return string
*/
public function getAvailableFundsPayload(): string
{
$payload = [
'partnerId' => $this->config->getPartner(),
];
return json_encode($payload);
}
/**
* @param string $service_operation
* @param string $payload
* @return string
*/
public function getCanonicalRequest(string $service_operation, string $payload): string
{
$HOST_HEADER = self::HOST_HEADER;
$X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER;
$X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER;
$ACCEPT_HEADER = self::ACCEPT_HEADER;
$payload_hash = $this->buildHash($payload);
$canonical_headers = $this->buildCanonicalHeaders($service_operation);
$canonical_request = "POST\n"
. "/$service_operation\n\n"
. "$canonical_headers\n\n"
. "$ACCEPT_HEADER;$HOST_HEADER;$X_AMZ_DATE_HEADER;$X_AMZ_TARGET_HEADER\n"
. "$payload_hash";
return $canonical_request;
}
/**
* @param string $data
* @return string
*/
public function buildHash(string $data): string
{
return hash('sha256', $data);
}
/**
* @return false|string
*/
public function getTimestamp()
{
return gmdate('Ymd\THis\Z');
}
/**
* @param string $data
* @param string $key
* @param bool $raw
* @return string
*/
public function hmac(string $data, string $key, bool $raw = true): string
{
return hash_hmac('sha256', $data, $key, $raw);
}
/**
* @return bool|string
*/
public function getDateString()
{
return substr($this->getTimestamp(), 0, 8);
}
/**
* @return string
*/
public function getContentType(): string
{
return 'application/json';
}
/**
* @param string $service_operation
* @return string
*/
public function buildCanonicalHeaders(string $service_operation): string
{
$ACCEPT_HEADER = self::ACCEPT_HEADER;
$HOST_HEADER = self::HOST_HEADER;
$X_AMZ_DATE_HEADER = self::X_AMZ_DATE_HEADER;
$X_AMZ_TARGET_HEADER = self::X_AMZ_TARGET_HEADER;
$date_time_string = $this->getTimestamp();
$endpoint = $this->config->getEndpoint();
$content_type = $this->getContentType();
return "$ACCEPT_HEADER:$content_type\n"
. "$HOST_HEADER:$endpoint\n"
. "$X_AMZ_DATE_HEADER:$date_time_string\n"
. "$X_AMZ_TARGET_HEADER:com.amazonaws.agcod.AGCODService.$service_operation";
}
}
// __END__

View File

@@ -0,0 +1,182 @@
<?php
/*
* Amazon Incentive Code
*
* # settings:
* aws endpoint (also sets region)
* aws key
* aws secret
* aws partner id
* money type (set as default, override in call)
* money value (set as default, override in call)
*
* # checks
* endpoint + region must match
*
* # calls:
* create gift card: CreateGiftCard
* cancel gift card: CancelGiftCard
*
* activate gift card: ActivateGiftCard
* deactivate gift card: DeactivateGiftCard
*
* gift card status: ActivationStatusCheck
*
* check available funds: GetAvailablefunds
*
* api server health check
*
* # sub classes
* config reader/checker
* API v4 encrypter
* submitter/data getter
* error handler/retry
*/
namespace Amazon;
use Amazon\AWS\AWS;
use Amazon\Config\Config;
use Amazon\Exceptions\AmazonErrors;
class AmazonIncentives
{
private $config;
/**
* AmazonGiftCode constructor.
*
* @param string|null $key
* @param string|null $secret
* @param string|null $partner
* @param string|null $endpoint
* @param string|null $currency
* @param bool|null $debug
*/
public function __construct(
string $key = null,
string $secret = null,
string $partner = null,
string $endpoint = null,
string $currency = null,
bool $debug = null
) {
// load AWS settings
// fail here if settings missing
$this->config = new Config($key, $secret, $partner, $endpoint, $currency, $debug);
}
// *********************************************************************
// PRIVATE HELPER METHODS
// *********************************************************************
// *********************************************************************
// PUBLIC DEBUG METHODS
// *********************************************************************
// like log collector (array) and returner
// *********************************************************************
// PUBLIC METHODS
// *********************************************************************
// public function activateGiftCard(): array
// {
// return [];
// }
// public function deactivateGiftCard(string $card_id): array
// {
// return [];
// }
// public function activationStatusCheck(string $card_id): array
// {
// return [];
// }
/**
* @param float $value
* @param string $creation_request_id AWS creationRequestId
* @return Response\CreateResponse
*
* @throws AmazonErrors
*/
public function buyGiftCard(float $value, string $creation_request_id = null): Response\CreateResponse
{
return (new AWS($this->config))->getCode($value, $creation_request_id);
}
/**
* @param string $creation_request_id AWS creationRequestId
* @param string $gift_card_id AWS gcId
* @return Response\CancelResponse
*/
public function cancelGiftCard(string $creation_request_id, string $gift_card_id): Response\CancelResponse
{
return (new AWS($this->config))->cancelCode($creation_request_id, $gift_card_id);
}
/**
* @return Response\CreateBalanceResponse
*
* @throws AmazonErrors
*/
public function getAvailableFunds(): Response\CreateBalanceResponse
{
return (new AWS($this->config))->getBalance();
}
/**
* AmazonGiftCode make own client.
*
* @param string|null $key
* @param string|null $secret
* @param string|null $partner
* @param string|null $endpoint
* @param string|null $currency
* @param bool|null $debug
* @return AmazonGiftCode
*/
public static function make(
string $key = null,
string $secret = null,
string $partner = null,
string $endpoint = null,
string $currency = null,
bool $debug = null
): AmazonIncentives {
return new static($key, $secret, $partner, $endpoint, $currency, $debug);
}
/**
* Decodes the Exception message body
* Returns an array with code (Amazon error codes), type (Amazon error info)
* message (Amazon returned error message string)
*
* @param string $message Exception message json string
* @return array Decoded with code, type, message fields
*/
public static function decodeExceptionMessage(string $message): array
{
return json_decode($message, true);
}
// *********************************************************************
// PUBLIC TEST METHODS
// *********************************************************************
public function checkMe(): array
{
$data = [];
$data['ENV'] = $_ENV;
$data['CONFIG'] = $this->config;
$data['KEY'] = $this->config->getAccessKey();
return $data;
}
}
// __END__

View File

@@ -0,0 +1,86 @@
<?php
namespace Amazon\Client;
use Amazon\Exceptions\AmazonErrors;
class Client implements ClientInterface
{
// instead of JsonResponse::HTTP_OK
private const HTTP_OK = 200;
/**
*
* @param string $url The URL being requested, including domain and protocol
* @param array $headers Headers to be used in the request
* @param array|string $params Can be nested for arrays and hashes
*
*
* @return String
*/
public function request(string $url, array $headers, $params): string
{
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
// curl_setopt($handle, CURLOPT_FAILONERROR, true);
curl_setopt($handle, CURLOPT_POSTFIELDS, $params);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($handle);
if ($result === false) {
$err = curl_errno($handle);
$message = curl_error($handle);
$this->handleCurlError($url, $err, $message);
}
if (curl_getinfo($handle, CURLINFO_HTTP_CODE) !== self::HTTP_OK) {
$err = curl_errno($handle);
// extract all the error codes from Amazon
$error_code = json_decode($result)->errorCode;
$error_type = json_decode($result)->errorType;
$message = json_decode($result)->message;
throw AmazonErrors::getError(
$error_code,
$error_type,
$message,
$err
);
}
return $result;
}
/**
* Undocumented function
*
* @param string $url
* @param string $errno
* @param string $message
* @return void
*/
private function handleCurlError(string $url, int $errno, string $message): void
{
switch ($errno) {
case CURLE_COULDNT_CONNECT:
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_OPERATION_TIMEOUTED:
$msg = 'Could not connect to AWS (' . $url . '). Please check your '
. 'internet connection and try again.';
break;
case CURLE_SSL_CACERT:
case CURLE_SSL_PEER_CERTIFICATE:
$msg = 'Could not verify AWS SSL certificate. Please make sure '
. 'that your network is not intercepting certificates. '
. '(Try going to ' . $url . 'in your browser.) '
. 'If this problem persists,';
break;
case 0:
default:
$msg = 'Unexpected error communicating with AWS. ' . $message;
}
throw new \RuntimeException($msg);
}
}
// __END__

View File

@@ -0,0 +1,18 @@
<?php
namespace Amazon\Client;
interface ClientInterface
{
/**
* @param string $url The URL being requested, including domain and protocol
* @param array $headers Headers to be used in the request
* @param array|string $params Can be nested for arrays and hashes
*
* @return String
*/
public function request(string $url, array $headers, $params): string;
}
// __END__

View File

@@ -0,0 +1,172 @@
<?php
namespace Amazon\Config;
class Config implements ConfigInterface
{
/**
* @var string
*/
private $endpoint;
/**
* @var string
*/
private $access_key;
/**
* @var string
*/
private $secret_key;
/**
* @var string
*/
private $partner_id;
/**
* @var string
*/
private $currency;
/**
* @var bool
*/
private $debug;
/**
* @param string|null $key
* @param string|null $secret
* @param string|null $partner
* @param string|null $endpoint
* @param string|null $currency
*/
public function __construct(
?string $key,
?string $secret,
?string $partner,
?string $endpoint,
?string $currency,
?bool $debug,
) {
$this->setAccessKey($key ?: $_ENV['AWS_GIFT_CARD_KEY'] ?? '');
$this->setSecret($secret ?: $_ENV['AWS_GIFT_CARD_SECRET'] ?? '');
$this->setPartner($partner ?: $_ENV['AWS_GIFT_CARD_PARTNER_ID'] ?? '');
$this->setEndpoint($endpoint ?: $_ENV['AWS_GIFT_CARD_ENDPOINT'] ?? '');
$this->setCurrency($currency ?: $_ENV['AWS_GIFT_CARD_CURRENCY'] ?? '');
$this->setDebug($debug ?: (!empty($_ENV['AWS_DEBUG']) ? true : false));
}
/**
* @return string
*/
public function getEndpoint(): string
{
return $this->endpoint;
}
/**
* @param string $endpoint
* @return ConfigInterface
*/
public function setEndpoint(string $endpoint): ConfigInterface
{
// TODO: check valid endpoint + set region
$this->endpoint = parse_url($endpoint, PHP_URL_HOST);
return $this;
}
/**
* @return string
*/
public function getAccessKey(): string
{
return $this->access_key;
}
/**
* @param string $key
* @return ConfigInterface
*/
public function setAccessKey(string $key): ConfigInterface
{
$this->access_key = $key;
return $this;
}
/**
* @return string
*/
public function getSecret(): string
{
return $this->secret_key;
}
/**
* @param string $secret
* @return ConfigInterface
*/
public function setSecret(string $secret): ConfigInterface
{
$this->secret_key = $secret;
return $this;
}
/**
* @return string
*/
public function getCurrency(): string
{
return $this->currency;
}
/**
* @param string $currency
* @return ConfigInterface
*/
public function setCurrency(string $currency): ConfigInterface
{
// TODO: check currency valid + currenc valid for region
$this->currency = $currency;
return $this;
}
/**
* @return string
*/
public function getPartner(): string
{
return $this->partner_id;
}
/**
* @param string $partner
* @return ConfigInterface
*/
public function setPartner(string $partner): ConfigInterface
{
$this->partner_id = $partner;
return $this;
}
/**
* @return bool
*/
public function getDebug(): bool
{
return $this->debug;
}
/**
* @param bool $debug
* @return ConfigInterface
*/
public function setDebug(bool $debug): ConfigInterface
{
$this->debug = $debug;
return $this;
}
}
// __END__

View File

@@ -0,0 +1,63 @@
<?php
namespace Amazon\Config;
interface ConfigInterface
{
/**
* @return String
*/
public function getEndpoint(): string;
/**
* @param string $endpoint
* @return $this
*/
public function setEndpoint(string $endpoint): ConfigInterface;
/**
* @return String
*/
public function getAccessKey(): string;
/**
* @param string $key
* @return $this
*/
public function setAccessKey(string $key): ConfigInterface;
/**
* @return String
*/
public function getSecret(): string;
/**
* @param string $secret
* @return $this
*/
public function setSecret(string $secret): ConfigInterface;
/**
* @return String
*/
public function getCurrency(): string;
/**
* @param string $currency
* @return $this
*/
public function setCurrency(string $currency): ConfigInterface;
/**
* @return String
*/
public function getPartner(): string;
/**
* @param string $partner
* @return $this
*/
public function setPartner(string $partner): ConfigInterface;
}
// __END__

View File

@@ -0,0 +1,56 @@
<?php
// simple write all into an array that we can poll in the return group
namespace Amazon\Debug;
class AmazonDebug
{
private static $log = [];
private static $debug = false;
private static $id = null;
public function __construct()
{
}
public static function setId(?string $id = null): void
{
if (self::$debug === false) {
return;
}
if ($id === null) {
$id = uniqid();
}
self::$id = $id;
}
public static function getId(): string
{
return self::$id;
}
public static function setFlag(bool $debug): void
{
self::$debug = $debug;
}
public static function writeLog(array $data): void
{
if (self::$debug === false) {
return;
}
self::$log[self::$id][] = $data;
}
public static function getLog(?string $id = null): array
{
if ($id === null) {
return self::$log;
} else {
return self::$log[$id] ?? [];
}
}
}
// __END__

View File

@@ -0,0 +1,37 @@
<?php
namespace Amazon\Exceptions;
use RuntimeException;
class AmazonErrors extends RuntimeException
{
/**
* @param string $error_code errorCode from Amazon
* @param string $error_type errorType from Amazon
* @param string $message
* @param string $_error_code
* @return AmazonErrors
*/
public static function getError(
string $error_code,
string $error_type,
string $message,
string $_error_code
): self {
// NOTE: if xdebug.show_exception_trace is set to 1 this will print ERRORS
return new static(
json_encode([
'code' => $error_code,
'type' => $error_type,
'message' => $message,
// atach log data if exists
'log_id' => \Amazon\Debug\AmazonDebug::getId(),
'log' => \Amazon\Debug\AmazonDebug::getLog(),
]),
$_error_code
);
}
}
// __END__

View File

@@ -0,0 +1,111 @@
<?php
namespace Amazon\Response;
class CancelResponse
{
/**
* Amazon Gift Card gcId.
*
* @var string
*/
protected $id;
/**
* Amazon Gift Card creationRequestId
*
* @var string
*/
protected $creation_request_id;
/**
* Amazon Gift Card status
*
* @var string
*/
protected $status;
/**
* Amazon Gift Card Raw JSON
*
* @var string
*/
protected $raw_json;
/**
* @var array
*/
protected $log;
/**
* Response constructor.
* @param array $json_response
*/
public function __construct(array $json_response)
{
$this->raw_json = $json_response;
$this->log = \Amazon\Debug\AmazonDebug::getLog(\Amazon\Debug\AmazonDebug::getId());
$this->parseJsonResponse($json_response);
}
/**
* @return array
*/
public function getLog(): array
{
return $this->log;
}
/**
* @return string
*/
public function getId(): string
{
return $this->id;
}
/**
* @return string
*/
public function getCreationRequestId(): string
{
return $this->creation_request_id;
}
/**
* @return string
*/
public function getStatus(): string
{
return $this->status;
}
/**
* @return string
*/
public function getRawJson(): string
{
return json_encode($this->raw_json);
}
/**
* @param array $json_response
* @return CancelResponse
*/
public function parseJsonResponse(array $json_response): self
{
if (!is_array($json_response)) {
throw new \RuntimeException('Response must be a scalar value');
}
if (array_key_exists('gcId', $json_response)) {
$this->id = $json_response['gcId'];
}
if (array_key_exists('creationRequestId', $json_response)) {
$this->creation_request_id = $json_response['creationRequestId'];
}
// SUCCESS, FAILURE, RESEND
if (array_key_exists('status', $json_response)) {
$this->status = $json_response['status'];
}
return $this;
}
}
// __END__

View File

@@ -0,0 +1,129 @@
<?php
namespace Amazon\Response;
class CreateBalanceResponse
{
/**
* Amazon Gift Card Balance Amount
*
* @var string
*/
protected $amount;
/**
* Amazon Gift Card Balance Currency
*
* @var string
*/
protected $currency;
/**
* Amazon Gift Card Balance Status
*
* @var string
*/
protected $status;
/**
* Amazon Gift Card Balance Timestamp
*
* @var string
*/
protected $timestamp;
/**
* Amazon Gift Card Raw JSON
*
* @var string
*/
protected $raw_json;
/**
* @var array
*/
protected $log;
/**
* Response constructor.
*
* @param array $json_response
*/
public function __construct(array $json_response)
{
$this->raw_json = $json_response;
$this->log = \Amazon\Debug\AmazonDebug::getLog(\Amazon\Debug\AmazonDebug::getId());
$this->parseJsonResponse($json_response);
}
/**
* @return array
*/
public function getLog(): array
{
return $this->log;
}
/**
* @return string
*/
public function getAmount(): string
{
return $this->amount;
}
/**
* @return string
*/
public function getCurrency(): string
{
return $this->currency;
}
/**
* @return string
*/
public function getStatus(): string
{
return $this->status;
}
/**
* @return string
*/
public function getTimestamp(): string
{
return $this->timestamp;
}
/**
* @return string
*/
public function getRawJson(): string
{
return json_encode($this->raw_json);
}
/**
* Undocumented function
*
* @param array $json_response
* @return CreateBalanceResponse
*/
public function parseJsonResponse(array $json_response): self
{
if (!is_array($json_response)) {
throw new \RuntimeException('Response must be a scalar value');
}
if (array_key_exists('amount', $json_response['availableFunds'])) {
$this->amount = $json_response['availableFunds']['amount'];
}
if (array_key_exists('currencyCode', $json_response['availableFunds'])) {
$this->currency = $json_response['availableFunds']['currencyCode'];
}
// SUCCESS, FAILURE, RESEND
if (array_key_exists('status', $json_response)) {
$this->status = $json_response['status'];
}
if (array_key_exists('timestamp', $json_response)) {
$this->timestamp = $json_response['timestamp'];
}
return $this;
}
}

View File

@@ -0,0 +1,201 @@
<?php
namespace Amazon\Response;
class CreateResponse
{
/**
* Amazon Gift Card gcId.
*
* @var string
*/
protected $id;
/**
* Amazon Gift Card creationRequestId
*
* @var string
*/
protected $creation_request_id;
/**
* Amazon Gift Card gcClaimCode
*
* @var string
*/
protected $claim_code;
/**
* Amazon Gift Card amount
*
* @var float
*/
protected $value;
/**
* Amazon Gift Card currency
*
* @var string
*/
protected $currency;
/**
* Amazon Gift Card status
*
* @var string
*/
protected $status;
/**
* Amazon Gift Card Expiration Date
*
* @var string
*/
protected $expiration_date;
/**
* Amazon Gift Card Expiration Date
*
* @var string
*/
protected $card_status;
/**
* Amazon Gift Card Raw JSON
*
* @var string
*/
protected $raw_json;
/**
* @var array
*/
protected $log;
/**
* Response constructor.
* @param array $json_response
*/
public function __construct(array $json_response)
{
$this->raw_json = $json_response;
$this->log = \Amazon\Debug\AmazonDebug::getLog(\Amazon\Debug\AmazonDebug::getId());
$this->parseJsonResponse($json_response);
}
/**
* @return array
*/
public function getLog(): array
{
return $this->log;
}
/**
* @return string
*/
public function getId(): string
{
return $this->id;
}
/**
* @return string
*/
public function getCreationRequestId(): string
{
return $this->creation_request_id;
}
/**
* @return string
*/
public function getClaimCode(): string
{
return $this->claim_code;
}
/**
* @return string
*/
public function getValue(): string
{
return $this->value;
}
/**
* @return string
*/
public function getCurrency(): string
{
return $this->currency;
}
/**
* @return string
*/
public function getStatus(): string
{
return $this->status;
}
/**
* @return string
*/
public function getExpirationDate(): string
{
return $this->expiration_date;
}
/**
* @return string
*/
public function getCardStatus(): string
{
return $this->card_status;
}
/**
* @return string
*/
public function getRawJson(): string
{
return json_encode($this->raw_json);
}
/**
* @param array $json_response
* @return CreateResponse
*/
public function parseJsonResponse(array $json_response): self
{
if (!is_array($json_response)) {
throw new \RuntimeException('Response must be a scalar value');
}
if (array_key_exists('gcId', $json_response)) {
$this->id = $json_response['gcId'];
}
if (array_key_exists('creationRequestId', $json_response)) {
$this->creation_request_id = $json_response['creationRequestId'];
}
if (array_key_exists('gcClaimCode', $json_response)) {
$this->claim_code = $json_response['gcClaimCode'];
}
if (array_key_exists('amount', $json_response['cardInfo']['value'])) {
$this->value = $json_response['cardInfo']['value']['amount'];
}
if (array_key_exists('currencyCode', $json_response['cardInfo']['value'])) {
$this->currency = $json_response['cardInfo']['value']['currencyCode'];
}
if (array_key_exists('gcExpirationDate', $json_response)) {
$this->expiration_date = $json_response['gcExpirationDate'];
}
if (array_key_exists('cardStatus', $json_response['cardInfo'])) {
$this->card_status = $json_response['cardInfo']['cardStatus'];
}
// SUCCESS, FAILURE, RESEND
if (array_key_exists('status', $json_response)) {
$this->status = $json_response['status'];
}
return $this;
}
}
// __END__

63
test/autoloader.php Normal file
View File

@@ -0,0 +1,63 @@
<?php // phpcs:ignore PSR1.Files.SideEffects
declare(strict_types=1);
namespace Autoloader;
// shall implement an auto loader
if (class_exists('Autoload', false) === false) {
// define the auto loader class
class Autoload
{
// we do it simple here
// passes on the class to load and we search here in namespace
// to load that class
public static function load($class)
{
// print "(1) Class: $class / DIR: " . __DIR__ . "<br>";
// set directory seperator (we need to replace from namespace)
$DS = DIRECTORY_SEPARATOR;
// base lib
$LIB = defined('LIB') ? LIB : '../src' . $DS;
// if lib is in path at the end, do not add lib again
// note that $LIB can have a directory seperator at the end
// strip that out before we do a match
$_LIB = rtrim($LIB, $DS);
if (!preg_match("|$_LIB$|", __DIR__)) {
$LIB .= $DS;
} else {
$LIB = '';
}
// default path is unset
$path = false;
// set path on full dir
// if we have the namespace in the class, strip it out
$len = 0;
if (strpos($class, __NAMESPACE__) !== false) {
$len = strlen(__NAMESPACE__);
}
// set default extension
$extension = '.php';
// set full include path
$path = __DIR__ . $DS . $LIB . substr($class, $len);
// replace namespace \ with dir sepeator
$path = str_replace('\\', $DS, $path) . $extension;
// print "(2) Class clean: $path<br>";
// if path is set and a valid file
if ($path !== false && is_file($path)) {
// print "<b>(3)</b> Load Path: $path<br>";
// we should sub that
// self::loadFile($path);
include $path;
return true;
}
return false;
}
// end class define
}
spl_autoload_register('Autoloader\Autoload::load', true, true);
} // end check for already defined
// __END__

View File

@@ -0,0 +1,141 @@
<?php // phpcs:ignore PSR1.Files.SideEffects
// test for Amazon Gift Card Incentives
// general auto loader
require 'autoloader.php';
// env file loader
require 'read_env_file.php';
// load env data with dotenv
readEnvFile(__DIR__);
print "<h1>Amazon Gift Card Incentives</h1><br>";
// must have set
// endpoint/region: AWS_GIFT_CARD_ENDPOINT
// aws key: AWS_GIFT_CARD_KEY
// aws secret: AWS_GIFT_CARD_SECRET
// partner id: AWS_GIFT_CARD_PARTNER_ID
// optional
// currency: AWS_ICENTIVE_CURRENCY
// as in .env
// AWS_GIFT_CARD_ENDPOINT.TEST
// AWS_GIFT_CARD_ENDPOINT.LIVE
define('LOCATION', 'test');
foreach (
[
'AWS_GIFT_CARD_KEY', 'AWS_GIFT_CARD_SECRET', 'AWS_GIFT_CARD_PARTNER_ID',
'AWS_GIFT_CARD_ENDPOINT', 'AWS_GIFT_CARD_CURRENCY', 'AWS_DEBUG'
] as $key
) {
//
$_ENV[$key] = $_ENV[$key . '.' . strtoupper((LOCATION))] ?? $_ENV[$key] ?? '';
}
/*
ENDPOINTS:
- remove '-gamma' for non sandox
WHERE URL REGION
North America https://agcod-v2-gamma.amazon.com us-east-1
https://agcod-v2.amazon.com
(US, CA, MX)
Europe and Asia https://agcod-v2-eu-gamma.amazon.com eu-west-1
https://agcod-v2-eu.amazon.com
(IT, ES, DE, FR, UK, TR, UAE, KSA, PL, NL, SE)
Far East https://agcod-v2-fe-gamma.amazon.com us-west-2
https://agcod-v2-fe.amazon.com
(JP, AU, SG)
CURRENCY
USD for US
EUR for EU
JPY for JP
CAD for CA
AUD for AU
TRY for TR
AED for UAE
*/
// run tests
// print "checkMe Static: <pre>" . print_r(Amazon\AmazonIncentives::checkMeStatic(), true) . "</pre>";
$aws = new Amazon\AmazonIncentives();
// $aws->createGiftCard(100);
print "checkMe: <pre>" . print_r($aws->checkMe(), true) . "</pre>";
print "<hr>";
// we should open log file to collect all creationRequestId/gcId
// so we can test and cancel
// check balance
try {
$aws_test = Amazon\AmazonIncentives::make()->getAvailableFunds();
print "AWS: getAvailableFunds: <pre>" . print_r($aws_test, true) . "</pre><br>";
} catch (Exception $e) {
print "AWS: getAvailableFunds FAILURE [" . $e->getCode() . "]: "
. "<pre>" . print_r(Amazon\AmazonIncentives::decodeExceptionMessage($e->getMessage()), true) . "</pre><br>";
exit;
};
// print "LOG: <pre>" . print_r($aws_test->getLog(), true) . "</pre><br>";
print "<hr>";
// skip early for testing
// exit;
/*
// create card
$value = 1000;
// we must be sure we pass FLOAT there
$aws_test = Amazon\AmazonIncentives::make()->buyGiftCard((float)$value);
print "AWS: buyGiftCard: <pre>" . print_r($aws_test, true) . "</pre><br>";
$creation_request_id = $aws_test->getCreationRequestId();
$gift_card_id = $aws_test->getId();
$claim_code = $aws_test->getClaimCode();
print "AWS creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . "<br>";
print "AWS CLAIM CODE: <b>" . $claim_code . "</b><br>";
print "<hr>";
// cancel card
$aws_test = Amazon\AmazonIncentives::make()->cancelGiftCard($creation_request_id, $gift_card_id);
print "AWS: buyGiftCard: <pre>" . print_r($aws_test, true) . "</pre><br>";
print "<hr>";
*/
// MOCK TEST
$value = 500;
$creation_id = 'F0000';
$aws_test = Amazon\AmazonIncentives::make()->buyGiftCard((float)$value, $creation_id);
$creation_request_id = $aws_test->getCreationRequestId();
$gift_card_id = $aws_test->getId();
$claim_code = $aws_test->getClaimCode();
print "AWS: MOCK: " . $creation_id . ": buyGiftCard: <pre>" . print_r($aws_test, true) . "</pre><br>";
print "AWS creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . "<br>";
print "AWS CLAIM CODE: <b>" . $claim_code . "</b><br>";
print "<hr>";
$creation_id = 'F2005';
try {
$aws_test = Amazon\AmazonIncentives::make()->buyGiftCard((float)$value, $creation_id);
$creation_request_id = $aws_test->getCreationRequestId();
$gift_card_id = $aws_test->getId();
$claim_code = $aws_test->getClaimCode();
print "AWS: MOCK: " . $creation_id . ": buyGiftCard: <pre>" . print_r($aws_test, true) . "</pre><br>";
print "AWS creationRequestId: " . $creation_request_id . ", gcId: " . $gift_card_id . "<br>";
print "AWS CLAIM CODE: <b>" . $claim_code . "</b><br>";
} catch (Exception $e) {
print "AWS: MOCK: " . $creation_id . ": buyGiftCard: FAILURE [" . $e->getCode() . "]: "
. "<pre>" . print_r(Amazon\AmazonIncentives::decodeExceptionMessage($e->getMessage()), true) . "</pre><br>";
}
print "<hr>";
// ... should do all possible important mock tests
// failed card (invalid data)
// double card
// __END__

84
test/read_env_file.php Normal file
View File

@@ -0,0 +1,84 @@
<?php
/**
* parses .env file
*
* Rules for .env file
* variable is any alphanumeric string followed by = on the same line
* content starts with the first non space part
* strings can be contained in "
* strings MUST be contained in " if they are multiline
* if string starts with " it will match until another " is found
* anything AFTER " is ignored
* if there are two variables with the same name only the first is used
* variables are case sensitive
*
* @param string $path Folder to file, default is __DIR__
* @param string $env_file What file to load, default is .env
* @return int -1 other error
* 0 for success full load
* 1 for file loadable, but no data inside
* 2 for file not readable
* 3 for file not found
*/
function readEnvFile(string $path = __DIR__, string $env_file = '.env'): int
{
// default -1;
$status = -1;
$env_file_target = $path . DIRECTORY_SEPARATOR . $env_file;
// this is not a file -> abort
if (!is_file($env_file_target)) {
$status = 3;
return $status;
}
// cannot open file -> abort
if (($fp = fopen($env_file_target, 'r')) === false) {
$status = 2;
return $status;
}
// set to readable but not yet any data loaded
$status = 1;
$block = false;
$var = '';
while ($line = fgets($fp)) {
// main match for variable = value part
if (preg_match("/^\s*([\w_.]+)\s*=\s*((\"?).*)/", $line, $matches)) {
$var = $matches[1];
$value = $matches[2];
$quotes = $matches[3];
// wirte only if env is not set yet, and write only the first time
if (empty($_ENV[$var])) {
if (!empty($quotes)) {
// match greedy for first to last so we move any " if there are
if (preg_match('/^"(.*[^\\\])"/U', $value, $matches)) {
$value = $matches[1];
} else {
// this is a multi line
$block = true;
// first " in string remove
// add removed new line back because this is a multi line
$value = ltrim($value, '"') . PHP_EOL;
}
}
// if block is set, we strip line of slashes
$_ENV[$var] = $block === true ? stripslashes($value) : $value;
// set successful load
$status = 0;
}
} elseif ($block === true) {
// read line until there is a unescaped "
// this also strips everything after the last "
if (preg_match("/(.*[^\\\])\"/", $line, $matches)) {
$block = false;
// strip ending " and EVERYTHING that follows after that
$line = $matches[1];
}
// strip line of slashes
$_ENV[$var] .= stripslashes($line);
}
}
fclose($fp);
return $status;
}
// __END__