2 Commits

Author SHA1 Message Date
twotalesanimation
35c177b11d htacces update 2025-12-15 15:52:25 +02:00
twotalesanimation
acd7f563b1 added transaction table, fixed signature auth. Monitor for bugs before rmoving bypass 2025-12-15 15:51:11 +02:00
9 changed files with 583 additions and 203 deletions

View File

@@ -94,7 +94,7 @@ RewriteRule ^admin_course_bookings$ src/admin/admin_course_bookings.php [L]
RewriteRule ^admin_camp_bookings$ src/admin/admin_camp_bookings.php [L]
RewriteRule ^admin_trip_bookings$ src/admin/admin_trip_bookings.php [L]
RewriteRule ^admin_visitors$ src/admin/admin_visitors.php [L]
RewriteRule ^admin_efts$ src/admin/admin_efts.php [L]
RewriteRule ^admin_transactions$ src/admin/admin_transactions.php [L]
RewriteRule ^admin_trips$ src/admin/admin_trips.php [L]
RewriteRule ^manage_events$ src/admin/manage_events.php [L]
RewriteRule ^manage_trips$ src/admin/manage_trips.php [L]
@@ -156,7 +156,7 @@ RewriteRule ^autosave$ src/processors/blog/autosave.php [L]
</IfModule>
php_flag display_errors On
php_flag display_errors Off
# php_value error_reporting -1
RedirectMatch 403 ^/\.well-known
Options -Indexes

View File

