From 28a9e390ccda65541622426f07fc84359332d32d Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Tue, 21 Jan 2025 10:48:41 +0900 Subject: [PATCH] Code clean up with declare strict and php stan level 9 checks add "declare(strict_types=1);" to all pages Add a json handler class to handle that json_decode always returns array and throws error otherwise On failure these will throw the normal JSON encoded error was FAILURE with code "J-" and the number is the json error If 0 then the return was null or some other problem that did not return an array amount is float and not string and checks are done that the returned value is a float various updates for phpdoc array delcarations - curl header is array - the log array is proper declared as array with string key and a list of mixed arrays --- .phan/config.php | 3 +- phpstan.neon | 2 +- phpunit.xml | 2 +- src/AWS/AWS.php | 17 ++++++----- src/AmazonIncentives.php | 26 ++++++++-------- src/Client/Client.php | 12 ++++++-- src/Client/ClientInterface.php | 2 ++ src/Config/Config.php | 5 ++- src/Config/ConfigInterface.php | 2 ++ src/Debug/AmazonDebug.php | 4 ++- src/Exceptions/AmazonErrors.php | 4 ++- src/Handle/Json.php | 42 ++++++++++++++++++++++++++ src/Response/CancelResponse.php | 2 ++ src/Response/CreateBalanceResponse.php | 24 ++++++++++----- src/Response/CreateResponse.php | 2 ++ test/phpUnit/AmazonIncentivesTest.php | 2 +- 16 files changed, 115 insertions(+), 36 deletions(-) create mode 100644 src/Handle/Json.php diff --git a/.phan/config.php b/.phan/config.php index e138932..9679218 100644 --- a/.phan/config.php +++ b/.phan/config.php @@ -26,6 +26,7 @@ // use Phan\Config; return [ + "minimum_target_php_version" => "7.4", // If true, missing properties will be created when // they are first seen. If false, we'll report an // error message. @@ -65,7 +66,7 @@ return [ 'directory_list' => [ // Change this to include the folders you wish to analyze // (and the folders of their dependencies) - '.' + 'src/' // 'www', // To speed up analysis, we recommend going back later and // limiting this to only the vendor/ subdirectories your diff --git a/phpstan.neon b/phpstan.neon index a1ca077..b5185b7 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,7 +2,7 @@ parameters: tmpDir: %currentWorkingDirectory%/tmp/phpstan-codeblocks-amazon-incentives - level: 8 + level: 9 paths: - %currentWorkingDirectory%/src excludePaths: diff --git a/phpunit.xml b/phpunit.xml index 1132d19..b004c68 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,6 +1,6 @@ diff --git a/src/AWS/AWS.php b/src/AWS/AWS.php index 7689f5f..f6340e8 100644 --- a/src/AWS/AWS.php +++ b/src/AWS/AWS.php @@ -1,5 +1,7 @@ getCanonicalRequest($service_operation, $payload); $date_time_string = $this->getTimestamp(); AmazonDebug::writeLog(['call' => __METHOD__]); - $result = json_decode($this->makeRequest( + $result = Json::jsonDecode($this->makeRequest( $payload, $canonical_request, $service_operation, $date_time_string - ), true); + )); return new CreateResponse($result); } @@ -97,12 +100,12 @@ class AWS $canonical_request = $this->getCanonicalRequest($service_operation, $payload); $date_time_string = $this->getTimestamp(); AmazonDebug::writeLog(['call' => __METHOD__]); - $result = json_decode($this->makeRequest( + $result = Json::jsonDecode($this->makeRequest( $payload, $canonical_request, $service_operation, $date_time_string - ), true); + )); return new CancelResponse($result); } @@ -120,12 +123,12 @@ class AWS $canonical_request = $this->getCanonicalRequest($service_operation, $payload); $date_time_string = $this->getTimestamp(); AmazonDebug::writeLog(['call' => __METHOD__]); - $result = json_decode($this->makeRequest( + $result = Json::jsonDecode($this->makeRequest( $payload, $canonical_request, $service_operation, $date_time_string - ), true); + )); return new CreateBalanceResponse($result); } @@ -212,7 +215,7 @@ class AWS * @param string $date_time_string Ymd\THis\Z encoded timestamp, getTimestamp() * @param string $service_target Target service in the agcod string: * Value like com.amazonaws.agcod.. - * @return array Header data as array for curl request + * @return array Header data as array for curl request */ public function buildHeaders( string $payload, diff --git a/src/AmazonIncentives.php b/src/AmazonIncentives.php index af5005d..848956b 100644 --- a/src/AmazonIncentives.php +++ b/src/AmazonIncentives.php @@ -30,12 +30,12 @@ final class AmazonIncentives * @param bool|null $debug Debug flag */ public function __construct( - string $key = null, - string $secret = null, - string $partner = null, - string $endpoint = null, - string $currency = null, - bool $debug = null + ?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 @@ -65,7 +65,7 @@ final class AmazonIncentives * * @throws AmazonErrors */ - public function buyGiftCard(float $value, string $creation_request_id = null): Response\CreateResponse + public function buyGiftCard(float $value, ?string $creation_request_id = null): Response\CreateResponse { return ($this->newAWS())->getCode($value, $creation_request_id); } @@ -109,12 +109,12 @@ final class AmazonIncentives * @return AmazonIncentives self class */ public static function make( - string $key = null, - string $secret = null, - string $partner = null, - string $endpoint = null, - string $currency = null, - bool $debug = null + ?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); } diff --git a/src/Client/Client.php b/src/Client/Client.php index abea497..1fa02b1 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -1,9 +1,12 @@ $headers Headers to be used in the request + * @param array $headers Headers to be used in the request * @param array|string $params Can be nested for arrays and hashes * @return string Result as json string */ @@ -50,7 +53,12 @@ class Client implements ClientInterface $err = curl_errno($handle); AmazonDebug::writeLog(['CURL_REQUEST_RESULT' => $result]); // extract all the error codes from Amazon - $result_ar = json_decode((string)$result, true); + // note we do not care about result errors here, if json decode fails, just set to empty + try { + $result_ar = Json::jsonDecode((string)$result); + } catch (AmazonErrors $e) { + $result_ar = []; + } // if message is 'Rate exceeded', set different error if (($result_ar['message'] ?? '') == 'Rate exceeded') { $error_status = 'RESEND'; diff --git a/src/Client/ClientInterface.php b/src/Client/ClientInterface.php index 8cf67c7..c0c1425 100644 --- a/src/Client/ClientInterface.php +++ b/src/Client/ClientInterface.php @@ -1,5 +1,7 @@ Log data array log id -> array of log entries */ + /** @var array>> Log data array log id -> array of log entries */ private static $log = []; /** @var bool debug flag */ private static $debug = false; diff --git a/src/Exceptions/AmazonErrors.php b/src/Exceptions/AmazonErrors.php index b07612e..aa4baec 100644 --- a/src/Exceptions/AmazonErrors.php +++ b/src/Exceptions/AmazonErrors.php @@ -1,5 +1,7 @@ '', 'code' => '', diff --git a/src/Handle/Json.php b/src/Handle/Json.php new file mode 100644 index 0000000..c8eea53 --- /dev/null +++ b/src/Handle/Json.php @@ -0,0 +1,42 @@ + + * @throws AmazonErrors + */ + public static function jsonDecode(string $json): array + { + $result = json_decode($json, true); + if ( + ($json_last_error = json_last_error()) || + $result === null || + !is_array($result) + ) { + throw AmazonErrors::getError( + 'FAILURE', + 'J-' . $json_last_error, + 'jsonDecoreError', + 'Failed to decode json data', + 0 + ); + } + return $result; + } +} + +// __END__ diff --git a/src/Response/CancelResponse.php b/src/Response/CancelResponse.php index effd540..49b3309 100644 --- a/src/Response/CancelResponse.php +++ b/src/Response/CancelResponse.php @@ -1,5 +1,7 @@ amount; } @@ -98,10 +100,18 @@ class CreateBalanceResponse */ public function parseJsonResponse(array $json_response): self { - if (array_key_exists('amount', $json_response['availableFunds'])) { - $this->amount = $json_response['availableFunds']['amount']; + if ( + is_array($json_response['availableFunds']) && + array_key_exists('amount', $json_response['availableFunds']) && + is_numeric($json_response['availableFunds']['amount']) + ) { + $this->amount = (float)$json_response['availableFunds']['amount']; } - if (array_key_exists('currencyCode', $json_response['availableFunds'])) { + if ( + is_array($json_response['availableFunds']) && + array_key_exists('currencyCode', $json_response['availableFunds']) && + is_string($json_response['availableFunds']['currencyCode']) + ) { $this->currency = $json_response['availableFunds']['currencyCode']; } // SUCCESS, FAILURE, RESEND diff --git a/src/Response/CreateResponse.php b/src/Response/CreateResponse.php index f22813e..f85029c 100644 --- a/src/Response/CreateResponse.php +++ b/src/Response/CreateResponse.php @@ -1,5 +1,7 @@ assertIsNumeric( $funds->getAmount(), - 'Assert amoount is numerc' + 'Assert amoount is numeric' ); // USD, JPY, etc $this->assertIsString(