From acd7f563b11e151ad7d1d3983ff76b1fd277df3a Mon Sep 17 00:00:00 2001 From: twotalesanimation <80506065+twotalesanimation@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:51:11 +0200 Subject: [PATCH] added transaction table, fixed signature auth. Monitor for bugs before rmoving bypass --- .env copy | 42 ++++++ .env.example | 42 ++++++ .htaccess | 2 +- header.php | 4 +- progress.log | 170 +++++++++++++++------ src/admin/_admin_tx_debug.log | 56 +++++++ src/admin/admin_transactions.php | 248 +++++++++++++++++++++++++++++++ src/api/ikhokha_webhook.php | 208 ++++++++++++-------------- src/config/functions.php | 53 +++++++ src/logs/db_errors.log | 2 +- test.php | 75 ++++++---- test2.php | 5 + 12 files changed, 716 insertions(+), 191 deletions(-) create mode 100644 .env copy create mode 100644 .env.example create mode 100644 src/admin/_admin_tx_debug.log create mode 100644 src/admin/admin_transactions.php create mode 100644 test2.php diff --git a/.env copy b/.env copy new file mode 100644 index 00000000..9d3a55ee --- /dev/null +++ b/.env copy @@ -0,0 +1,42 @@ +# Database Configuration +DB_HOST=mysql-db +DB_USER=app +DB_PASS=4wdcsa2025! +DB_NAME=4wdcsa +SALT=4wdcsa +HOST=https://beta.4wdcsa.co.za + +ENFORCE_HTTPS=true + +# Mailjet Email Service +MAILJET_API_KEY=1a44f8d5e847537dbb8d3c76fe73a93c +MAILJET_API_SECRET=ec98b45c53a7694c4f30d09eee9ad280 +MAILJET_FROM_EMAIL=info@4wdcsa.co.za +MAILJET_FROM_NAME=4WDCSA +ADMIN_EMAIL=info@4wdcsa.co.za +FINANCE_EMAIL=louiseb@global.co.za +POP_NOTIFICATION_EMAILS=chrispintoza@gmail.com,chrispintoza+pop@gmail.com,chrispintoza+4wdcsapop@gmail.com +NOTIFICATION_ADDR=chrispintoza@gmail.com + +# Google OAuth +GOOGLE_CLIENT_ID=948441222188-8qhboq2urr8o9n35mc70s5h2nhd52v0m.apps.googleusercontent.com +GOOGLE_CLIENT_SECRET=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 + +# Instagram (optional) +INSTAGRAM_ACCESS_TOKEN=your-instagram-token + +# Application Settings +APP_ENV=development +APP_DEBUG=true +APP_URL=https://beta.4wdcsa.co.za + +IKHOKHA_APP_ID=IKFLESZTKFM4HWWS76131L8HK9BYF96P +IKHOKHA_APP_SECRET=gfoQTvXRXuzq6ArPHUS2CBFxtHtH1bxM +IKHOKHA_ENDPOINT=https://api.ikhokha.com/public-api/v1/api/payment +IKHOKHA_EXTERNAL_ENTITY_ID=4WDCSA +IKHOKHA_CALLBACK_URL=https://beta.4wdcsa.co.za/src/api/ikhokha_webhook.php +IKHOKHA_SUCCESS_URL=https://beta.4wdcsa.co.za/success +IKHOKHA_FAILURE_URL=https://beta.4wdcsa.co.za/failure +IKHOKHA_CANCEL_URL=https://beta.4wdcsa.co.za/cancel +IKHOKHA_MODE=live +IKHOKHA_BYPASS_SIGNATURE=true diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..1ae3de1d --- /dev/null +++ b/.env.example @@ -0,0 +1,42 @@ +# Database Configuration +DB_HOST=mysql-db +DB_USER=app +DB_PASS=4wdcsa2025! +DB_NAME=4wdcsa +SALT=4wdcsa +HOST=https://4wdcsa.co.za + +ENFORCE_HTTPS=true + +# Mailjet Email Service +MAILJET_API_KEY=1a44f8d5e847537dbb8d3c76fe73a93c +MAILJET_API_SECRET=ec98b45c53a7694c4f30d09eee9ad280 +MAILJET_FROM_EMAIL=info@4wdcsa.co.za +MAILJET_FROM_NAME=4WDCSA +ADMIN_EMAIL=info@4wdcsa.co.za +FINANCE_EMAIL=louiseb@global.co.za +POP_NOTIFICATION_EMAILS=chrispintoza@gmail.com,chrispintoza+pop@gmail.com,chrispintoza+4wdcsapop@gmail.com +NOTIFICATION_ADDR=info@4wdcsa.co.za + +# Google OAuth +GOOGLE_CLIENT_ID=948441222188-8qhboq2urr8o9n35mc70s5h2nhd52v0m.apps.googleusercontent.com +GOOGLE_CLIENT_SECRET=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 + +# Instagram (optional) +INSTAGRAM_ACCESS_TOKEN=your-instagram-token + +# Application Settings +APP_ENV=development +APP_DEBUG=true +APP_URL=https://4wdcsa.co.za + +IKHOKHA_APP_ID=IKFLESZTKFM4HWWS76131L8HK9BYF96P +IKHOKHA_APP_SECRET=gfoQTvXRXuzq6ArPHUS2CBFxtHtH1bxM +IKHOKHA_ENDPOINT=https://api.ikhokha.com/public-api/v1/api/payment +IKHOKHA_EXTERNAL_ENTITY_ID=4WDCSA +IKHOKHA_CALLBACK_URL=https://4wdcsa.co.za/src/api/ikhokha_webhook.php +IKHOKHA_SUCCESS_URL=https://4wdcsa.co.za/success +IKHOKHA_FAILURE_URL=https://4wdcsa.co.za/failure +IKHOKHA_CANCEL_URL=https://4wdcsa.co.za/cancel +IKHOKHA_MODE=live +IKHOKHA_BYPASS_SIGNATURE=true diff --git a/.htaccess b/.htaccess index 89e12b95..70870fd0 100644 --- a/.htaccess +++ b/.htaccess @@ -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] diff --git a/header.php b/header.php index 7d82aa03..17930744 100644 --- a/header.php +++ b/header.php @@ -288,8 +288,8 @@ if ($headerStyle === 'light') {
  • Manage Trips
  • Trip Bookings
  • Course Bookings
  • -
  • EFT Payments
  • -
  • Process Payments
  • +
  • iKhokha Payment History
  • +
  • Visitor Log
  • diff --git a/progress.log b/progress.log index 975b16ba..fa15d3bd 100644 --- a/progress.log +++ b/progress.log @@ -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 diff --git a/src/admin/_admin_tx_debug.log b/src/admin/_admin_tx_debug.log new file mode 100644 index 00000000..fdcd6b4b --- /dev/null +++ b/src/admin/_admin_tx_debug.log @@ -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 diff --git a/src/admin/admin_transactions.php b/src/admin/admin_transactions.php new file mode 100644 index 00000000..e0bdc6cd --- /dev/null +++ b/src/admin/admin_transactions.php @@ -0,0 +1,248 @@ + + + + + +
    + +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    + '; + echo ' + + + + + + + + + + + '; + + $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 " + + + + + + + "; + + $printed = true; + } + + if (!$printed) { + echo ''; + } + } else { + echo ''; + echo '
    DateIDPaylinkIDDescriptionAmountStatus
    " . htmlspecialchars($createdAt) . "" . htmlspecialchars($txId) . "" . htmlspecialchars($ikhokhaTxId) . "" . htmlspecialchars($description) . "R " . htmlspecialchars($amount/100) . ".00" . htmlspecialchars($status) . "
    No records found
    + + + + + + + + + + '; + echo ''; + } ?> + + +
    DateIDDescriptionAmountStatus
    No records found
    +
    +
    +
    +
    +
    +
    + + + + diff --git a/src/api/ikhokha_webhook.php b/src/api/ikhokha_webhook.php index 9732ffda..a4157953 100644 --- a/src/api/ikhokha_webhook.php +++ b/src/api/ikhokha_webhook.php @@ -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'; +// Decode body so we can remove `text` +$bodyArray = json_decode($raw, true); +if (!is_array($bodyArray)) { + http_response_code(400); + exit('Invalid JSON'); +} + +// 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 (empty($callbackUrl)) { - http_response_code(500); - progress_log('iKhokha webhook: callback URL not configured'); - exit('Server misconfigured'); - } - - $expected = hash_hmac( - 'sha256', - $callbackUrl . $raw, - $_ENV['IKHOKHA_APP_SECRET'] - ); - 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 - ); - } + 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)); } /** diff --git a/src/config/functions.php b/src/config/functions.php index ab95e405..b21d6ac7 100644 --- a/src/config/functions.php +++ b/src/config/functions.php @@ -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(); diff --git a/src/logs/db_errors.log b/src/logs/db_errors.log index 4a23ee8e..effc7895 100644 --- a/src/logs/db_errors.log +++ b/src/logs/db_errors.log @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/test.php b/test.php index 011cbbf8..f1cb3b10 100644 --- a/test.php +++ b/test.php @@ -1,41 +1,56 @@ IK-SIGN FROM WEBHOOK:
    "; -echo "bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557

    "; +// Simulated header signature from iKhokha +$ikSignFromWebhook = 'bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557'; -$payloadToSign = $path . $raw; +// Simulated raw webhook body (EXACT) +$raw = '{"paylinkID":"ys5225k4z56x0mm","status":"SUCCESS","externalTransactionID":"693efeaca71a9","responseCode":"00","text":null}'; -// Generate signature using hash_hmac directly on the constructed string -$expected = hash_hmac('sha256', $payloadToSign, $secret); +// Simulated header signature from iKhokha +$ikSignFromWebhook = 'bb1702d488a40091ebd5414bc6f524e203e2c5e36b24a1b86e243dad440bb557'; -// --- Output debug info (UPDATED) --- -echo "DEBUG INFO
    "; -echo "Callback URL: $callbackUrl

    "; +// Decode JSON string into array +$bodyArray = json_decode($raw, true); -echo "Payload to Sign (Un-escaped):
    "; -echo htmlspecialchars($payloadToSign) . "

    "; +// Remove `text` key exactly like JS +unset($bodyArray['text']); + +// Re-encode JSON (no double-encoding) +$cleanBody = json_encode($bodyArray, JSON_UNESCAPED_SLASHES); + +// Now sign the SAME payload JS signs +$payloadToSign = createPayloadToSign($callbackUrl, $cleanBody); + +$ikSign = generateSignature($payloadToSign, $secret); +?> + + + + + iKhokha Signature Debug (JS) + + + +

    IK-SIGN FROM WEBHOOK:

    +
    + +

    DEBUG INFO

    +

    Callback URL:

    + +

    Payload to Sign (Un-escaped):

    + +
    + +

    EXPECTED SIGNATURE (JS):

    + +
    -echo "EXPECTED SIGNATURE:
    "; -echo $expected . "
    "; \ No newline at end of file diff --git a/test2.php b/test2.php new file mode 100644 index 00000000..7c9dc916 --- /dev/null +++ b/test2.php @@ -0,0 +1,5 @@ +