@@ -288,8 +288,8 @@ if ($headerStyle === 'light') {
<li><a href="admin_trips">Manage Trips</a></li>
<li><a href="admin_trip_bookings">Trip Bookings</a></li>
<li><a href="admin_course_bookings">Course Bookings</a></li>
<li><a href="admin_efts">EFT Payments</a></li>
<li><a href="process_payments">Process Payments</a></li>
<li><a href="admin_transactions">iKhokha Payment History</a></li>
<!-- <li><a href="process_payments">Process Payments</a></li> -->
<?php if ($role === 'superadmin') { ?>
<li><a href="admin_visitors">Visitor Log</a></li>
<?php } ?>

View File

@@ -1,48 +1,122 @@
[2025-12-14 16:27:25] Testing Log Entry at 2025-12-14 16:27:25
[2025-12-14 16:28:03] Testing Log Entry at 2025-12-14 16:28:03
[2025-12-14 16:28:18] Testing Log Entry at 2025-12-14 16:28:18
[2025-12-14 18:30:36] --- iKhokha WEBHOOK DEBUG ---
[2025-12-14 18:30:36] PATH: /src/api/ikhokha_webhook.php
[2025-12-14 18:30:36] RAW BODY: {"paylinkID":"cwm225jy497j0qc","status":"SUCCESS","externalTransactionID":"693ee604c8e38","responseCode":"00","text":null}
[2025-12-14 18:30:36] IK-SIGN: 3a2b8c9da4f1aff63c011adec10552450c5b6605f587e82ab1272914715fd4cf
[2025-12-14 18:30:36] iKhokha webhook: signature mismatch
[2025-12-14 18:30:36] EXPECTED SIGN: f8356ee6b609e9bd44221fa71851b06171bbb7523c52dca4bde605e3bd93f654
[2025-12-14 18:30:37] --- iKhokha WEBHOOK DEBUG ---
[2025-12-14 18:30:37] PATH: /src/api/ikhokha_webhook.php
[2025-12-14 18:30:37] RAW BODY: {"paylinkID":"cwm225jy497j0qc","status":"SUCCESS","externalTransactionID":"693ee604c8e38","responseCode":"00","text":null}
[2025-12-14 18:30:37] IK-SIGN: 3a2b8c9da4f1aff63c011adec10552450c5b6605f587e82ab1272914715fd4cf
[2025-12-14 18:30:37] iKhokha webhook: signature mismatch
[2025-12-14 18:30:37] EXPECTED SIGN: f8356ee6b609e9bd44221fa71851b06171bbb7523c52dca4bde605e3bd93f654
[2025-12-14 18:36:19] --- iKhokha WEBHOOK DEBUG ---
[2025-12-14 18:36:19] PATH: /api/ikhokha_webhook.php
[2025-12-14 18:36:19] RAW BODY: {"paylinkID":"xx6225jyhx6x5n1","status":"SUCCESS","externalTransactionID":"693ee75cec963","responseCode":"00","text":null}
[2025-12-14 18:36:19] IK-SIGN: 8fb11ceb8ea6b2cd6fec1773719927889f02764b0f04ad3c8543edbc9f74cf43
[2025-12-14 18:36:19] iKhokha webhook: signature mismatch
[2025-12-14 18:36:19] EXPECTED SIGN: 7a594957e7dc8775a6f9e1f8e3a1292f4dcd10268facaec57735f937b1cd9949
[2025-12-14 18:36:19] --- iKhokha WEBHOOK DEBUG ---
[2025-12-14 18:36:19] PATH: /api/ikhokha_webhook.php
[2025-12-14 18:36:19] RAW BODY: {"paylinkID":"xx6225jyhx6x5n1","status":"SUCCESS","externalTransactionID":"693ee75cec963","responseCode":"00","text":null}
[2025-12-14 18:36:19] IK-SIGN: 8fb11ceb8ea6b2cd6fec1773719927889f02764b0f04ad3c8543edbc9f74cf43
[2025-12-14 18:36:19] iKhokha webhook: signature mismatch
[2025-12-14 18:36:19] EXPECTED SIGN: 7a594957e7dc8775a6f9e1f8e3a1292f4dcd10268facaec57735f937b1cd9949
[2025-12-14 18:55:49] --- iKhokha WEBHOOK DEBUG ---
[2025-12-14 18:55:49] RAW BODY: {"paylinkID":"433225jzs9rvk5n","status":"SUCCESS","externalTransactionID":"693eebf1a9f75","responseCode":"00","text":null}
[2025-12-14 18:55:49] IK-SIGN: 5cb01840f3516c964bdffc34cb1da41130bd668deffc2e4ea5a9f4cbb89b9807
[2025-12-14 18:55:49] SIGN BASE STRING: | CONTEXT: https://beta.4wdcsa.co.za/src/api/ikhokha_webhook.php{"paylinkID":"433225jzs9rvk5n","status":"SUCCESS","externalTransactionID":"693eebf1a9f75","responseCode":"00","text":null}
[2025-12-14 18:55:49] iKhokha webhook: signature mismatch
[2025-12-14 18:55:49] EXPECTED SIGN: 75c491d05ac5006b3ad4fcec20c870e860a66ea03ed5a3e8900d6e29cd601445
[2025-12-14 18:55:49] RECEIVED SIGN: 5cb01840f3516c964bdffc34cb1da41130bd668deffc2e4ea5a9f4cbb89b9807
[2025-12-14 18:55:49] --- iKhokha WEBHOOK DEBUG ---
[2025-12-14 18:55:49] RAW BODY: {"paylinkID":"433225jzs9rvk5n","status":"SUCCESS","externalTransactionID":"693eebf1a9f75","responseCode":"00","text":null}
[2025-12-14 18:55:49] IK-SIGN: 5cb01840f3516c964bdffc34cb1da41130bd668deffc2e4ea5a9f4cbb89b9807
[2025-12-14 18:55:49] SIGN BASE STRING: | CONTEXT: https://beta.4wdcsa.co.za/src/api/ikhokha_webhook.php{"paylinkID":"433225jzs9rvk5n","status":"SUCCESS","externalTransactionID":"693eebf1a9f75","responseCode":"00","text":null}
[2025-12-14 18:55:49] iKhokha webhook: signature mismatch
[2025-12-14 18:55:49] EXPECTED SIGN: 75c491d05ac5006b3ad4fcec20c870e860a66ea03ed5a3e8900d6e29cd601445
[2025-12-14 18:55:49] RECEIVED SIGN: 5cb01840f3516c964bdffc34cb1da41130bd668deffc2e4ea5a9f4cbb89b9807
[2025-12-14 20:15:55] --- iKhokha WEBHOOK DEBUG ---
[2025-12-14 20:15:55] RAW BODY: {"paylinkID":"ys5225k4z56x0mm","status":"SUCCESS","externalTransactionID":"693efeaca71a9","responseCode":"00","text":null}
[2025-12-14 20:15:55] IK-SIGN: bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557
[2025-12-14 20:15:55] ⚠️ IKHOKHA SIGNATURE CHECK BYPASSED
[2025-12-14 20:15:55] Parsed externalTransactionID: 693efeaca71a9
[2025-12-14 20:15:55] Parsed providerPaymentId: ys5225k4z56x0mm
[2025-12-14 20:15:55] Parsed providerStatus: SUCCESS
[2025-12-15 12:32:19] AJAX BLOCK ENTERED
[2025-12-15 12:32:19] startDate=2025-10-16
[2025-12-15 12:32:19] endDate=2025-12-15
[2025-12-15 12:32:19] APP ID present: YES
[2025-12-15 12:32:19] APP SECRET present: YES
[2025-12-15 12:32:19] PAYLOAD: https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:32:19] IK-SIGN: ced35ab201ad54e8f8b5935d2778c4ec7e75af0102d40d9c4515f8118ca8b5dd
[2025-12-15 12:32:19] CURL HTTP CODE: 422
[2025-12-15 12:32:19] CURL ERROR: none
[2025-12-15 12:32:19] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:33:31] AJAX BLOCK ENTERED
[2025-12-15 12:33:31] startDate=2025-10-16
[2025-12-15 12:33:31] endDate=2025-12-15
[2025-12-15 12:33:31] APP ID present: YES
[2025-12-15 12:33:31] APP SECRET present: YES
[2025-12-15 12:33:31] IKHOKHA PAYLOAD (FULL URL): https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:33:31] IKHOKHA IK-SIGN: ced35ab201ad54e8f8b5935d2778c4ec7e75af0102d40d9c4515f8118ca8b5dd
[2025-12-15 12:33:31] CURL HTTP CODE: 422
[2025-12-15 12:33:31] CURL ERROR: none
[2025-12-15 12:33:31] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:33:59] AJAX BLOCK ENTERED
[2025-12-15 12:33:59] startDate=2025-10-16
[2025-12-15 12:33:59] endDate=2025-12-15
[2025-12-15 12:33:59] APP ID present: YES
[2025-12-15 12:33:59] APP SECRET present: YES
[2025-12-15 12:33:59] IKHOKHA PAYLOAD (FULL URL): https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:33:59] IKHOKHA IK-SIGN: ced35ab201ad54e8f8b5935d2778c4ec7e75af0102d40d9c4515f8118ca8b5dd
[2025-12-15 12:34:00] CURL HTTP CODE: 422
[2025-12-15 12:34:00] CURL ERROR: none
[2025-12-15 12:34:00] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:37:06] AJAX BLOCK ENTERED
[2025-12-15 12:37:06] startDate=2025-10-16
[2025-12-15 12:37:06] endDate=2025-12-15
[2025-12-15 12:37:06] APP ID present: YES
[2025-12-15 12:37:06] APP SECRET present: YES
[2025-12-15 12:37:06] IKHOKHA ENDPOINT (REQUEST): https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:37:06] IKHOKHA PAYLOAD (SIGNED): https://api.ikhokha.com/public-api/v1/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:37:06] IKHOKHA IK-SIGN: 418e48921e566e5804b58f65e1ca4a28dba4d69de3611d1cf7f90f865490f42d
[2025-12-15 12:37:06] CURL HTTP CODE: 422
[2025-12-15 12:37:06] CURL ERROR: none
[2025-12-15 12:37:06] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:56:21] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:56:21] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:56:37] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:56:37] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:57:04] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:57:04] 13e6e02a7ccad937bc27b31038373d48d8ba2700a7ba8d9a7a2e4f9b07378692 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:57:30] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:57:30] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:57:32] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:57:32] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:57:34] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:57:34] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:58:00] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA Endpoint
[2025-12-15 12:58:00] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:58:00] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:58:04] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA Endpoint
[2025-12-15 12:58:04] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:58:04] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:58:17] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 12:58:17] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:58:17] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 12:58:48] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 12:58:48] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 12:58:48] 13e6e02a7ccad937bc27b31038373d48d8ba2700a7ba8d9a7a2e4f9b07378692 | CONTEXT: IKHOKHA Signature
[2025-12-15 13:00:13] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 13:00:13] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:00:13] 13e6e02a7ccad937bc27b31038373d48d8ba2700a7ba8d9a7a2e4f9b07378692 | CONTEXT: IKHOKHA Signature
[2025-12-15 13:00:29] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 13:00:29] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:00:29] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 13:03:10] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 13:03:10] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:03:10] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 13:03:19] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 13:03:19] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:03:19] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 13:05:51] bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557 | CONTEXT: IKHOKHA Signature from Webhook
[2025-12-15 13:05:51] "{\"paylinkID\":\"ys5225k4z56x0mm\",\"status\":\"SUCCESS\",\"externalTransactionID\":\"693efeaca71a9\",\"responseCode\":\"00\",\"text\":null}" | CONTEXT: IKHOKHA Stringified Body
[2025-12-15 13:06:29] bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557 | CONTEXT: IKHOKHA Signature from Webhook
[2025-12-15 13:06:29] "{\"paylinkID\":\"ys5225k4z56x0mm\",\"status\":\"SUCCESS\",\"externalTransactionID\":\"693efeaca71a9\",\"responseCode\":\"00\",\"text\":null}" | CONTEXT: IKHOKHA Stringified Body
[2025-12-15 13:06:29] /src/api/ikhokha_webhook.php\"{\\"paylinkID\\":\\"ys5225k4z56x0mm\\",\\"status\\":\\"SUCCESS\\",\\"externalTransactionID\\":\\"693efeaca71a9\\",\\"responseCode\\":\\"00\\",\\"text\\":null}\" | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:06:29] 43a6a56af31c276174953e115eb41402f12969fedab5b673dd34327cd7135a75 | CONTEXT: IKHOKHA Generated Signature
[2025-12-15 13:06:42] bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557 | CONTEXT: IKHOKHA Signature from Webhook
[2025-12-15 13:06:42] {"paylinkID":"ys5225k4z56x0mm","status":"SUCCESS","externalTransactionID":"693efeaca71a9","responseCode":"00","text":null} | CONTEXT: IKHOKHA Stringified Body
[2025-12-15 13:06:42] /src/api/ikhokha_webhook.php\"{\\"paylinkID\\":\\"ys5225k4z56x0mm\\",\\"status\\":\\"SUCCESS\\",\\"externalTransactionID\\":\\"693efeaca71a9\\",\\"responseCode\\":\\"00\\",\\"text\\":null}\" | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:06:42] 43a6a56af31c276174953e115eb41402f12969fedab5b673dd34327cd7135a75 | CONTEXT: IKHOKHA Generated Signature
[2025-12-15 13:07:09] bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557 | CONTEXT: IKHOKHA Signature from Webhook
[2025-12-15 13:07:09] {"paylinkID":"ys5225k4z56x0mm","status":"SUCCESS","externalTransactionID":"693efeaca71a9","responseCode":"00","text":null} | CONTEXT: IKHOKHA Stringified Body
[2025-12-15 13:07:09] /src/api/ikhokha_webhook.php\"{\\"paylinkID\\":\\"ys5225k4z56x0mm\\",\\"status\\":\\"SUCCESS\\",\\"externalTransactionID\\":\\"693efeaca71a9\\",\\"responseCode\\":\\"00\\",\\"text\\":null}\" | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:07:09] 43a6a56af31c276174953e115eb41402f12969fedab5b673dd34327cd7135a75 | CONTEXT: IKHOKHA Generated Signature
[2025-12-15 13:09:39] bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557 | CONTEXT: IKHOKHA Signature from Webhook
[2025-12-15 13:19:12] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 13:19:12] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:19:12] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 13:36:28] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 13:36:28] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:36:28] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 13:36:54] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 13:36:54] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 13:36:54] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 15:41:25] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 15:41:25] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 15:41:25] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 15:43:53] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 15:43:53] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 15:43:53] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 15:44:29] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 15:44:29] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 15:44:29] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 15:46:02] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 15:46:02] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 15:46:02] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 15:47:46] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 15:47:46] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 15:47:46] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 15:47:51] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 15:47:51] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 15:47:51] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature
[2025-12-15 15:48:43] IKFLESZTKFM4HWWS76131L8HK9BYF96P | CONTEXT: IKHOKHA App ID
[2025-12-15 15:48:43] /public-api/v1/api/payments/history | CONTEXT: IKHOKHA Payload to Sign
[2025-12-15 15:48:43] b3b592829090d2cfd0912ccbdec73db18742088d01a2d2bee9f0eacdf37a6b26 | CONTEXT: IKHOKHA Signature

