diff --git a/README.md b/README.md index 0b064df..dce7b1b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,12 @@ composer require paysgator/paysgator-php ### Configuration -For most requests, you simply need to provide your API Key. +For most requests, you should load your API Key from environment variables for security: + +```bash +# .env file +PAYSgATOR_API_KEY=your_actual_api_key_here +``` ```php require 'vendor/autoload.php'; diff --git a/composer.json b/composer.json index 8c0d054..675de15 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ } ], "require": { - "php": "^7.4 || ^8.0", + "php": "^8.0", "guzzlehttp/guzzle": "^7.8" }, "autoload": { diff --git a/index.php b/index.php index 970f7d0..d8880c4 100644 --- a/index.php +++ b/index.php @@ -8,27 +8,38 @@ 'base_url' => 'https://paysgator.com/api/v1/', // Optional, defaults to production ]); -$apiKey=""; -$walletId=""; +$apiKey = getenv('PAYSGATOR_API_KEY') ?: ''; +$walletId = getenv('PAYSGATOR_WALLET_ID') ?: ''; // Authenticate to get a new token (automatically sets it on the client) -$response = $client->auth()->authenticate($apiKey, $walletId); -$token = $response['accessToken']; - -//Genrating a direct charge - -$directCharge = $client->paymentLinks()->create([ - 'amount' => 0.01, - 'currency' => 'MZN', - 'description' => 'Direct charge', - 'returnUrl' => 'https://mysite.com/return', - 'payment_fields'=>[ - 'phoneNumber'=>'842383770' - ], - 'methods'=>['MPESA'], - 'title'=>'Direct charge', - 'confirm'=>true -]); - -print_r($directCharge); +try { + $response = $client->auth()->authenticate($apiKey, $walletId); + $token = $response['accessToken']; +} catch (\Exception $e) { + echo "Authentication Error: " . $e->getMessage() . "\n"; + exit(1); +} + +// Generating a direct charge +try { + $directCharge = $client->paymentLinks()->create([ + 'amount' => 0.01, + 'currency' => 'MZN', + 'description' => 'Direct charge', + 'returnUrl' => 'https://mysite.com/return', + 'payment_fields'=>[ + 'phoneNumber' => getenv('PAYSGATOR_PHONE_NUMBER') ?: '842383770' + ], + 'methods'=>['MPESA'], + 'title'=>'Direct charge', + 'confirm'=>true + ]); +} catch (\Exception $e) { + echo "Payment Error: " . $e->getMessage() . "\n"; + exit(1); +} + +if (isset($directCharge)) { + print_r($directCharge); +} diff --git a/src/PaysgatorClient.php b/src/PaysgatorClient.php index ae8682b..7c0c4c7 100644 --- a/src/PaysgatorClient.php +++ b/src/PaysgatorClient.php @@ -4,10 +4,6 @@ use GuzzleHttp\Client; use GuzzleHttp\Exception\GuzzleException; -use Paysgator\Resources\Payments; -use Paysgator\Resources\Subscriptions; -use Paysgator\Resources\Transactions; -use Paysgator\Resources\Wallet; class PaysgatorClient { @@ -17,31 +13,28 @@ class PaysgatorClient public function __construct(array $config = []) { + // Load API key from environment variable if not provided + $this->apiKey = $config['api_key'] ?? $_ENV['PAYS_GATOR_API_KEY'] ?? null; + + // Validate API key presence + if (empty($this->apiKey)) { + throw new \InvalidArgumentException('API key is required. Provide it via config or PAYS_GATOR_API_KEY environment variable.'); + } + $this->baseUrl = $config['base_url'] ?? $this->baseUrl; - $this->apiKey = $config['api_key'] ?? null; $guzzleConfig = [ 'base_uri' => $this->baseUrl, 'headers' => [ 'Accept' => 'application/json', 'Content-Type' => 'application/json', + 'X-Api-Key' => $this->apiKey, ], ]; - if ($this->apiKey) { - $guzzleConfig['headers']['X-Api-Key'] = $this->apiKey; - } - $this->client = new Client($guzzleConfig); } - public function setApiKey($key) - { - $this->apiKey = $key; - $config = $this->client->getConfig(); - $config['headers']['X-Api-Key'] = $key; - $this->client = new Client($config); - } public function getHttpClient() { @@ -50,21 +43,21 @@ public function getHttpClient() public function payments() { - return new Payments($this); + return new Payments($this->client); } public function subscriptions() { - return new Subscriptions($this); + return new Subscriptions($this->client); } public function transactions() { - return new Transactions($this); + return new Transactions($this->client); } public function wallet() { - return new Wallet($this); + return new Wallet($this->client); } } diff --git a/src/Resources/Payments.php b/src/Resources/Payments.php index 38ddcbb..491966f 100644 --- a/src/Resources/Payments.php +++ b/src/Resources/Payments.php @@ -3,6 +3,8 @@ namespace Paysgator\Resources; use Paysgator\PaysgatorClient; +use GuzzleHttp\Exception\GuzzleException; +use InvalidArgumentException; class Payments { @@ -19,7 +21,7 @@ public function __construct(PaysgatorClient $client) * @param array $data * @return array */ - public function create(array $data) + public function create(array $data): array { $response = $this->client->getHttpClient()->post('payment/create', [ 'json' => $data, @@ -34,7 +36,7 @@ public function create(array $data) * @param array $data * @return array */ - public function confirm(array $data) + public function confirm(array $data): array { $response = $this->client->getHttpClient()->post('payment/confirm', [ 'json' => $data, diff --git a/src/Resources/Subscriptions.php b/src/Resources/Subscriptions.php index 0ffd103..decb694 100644 --- a/src/Resources/Subscriptions.php +++ b/src/Resources/Subscriptions.php @@ -20,12 +20,29 @@ public function __construct(PaysgatorClient $client) * @param string $action * @return array */ - public function update($id, $action) + public function update(string $id, string $action): array { + if (empty($id)) { + throw new \InvalidArgumentException('Subscription ID cannot be empty'); + } + if (empty($action)) { + throw new \InvalidArgumentException('Action cannot be empty'); + } + $response = $this->client->getHttpClient()->patch("subscriptions/{$id}", [ 'json' => ['action' => $action], ]); - return json_decode($response->getBody()->getContents(), true); + if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) { + throw new \RuntimeException('API request failed with status code: ' . $response->getStatusCode()); + } + + $contents = $response->getBody()->getContents(); + $data = json_decode($contents, true); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \RuntimeException('Failed to decode JSON response: ' . json_last_error_msg()); + } + + return $data; } } diff --git a/src/Resources/Wallet.php b/src/Resources/Wallet.php index f51805b..e99bfdf 100644 --- a/src/Resources/Wallet.php +++ b/src/Resources/Wallet.php @@ -3,6 +3,8 @@ namespace Paysgator\Resources; use Paysgator\PaysgatorClient; +use GuzzleHttp\Exception\GuzzleException; +use Exception; class Wallet { @@ -18,10 +20,24 @@ public function __construct(PaysgatorClient $client) * * @return array */ - public function getBalance() + public function getBalance(): array { - $response = $this->client->getHttpClient()->get('wallet/balance'); + try { + $response = $this->client->getHttpClient()->get('wallet/balance'); + $contents = $response->getBody()->getContents(); + $data = json_decode($contents, true); - return json_decode($response->getBody()->getContents(), true); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new Exception('Invalid JSON response from API: ' . json_last_error_msg()); + } + + if (!is_array($data)) { + throw new Exception('Unexpected response format from wallet balance API'); + } + + return $data; + } catch (GuzzleException $e) { + throw new Exception('Wallet API request failed: ' . $e->getMessage(), $e->getCode(), $e); + } } }