121 lines
4.5 KiB
PHP
121 lines
4.5 KiB
PHP
<?php
|
|
|
|
class IkhokhaClient {
|
|
private string $appId;
|
|
private string $appSecret;
|
|
private string $apiUrl;
|
|
|
|
public function __construct() {
|
|
// Try getenv first, then fallback to $_ENV if available
|
|
$this->appId = getenv('IKHOKHA_APP_ID') ?: ($_ENV['IKHOKHA_APP_ID'] ?? '');
|
|
$this->appSecret = getenv('IKHOKHA_APP_SECRET') ?: ($_ENV['IKHOKHA_APP_SECRET'] ?? '');
|
|
$this->apiUrl = getenv('IKHOKHA_API_URL') ?: ($_ENV['IKHOKHA_API_URL'] ?? '');
|
|
}
|
|
|
|
/**
|
|
* Make a request to the iKhokha API. Signs the payload per API docs.
|
|
* $endpoint should be the path portion starting with '/public-api/...'
|
|
*/
|
|
private function request(string $endpoint, array $data, string $method = 'POST') {
|
|
// Validate apiUrl
|
|
if (empty($this->apiUrl)) {
|
|
return ['error' => true, 'errno' => 3, 'message' => 'IKHOKHA_API_URL is not configured in environment'];
|
|
}
|
|
|
|
// If the configured API URL already contains the endpoint path, use it as-is.
|
|
if ((function_exists('str_ends_with') && str_ends_with($this->apiUrl, $endpoint)) ||
|
|
(substr_compare($this->apiUrl, $endpoint, -strlen($endpoint)) === 0)) {
|
|
$url = $this->apiUrl;
|
|
} else {
|
|
$url = rtrim($this->apiUrl, '/') . $endpoint;
|
|
}
|
|
$body = json_encode($data);
|
|
|
|
// Build payload to sign: path + body and apply escape rules per iKhokha docs
|
|
$parsed = parse_url($url);
|
|
$path = $parsed['path'] ?? $endpoint;
|
|
$payloadToSign = $path . $body;
|
|
|
|
// Escape function from iKhokha example
|
|
$escapeString = function ($str) {
|
|
$escaped = preg_replace(['/[\\\"\'\"]/u', '/\x00/'], ['\\\\$0', '\\0'], (string)$str);
|
|
$cleaned = str_replace('\/', '/', $escaped);
|
|
return $cleaned;
|
|
};
|
|
|
|
$escapedPayload = $escapeString($payloadToSign);
|
|
$signature = hash_hmac('sha256', $escapedPayload, $this->appSecret);
|
|
|
|
$ch = curl_init($url);
|
|
|
|
$headers = [
|
|
'Content-Type: application/json',
|
|
"IK-APPID: {$this->appId}",
|
|
"IK-SIGN: {$signature}"
|
|
];
|
|
|
|
// Optional debug logging to logs/ikhokha.log when IKHOKHA_DEBUG_LOG is true
|
|
$debugLog = getenv('IKHOKHA_DEBUG_LOG') ?: ($_ENV['IKHOKHA_DEBUG_LOG'] ?? null);
|
|
if ($debugLog) {
|
|
$logPath = dirname(__DIR__) . '/logs/ikhokha.log';
|
|
$logEntry = [
|
|
'time' => date('c'),
|
|
'url' => $url,
|
|
'headers' => $headers,
|
|
'body' => $data,
|
|
'signature' => $signature
|
|
];
|
|
@file_put_contents($logPath, json_encode(['request' => $logEntry]) . PHP_EOL, FILE_APPEND | LOCK_EX);
|
|
}
|
|
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
|
|
|
if (strtoupper($method) === 'POST') {
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
|
|
} else {
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
|
}
|
|
|
|
$response = curl_exec($ch);
|
|
$errno = curl_errno($ch);
|
|
$error = curl_error($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
// Log response if debug enabled
|
|
if (!empty($debugLog)) {
|
|
$logPath = dirname(__DIR__) . '/logs/ikhokha.log';
|
|
$respEntry = [
|
|
'time' => date('c'),
|
|
'http_code' => $httpCode,
|
|
'errno' => $errno,
|
|
'error' => $error,
|
|
'response' => $response
|
|
];
|
|
@file_put_contents($logPath, json_encode(['response' => $respEntry]) . PHP_EOL, FILE_APPEND | LOCK_EX);
|
|
}
|
|
|
|
if ($response === false) {
|
|
return ['error' => true, 'message' => $error, 'errno' => $errno];
|
|
}
|
|
|
|
return json_decode($response, true);
|
|
}
|
|
|
|
/**
|
|
* Create a payment link using the iKhokha create payment endpoint.
|
|
* $body must match iKhokha request schema (amount in smallest unit, urls, externalTransactionID, etc.)
|
|
*/
|
|
public function createPaymentLink(array $body) {
|
|
return $this->request('/public-api/v1/api/payment', $body, 'POST');
|
|
}
|
|
|
|
public function getPaymentStatus($paymentId) {
|
|
// Use the GET status endpoint
|
|
$endpoint = '/public-api/v1/api/getStatus/' . urlencode($paymentId);
|
|
return $this->request($endpoint, [], 'GET');
|
|
}
|
|
}
|