View File

@@ -0,0 +1,56 @@
[2025-12-15 12:28:42] FILE HIT
[2025-12-15 12:28:42] AJAX BLOCK ENTERED
[2025-12-15 12:28:42] startDate=2025-10-16
[2025-12-15 12:28:42] endDate=2025-12-15
[2025-12-15 12:28:42] APP ID present: YES
[2025-12-15 12:28:42] APP SECRET present: YES
[2025-12-15 12:28:42] PAYLOAD: /public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:28:42] IK-SIGN: 3d610c60c8306cd1d5c99b2639f0e810594f8ffb9306a98d703f691173dab47d
[2025-12-15 12:28:44] CURL HTTP CODE: 422
[2025-12-15 12:28:44] CURL ERROR: none
[2025-12-15 12:28:44] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:28:51] FILE HIT
[2025-12-15 12:28:51] AJAX BLOCK ENTERED
[2025-12-15 12:28:51] startDate=2025-10-16
[2025-12-15 12:28:51] endDate=2025-12-15
[2025-12-15 12:28:51] APP ID present: YES
[2025-12-15 12:28:51] APP SECRET present: YES
[2025-12-15 12:28:51] PAYLOAD: /public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:28:51] IK-SIGN: 3d610c60c8306cd1d5c99b2639f0e810594f8ffb9306a98d703f691173dab47d
[2025-12-15 12:28:51] CURL HTTP CODE: 422
[2025-12-15 12:28:51] CURL ERROR: none
[2025-12-15 12:28:51] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:30:54] FILE HIT
[2025-12-15 12:30:54] AJAX BLOCK ENTERED
[2025-12-15 12:30:54] startDate=2025-10-16
[2025-12-15 12:30:54] endDate=2025-12-15
[2025-12-15 12:30:54] APP ID present: YES
[2025-12-15 12:30:54] APP SECRET present: YES
[2025-12-15 12:30:54] PAYLOAD: https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:30:54] IK-SIGN: ced35ab201ad54e8f8b5935d2778c4ec7e75af0102d40d9c4515f8118ca8b5dd
[2025-12-15 12:30:55] CURL HTTP CODE: 422
[2025-12-15 12:30:55] CURL ERROR: none
[2025-12-15 12:30:55] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:31:13] FILE HIT
[2025-12-15 12:31:13] AJAX BLOCK ENTERED
[2025-12-15 12:31:13] startDate=2025-10-16
[2025-12-15 12:31:13] endDate=2025-12-15
[2025-12-15 12:31:13] APP ID present: YES
[2025-12-15 12:31:13] APP SECRET present: YES
[2025-12-15 12:31:13] PAYLOAD: https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=2025-10-16&endDate=2025-12-15
[2025-12-15 12:31:13] IK-SIGN: ced35ab201ad54e8f8b5935d2778c4ec7e75af0102d40d9c4515f8118ca8b5dd
[2025-12-15 12:31:13] CURL HTTP CODE: 422
[2025-12-15 12:31:13] CURL ERROR: none
[2025-12-15 12:31:13] RAW RESPONSE: {"error":"Invalid Signature"}
[2025-12-15 12:31:21] FILE HIT
[2025-12-15 12:31:47] FILE HIT
[2025-12-15 12:31:47] FILE HIT
[2025-12-15 12:31:58] FILE HIT
[2025-12-15 12:32:18] FILE HIT
[2025-12-15 12:32:19] FILE HIT
[2025-12-15 12:33:30] FILE HIT
[2025-12-15 12:33:31] FILE HIT
[2025-12-15 12:33:59] FILE HIT
[2025-12-15 12:33:59] FILE HIT
[2025-12-15 12:37:05] FILE HIT
[2025-12-15 12:37:06] FILE HIT

View File

@@ -0,0 +1,248 @@
<?php
$headerStyle = 'light';
$rootPath = dirname(dirname(__DIR__));
include_once($rootPath . '/header.php');
checkAdmin();
?>
<style>
table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
margin: 10px 0;
}
thead th {
cursor: pointer;
text-align: left;
padding: 10px;
font-weight: bold;
position: relative;
}
thead th::after {
content: '\25B2';
/* Up arrow */
font-size: 0.8em;
position: absolute;
right: 10px;
opacity: 0;
transition: opacity 0.2s;
}
thead th.asc::after {
content: '\25B2';
/* Up arrow */
opacity: 1;
}
thead th.desc::after {
content: '\25BC';
/* Down arrow */
opacity: 1;
}
tbody tr:nth-child(odd) {
background-color: transparent;
}
tbody tr:nth-child(even) {
background-color: rgb(255, 255, 255);
border-radius: 10px;
}
tbody td {
padding: 5px;
}
tbody tr:nth-child(even) td:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
tbody tr:nth-child(even) td:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.filter-input {
width: 100%;
padding: 5px;
/* margin-bottom: 20px; */
font-size: 16px;
background-color: rgb(255, 255, 255);
border-radius: 25px;
}
.infobox {
color: #484848;
background: #f9f9f7;
border: 1px solid #d8d8d8;
border-radius: 10px;
margin-top: 15px;
margin-bottom: 15px;
}
</style>
<script>
document.addEventListener("DOMContentLoaded", function() {
const table = document.querySelector("table");
const headers = table.querySelectorAll("thead th");
const rows = Array.from(table.querySelectorAll("tbody tr"));
const filterInput = document.getElementById("filterInput");
headers.forEach((header, index) => {
header.addEventListener("click", () => {
const sortedRows = rows.sort((a, b) => {
const aText = a.cells[index].textContent.trim().toLowerCase();
const bText = b.cells[index].textContent.trim().toLowerCase();
if (aText < bText) return -1;
if (aText > bText) return 1;
return 0;
});
if (header.classList.contains("asc")) {
header.classList.remove("asc");
header.classList.add("desc");
sortedRows.reverse();
} else {
headers.forEach(h => h.classList.remove("asc", "desc"));
header.classList.add("asc");
}
const tbody = table.querySelector("tbody");
tbody.innerHTML = "";
sortedRows.forEach(row => tbody.appendChild(row));
});
});
filterInput.addEventListener("input", function() {
const filterValue = filterInput.value.trim().toLowerCase();
rows.forEach(row => {
const rowText = row.textContent.trim().toLowerCase();
row.style.display = rowText.includes(filterValue) ? "" : "none";
});
});
});
</script>
<!-- Page Banner Start -->
<?php
$bannerFolder = 'assets/images/banners/';
$bannerImages = glob($bannerFolder . '*.{jpg,jpeg,png,webp}', GLOB_BRACE);
$randomBanner = 'assets/images/base4/camping.jpg'; // default fallback
if (!empty($bannerImages)) {
$randomBanner = $bannerImages[array_rand($bannerImages)];
}
?>
<section class="page-banner-area pt-50 pb-35 rel z-1 bgs-cover" style="background-image: url('<?php echo $randomBanner; ?>');">
<div class="banner-overlay"></div>
<div class="container">
<div class="banner-inner text-white mb-50">
<h2 class="page-title mb-10" data-aos="fade-left" data-aos-duration="1500" data-aos-offset="50">iKhokha Payments</h2>
<nav aria-label="breadcrumb">
<ol class="breadcrumb justify-content-center mb-20" data-aos="fade-right" data-aos-delay="200" data-aos-duration="1500" data-aos-offset="50">
<li class="breadcrumb-item"><a href="index.php">Home</a></li>
<li class="breadcrumb-item active">iKhokha Payments</li>
</ol>
</nav>
</div>
</div>
</section>
<!-- Tour List Area start -->
<section class="tour-list-page py-10 rel z-1">
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class='infobox' data-aos='fade-up' data-aos-duration='1500' data-aos-offset='50'>
<div style='padding:10px;'>
<?php
// Fetch transactions from iKhokha API instead of DB
$startDate = isset($_GET['start']) ? $_GET['start'] : date('Y-m-d', strtotime('-30 days'));
$endDate = isset($_GET['end']) ? $_GET['end'] : date('Y-m-d');
// getIkhokhaTransactionHistory should return JSON (string) or an array
$raw = getIkhokhaTransactionHistory($startDate, $endDate);
$transactions = [];
if (is_string($raw)) {
$transactions = json_decode($raw, true);
} elseif (is_array($raw)) {
$transactions = $raw;
}
if (!empty($transactions)) {
echo '<input id="filterInput" type="text" class="filter-input" placeholder="Filter results...">';
echo '<table>
<thead>
<tr>
<th>Date</th>
<th>ID</th>
<th>PaylinkID</th>
<th>Description</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>';
$printed = false;
foreach ($transactions as $row) {
$createdAt = isset($row['createdAt']) ? htmlspecialchars($row['createdAt']) : '';
// prefer externalTransactionID when available, fallback to paylinkID
$txId = isset($row['externalTransactionID']) ? $row['externalTransactionID'] : (isset($row['paylinkID']) ? $row['paylinkID'] : '');
$ikhokhaTxId = isset($row['paylinkID']) ? $row['paylinkID'] : '';
$description = isset($row['description']) ? $row['description'] : '';
$amount = isset($row['amount']) ? $row['amount'] : '';
$status = isset($row['status']) ? $row['status'] : '';
// Skip unpaid transactions
if (strcasecmp($status, 'UNPAID') === 0) {
continue;
}
echo "<tr>
<td>" . htmlspecialchars($createdAt) . "</td>
<td>" . htmlspecialchars($txId) . "</td>
<td>" . htmlspecialchars($ikhokhaTxId) . "</td>
<td>" . htmlspecialchars($description) . "</td>
<td>R " . htmlspecialchars($amount/100) . ".00</td>
<td>" . htmlspecialchars($status) . "</td>
</tr>";
$printed = true;
}
if (!$printed) {
echo '<tr><td colspan="6">No records found</td></tr>';
}
} else {
echo '<input id="filterInput" type="text" class="filter-input" placeholder="Filter results...">';
echo '<table>
<thead>
<tr>
<th>Date</th>
<th>ID</th>
<th>Description</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody>';
echo '<tr><td colspan="5">No records found</td></tr>';
} ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Tour List Area end -->
<?php include_once($rootPath . '/components/insta_footer.php'); ?>

View File

@@ -7,80 +7,102 @@ require_once($rootPath . "/src/config/functions.php");
/**
* ==========================================================
* Read raw request and headers (DO NOT MODIFY RAW BODY)
* JS-equivalent escaping (matches iKhokha docs exactly)
* ==========================================================
*/
function jsStringEscape(string $str): string
{
$str = preg_replace('/([\\\\\"\'])/', '\\\\$1', $str);
$str = str_replace("\0", "\\0", $str);
return $str;
}
function createPayloadToSign(string $path, string $body): string
{
return jsStringEscape($path . $body);
}
/**
* ==========================================================
* Read raw request body (DO NOT MODIFY)
* ==========================================================
*/
$raw = file_get_contents('php://input');
if ($raw === false) {
if ($raw === false || $raw === '') {
http_response_code(400);
progress_log('iKhokha webhook: unable to read raw input');
progress_log('iKhokha webhook: empty body');
exit('No body');
}
/**
* ==========================================================
* Read headers
* ==========================================================
*/
$headers = function_exists('getallheaders') ? getallheaders() : [];
$headers = array_change_key_case($headers, CASE_LOWER);
$ikSign = $headers['ik-sign'] ?? null;
$ikAppId = $headers['ik-appid'] ?? null;
/**
* ==========================================================
* Basic header presence check
* ==========================================================
*/
if (empty($ikSign) || empty($ikAppId)) {
if (!$ikSign || !$ikAppId) {
http_response_code(400);
progress_log('iKhokha webhook: missing IK-SIGN or IK-APPID');
progress_log('iKhokha webhook: missing headers');
exit('Missing headers');
}
/**
* ==========================================================
* Signature verification
* HMAC_SHA256( path + raw_body, app_secret )
* Signature verification (JS-equivalent)
* ==========================================================
*/
$secret = $_ENV['IKHOKHA_APP_SECRET'] ?? null;
$callbackUrl = $_ENV['IKHOKHA_CALLBACK_URL'] ?? null;
$bypass = ($_ENV['IKHOKHA_BYPASS_SIGNATURE'] ?? 'false') === 'true';
if (empty($secret)) {
if (!$secret || !$callbackUrl) {
http_response_code(500);
progress_log('iKhokha webhook: app secret not configured');
exit('Server misconfigured');
}
// Debug logging (disable once stable)
progress_log('--- iKhokha WEBHOOK DEBUG ---');
progress_log('RAW BODY: ' . $raw);
progress_log('IK-SIGN: ' . $ikSign);
$callbackUrl = $_ENV['IKHOKHA_CALLBACK_URL'] ?? null;
$bypass = ($_ENV['IKHOKHA_BYPASS_SIGNATURE'] ?? 'false') === 'true';
if (!$bypass) {
if (empty($callbackUrl)) {
http_response_code(500);
progress_log('iKhokha webhook: callback URL not configured');
exit('Server misconfigured');
// Decode body so we can remove `text`
$bodyArray = json_decode($raw, true);
if (!is_array($bodyArray)) {
http_response_code(400);
exit('Invalid JSON');
}
$expected = hash_hmac(
'sha256',
$callbackUrl . $raw,
$_ENV['IKHOKHA_APP_SECRET']
);
// iKhokha JS deletes `text`
unset($bodyArray['text']);
// JS-style JSON (no escaped slashes)
$jsonBody = json_encode($bodyArray, JSON_UNESCAPED_SLASHES);
// Now sign the SAME payload JS signs
$payloadToSign = createPayloadToSign($callbackUrl, $jsonBody);
$expected = generateSignature($payloadToSign, $secret);
progress_log('JS PAYLOAD: ' . $payloadToSign);
progress_log('EXPECTED SIGN: ' . $expected);
progress_log('RECEIVED SIGN: ' . $ikSign);
if (!$bypass) {
if (!hash_equals($expected, $ikSign)) {
http_response_code(403);
progress_log('iKhokha webhook: signature mismatch');
progress_log('EXPECTED SIGN: ' . $expected);
progress_log('RECEIVED SIGN: ' . $ikSign);
// Audit signature mismatch
if (function_exists('auditLog')) {
auditLog(null, 'IKHOKHA_SIGNATURE_MISMATCH', 'webhook', null, ['expected' => $expected, 'received' => $ikSign]);
auditLog(null, 'IKHOKHA_SIGNATURE_MISMATCH', 'webhook', null, [
'expected' => $expected,
'received' => $ikSign
]);
}
exit('Invalid signature');
}
@@ -95,20 +117,13 @@ if (!$bypass) {
* ==========================================================
*/
$payload = json_decode($raw, true);
if (!is_array($payload)) {
http_response_code(400);
progress_log('iKhokha webhook: invalid JSON');
exit('Invalid JSON');
}
$data = $payload['data'] ?? $payload;
/**
* ==========================================================
* Extract data safely (iKhokha is inconsistent)
* Extract fields safely
* ==========================================================
*/
$data = $payload['data'] ?? $payload;
$externalTransactionID =
$data['externalTransactionID']
?? $data['externalTransactionId']
@@ -127,11 +142,11 @@ $providerStatus =
progress_log('Parsed externalTransactionID: ' . $externalTransactionID);
progress_log('Parsed providerPaymentId: ' . $providerPaymentId);
progress_log('Parsed providerStatus: ' . print_r($providerStatus, true));
progress_log('Parsed providerStatus: ' . $providerStatus);
/**
* ==========================================================
* Locate local payment
* Locate payment
* ==========================================================
*/
$localPaymentId = null;
@@ -146,16 +161,13 @@ if ($externalTransactionID) {
WHERE payment_id = ?
LIMIT 1"
);
if ($stmt) {
$stmt->bind_param('s', $externalTransactionID);
$stmt->execute();
$res = $stmt->get_result();
if ($row = $res->fetch_assoc()) {
extract($row);
$localPaymentId = $row['payment_id'];
$booking_id = $row['booking_id'];
$user_id = $row['user_id'];
$description = $row['description'];
}
$stmt->close();
}
@@ -168,16 +180,13 @@ if (!$localPaymentId && $providerPaymentId) {
WHERE provider_payment_id = ?
LIMIT 1"
);
if ($stmt) {
$stmt->bind_param('s', $providerPaymentId);
$stmt->execute();
$res = $stmt->get_result();
if ($row = $res->fetch_assoc()) {
extract($row);
$localPaymentId = $row['payment_id'];
$booking_id = $row['booking_id'];
$user_id = $row['user_id'];
$description = $row['description'];
}
$stmt->close();
}
@@ -185,11 +194,6 @@ if (!$localPaymentId && $providerPaymentId) {
if (!$localPaymentId) {
http_response_code(404);
progress_log('iKhokha webhook: payment not found');
progress_log(json_encode([$externalTransactionID, $providerPaymentId]));
if (function_exists('auditLog')) {
auditLog(null, 'IKHOKHA_PAYMENT_NOT_FOUND', 'payment', null, ['externalTransactionID' => $externalTransactionID, 'providerPaymentId' => $providerPaymentId]);
}
exit('Payment not found');
}
@@ -216,72 +220,58 @@ if ($update) {
);
$update->execute();
$update->close();
if (function_exists('auditLog')) {
auditLog($user_id, 'PAYMENT_PROVIDER_RESPONSE_SAVED', 'payment', null, ['payment_id' => $localPaymentId, 'provider_payment_id' => $providerPaymentId, 'provider_status' => $providerStatus]);
}
}
/**
* ==========================================================
* Normalize status and apply business logic
* Business logic
* ==========================================================
*/
$normalized = strtoupper(trim((string)$providerStatus));
if (in_array($normalized, ['PAID', 'SUCCESS', 'COMPLETED', 'SETTLED'], true)) {
// Mark payment as PAID
$setPaid = $conn->prepare(
$conn->prepare(
"UPDATE payments SET status = 'PAID' WHERE payment_id = ?"
);
if ($setPaid) {
$setPaid->bind_param('s', $localPaymentId);
$setPaid->execute();
$setPaid->close();
if (function_exists('auditLog')) {
auditLog($user_id, 'PAYMENT_MARKED_PAID', 'payment', null, ['payment_id' => $localPaymentId]);
}
}
)->bind_param('s', $localPaymentId)->execute();
// Booking or membership update
if (!empty($booking_id)) {
$upd = $conn->prepare(
if ($booking_id) {
$conn->prepare(
"UPDATE bookings SET status = 'PAID' WHERE booking_id = ?"
);
if ($upd) {
$upd->bind_param('i', $booking_id);
$upd->execute();
$upd->close();
sendAdminNotification('4WDCSA.co.za - New Booking - '.getFullName($user_id) , 'We have received a payment for a new booking for '.$description.' from '.getFullName($user_id));
if (function_exists('auditLog')) {
auditLog($user_id, 'BOOKING_PAYMENT_MARKED_PAID', 'bookings', $booking_id, ['payment_id' => $localPaymentId]);
}
}
)->bind_param('i', $booking_id)->execute();
} else {
$upd = $conn->prepare(
"UPDATE membership_fees
SET payment_status = 'PAID'
WHERE payment_id = ?"
);
if ($upd) {
$upd->bind_param('s', $localPaymentId);
$upd->execute();
$upd->close();
sendAdminNotification('4WDCSA.co.za - Membership Payment Received - '.getFullName($user_id) , 'A Membership Payment has been received from '.getFullName($user_id));
if (function_exists('auditLog')) {
auditLog($user_id, 'MEMBERSHIP_PAYMENT_MARKED_PAID', 'membership_fees', null, ['payment_id' => $localPaymentId]);
}
}
$conn->prepare(
"UPDATE membership_fees SET payment_status = 'PAID' WHERE payment_id = ?"
)->bind_param('s', $localPaymentId)->execute();
}
// Send confirmation email
if (!empty($user_id)) {
sendPaymentConfirmation(
getEmail($user_id),
getFullName($user_id),
$description
);
}
//generate $message for admin payment confirmation with payment details
$message = "Payment Confirmation\n\n";
$message .= "Payment ID: " . $localPaymentId . "\n";
$message .= "Amount: " . getPaymentAmount($localPaymentId) . "\n";
$message .= "Status: PAID\n";
$message .= "Description: " . $description . "\n";
$message .= "Thank you.\n";
$subject = "4WDCSA.co.za Payment Confirmation for Payment ID: " . $localPaymentId;
progress_log('Payment confirmation sent for payment ID: ' . $localPaymentId);
sendEmail(
$_ENV['FINANCE_EMAIL'],
$subject,
nl2br($message)
);
sendEmail(
'chrispintoza@gmail.com',
$subject,
nl2br($message)
);
sendAdminNotification($subject, nl2br($message));
}
/**

View File

@@ -858,6 +858,45 @@ function createIkhokhaPayment($payment_id, $amount, $description, $publicRef)
return $resp;
}
function getIkhokhaTransactionHistory($startDate, $endDate,)
{
// Base requester URL: prefer explicit env var, otherwise build from request
$endpoint = "https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=".$startDate."&endDate=".$endDate;
// $endpoint = "https://api.ikhokha.com/public-api/v1/api/payments/history?startDate=2024-02-01&endDate=2026-03-07";
$appID = $_ENV['IKHOKHA_APP_ID'];
progress_log($appID, "IKHOKHA App ID");
$appSecret = $_ENV['IKHOKHA_APP_SECRET'];
// $stringifiedBody = json_encode($requestBody);
$payloadToSign = createPayloadToSign($endpoint, null);
progress_log($payloadToSign, "IKHOKHA Payload to Sign");
$ikSign = generateSignature($payloadToSign, $appSecret);
progress_log($ikSign, "IKHOKHA Signature");
// Initialize cURL session
$ch = curl_init($endpoint);
// Set cURL options
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
// curl_setopt($ch, CURLOPT_POSTFIELDS, $stringifiedBody);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Content-Type: application/json",
"IK-APPID: $appID",
"IK-SIGN: $ikSign"
]);
// Execute cURL session
$response = curl_exec($ch);
curl_close($ch);
// Decode and output the response
$resp = json_decode($response, true);
return $response;
}
function escapeString($str) {
$escaped = preg_replace(['/[\\"\'\"]/u', '/\x00/'], ['\\\\$0', '\\0'], (string)$str);
$cleaned = str_replace('\/', '/', $escaped);
@@ -879,6 +918,20 @@ function generateSignature($payloadToSign, $secret) {
return hash_hmac('sha256', $payloadToSign, $secret);
}
function getPaymentAmount($localPaymentId) {
$conn = openDatabaseConnection();
$stmt = $conn->prepare("SELECT amount FROM payments WHERE payment_id = ? LIMIT 1");
$stmt->bind_param("s", $localPaymentId);
$stmt->execute();
$result = $stmt->get_result();
if ($row = $result->fetch_assoc()) {
return $row['amount'];
} else {
return false; // Payment not found
}
}
function processMembershipPayment($payment_id, $amount, $description)
{
$conn = openDatabaseConnection();

View File

@@ -1 +1 @@
Database Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directory
Database Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directoryDatabase Connection Error: No such file or directory

View File

@@ -1,41 +0,0 @@
<?php
require_once("./src/config/env.php");
/**
* EXACT escape function from iKhokha docs
*/
function escapeString($str) {
$escaped = preg_replace(
['/[\\"\'\"]/u', '/\x00/'],
['\\\\$0', '\\0'],
(string)$str
);
$cleaned = str_replace('\/', '/', $escaped);
return $cleaned;
}
$callbackUrl = $_ENV['IKHOKHA_CALLBACK_URL'] ?? null;
$path = '/src/api/ikhokha_webhook.php';
$secret = $_ENV['IKHOKHA_APP_SECRET'] ?? null;
// Simulated raw webhook body (EXACT, no whitespace changes)
$raw = '{"paylinkID":"ys5225k4z56x0mm","status":"SUCCESS","externalTransactionID":"693efeaca71a9","responseCode":"00","text":null}';
echo "<strong>IK-SIGN FROM WEBHOOK:</strong><br>";
echo "bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557<br><br>";
$payloadToSign = $path . $raw;
// Generate signature using hash_hmac directly on the constructed string
$expected = hash_hmac('sha256', $payloadToSign, $secret);
// --- Output debug info (UPDATED) ---
echo "<strong>DEBUG INFO</strong><br>";
echo "Callback URL: $callbackUrl<br><br>";
echo "<strong>Payload to Sign (Un-escaped):</strong><br>";
echo htmlspecialchars($payloadToSign) . "<br><br>";
echo "<strong>EXPECTED SIGNATURE:</strong><br>";
echo $expected . "<br>";