From 309d08497bfbb0e3be0bb71f966b61e6551e2c5c Mon Sep 17 00:00:00 2001 From: Frank Harris Date: Wed, 22 Oct 2025 10:03:37 -0400 Subject: [PATCH] website fix --- _website/admin.php | 68 ++++++++ _website/admin_config.php | 103 +++++++++++ _website/admin_payments.php | 59 +++++++ _website/adminserverlist.php | 91 +++++----- _website/ai.php | 13 +- {paypal => _website}/api/capture_order.php | 10 +- {paypal => _website}/api/create_order.php | 56 ++---- _website/cart.php | 135 ++++++++++----- _website/css/header.css | 115 +++++++++++++ .../data/INV-20250825-170438-e37518.json | 0 .../data/INV-20250825-174311-0a7993.json | 0 {paypal => _website}/data/NO-INVOICE.json | 0 .../SIMULATED-WEBHOOK-20251022-101500.json | 10 ++ _website/data/webhook.log | 2 + _website/docs/docs.php | 2 +- _website/docs/games/index.php | 2 +- _website/images/banner.png | Bin 0 -> 284540 bytes _website/images/bf3_the_russian.jpg | Bin 0 -> 159892 bytes _website/images/dark.jpg | Bin 0 -> 659147 bytes _website/images/logo-sm.png | Bin 0 -> 20171 bytes _website/includes/admin_auth.php | 60 +++++++ _website/includes/cart_helper.php | 22 +++ _website/includes/config.inc.php | 16 ++ _website/includes/footer.php | 8 + _website/includes/login_required.php | 19 +++ _website/includes/menu.php | 89 +++++++--- _website/includes/top.php | 18 ++ _website/index.php | 15 +- _website/invoices.php | 66 +++++++ _website/logfile.txt | 12 ++ _website/login.php | 131 ++++++++++++-- _website/logout.php | 31 +++- _website/order.php | 28 +-- _website/payments/api/README.md | 1 + _website/payments/config.php | 4 + _website/payments/pay.php | 4 + _website/payments/return.php | 4 + _website/payments/webhook.php | 159 +++++++++++++++++ _website/paypal/api/README.md | 1 + _website/paypal/config.php | 7 + _website/paypal/pay.php | 103 +++++++++++ _website/paypal/return.php | 4 + _website/paypal/webhook.php | 161 ++++++++++++++++++ _website/privacy.php | 6 + _website/register.php | 65 +++++++ {paypal => _website}/return.php | 29 ++-- _website/serverlist.php | 17 +- _website/tools/check_db_user.php | 30 ++++ _website/tools/check_invoices_redirect.php | 16 ++ _website/tools/check_logout_redirect.php | 21 +++ _website/tools/debug_invoices_redirect.php | 40 +++++ _website/tools/simulate_webhook.php | 39 +++++ _website/tos.php | 6 + {paypal => _website}/webhook.php | 47 +++-- images/xpgamehost.png | Bin 16290 -> 0 bytes images/xplogo.png | Bin 16925 -> 0 bytes paypal/config.php | 6 - paypal/pay.php | 102 ----------- 58 files changed, 1690 insertions(+), 363 deletions(-) create mode 100644 _website/admin.php create mode 100644 _website/admin_config.php create mode 100644 _website/admin_payments.php rename {paypal => _website}/api/capture_order.php (91%) rename {paypal => _website}/api/create_order.php (57%) create mode 100644 _website/css/header.css rename {paypal => _website}/data/INV-20250825-170438-e37518.json (100%) rename {paypal => _website}/data/INV-20250825-174311-0a7993.json (100%) rename {paypal => _website}/data/NO-INVOICE.json (100%) create mode 100644 _website/data/SIMULATED-WEBHOOK-20251022-101500.json create mode 100644 _website/data/webhook.log create mode 100644 _website/images/banner.png create mode 100644 _website/images/bf3_the_russian.jpg create mode 100644 _website/images/dark.jpg create mode 100644 _website/images/logo-sm.png create mode 100644 _website/includes/admin_auth.php create mode 100644 _website/includes/cart_helper.php create mode 100644 _website/includes/footer.php create mode 100644 _website/includes/login_required.php create mode 100644 _website/includes/top.php create mode 100644 _website/invoices.php create mode 100644 _website/logfile.txt create mode 100644 _website/payments/api/README.md create mode 100644 _website/payments/config.php create mode 100644 _website/payments/pay.php create mode 100644 _website/payments/return.php create mode 100644 _website/payments/webhook.php create mode 100644 _website/paypal/api/README.md create mode 100644 _website/paypal/config.php create mode 100644 _website/paypal/pay.php create mode 100644 _website/paypal/return.php create mode 100644 _website/paypal/webhook.php create mode 100644 _website/privacy.php create mode 100644 _website/register.php rename {paypal => _website}/return.php (81%) create mode 100644 _website/tools/check_db_user.php create mode 100644 _website/tools/check_invoices_redirect.php create mode 100644 _website/tools/check_logout_redirect.php create mode 100644 _website/tools/debug_invoices_redirect.php create mode 100644 _website/tools/simulate_webhook.php create mode 100644 _website/tos.php rename {paypal => _website}/webhook.php (80%) delete mode 100644 images/xpgamehost.png delete mode 100644 images/xplogo.png delete mode 100644 paypal/config.php delete mode 100644 paypal/pay.php diff --git a/_website/admin.php b/_website/admin.php new file mode 100644 index 00000000..738dc177 --- /dev/null +++ b/_website/admin.php @@ -0,0 +1,68 @@ + + + + + + Admin — Dashboard + + + + +
+

Admin Dashboard

+

Welcome to the admin area. From here you can manage servers, payments, and site settings.

+ +
+ Manage Servers & Services + Invoice History + Edit Site Config +
+ +
+

Quick usage notes

+ + +

Sandbox account (testing)

+

Use PayPal sandbox credentials when testing payments. Set your sandbox client_id and client_secret in the runtime config that the payment handlers use (for this site those are in the respective files under _website/paypal/ and _website/payments/ or in a central config if you moved credentials).

+ + +

Payments: high-level program flow

+
    +
  1. User adds an item and proceeds to checkout (_website/cart.php).
  2. +
  3. The checkout page renders the PayPal JS SDK and calls server-side endpoints (create_order/capture_order).
  4. +
  5. After a successful capture, PayPal sends a webhook event to _website/webhook.php (or the equivalent handler under _website/paypal/).
  6. +
  7. The webhook verifies the signature, fetches any missing order details, and writes a JSON record to the data/ directory (this powers invoices.php and return.php).
  8. +
  9. On successful payment we mark the order as PAID in the JSON and the site UI (invoices/returns) reads those JSONs to render receipts.
  10. +
  11. Admin pages can view invoices at ./invoices.php and reconcile or trigger further provisioning via internal panel APIs.
  12. +
+ +

Environment

+ + + + + +
Site Base URL
Data directory
PHP SAPI
Writable?
+ +
+ + + diff --git a/_website/admin_config.php b/_website/admin_config.php new file mode 100644 index 00000000..dd30a966 --- /dev/null +++ b/_website/admin_config.php @@ -0,0 +1,103 @@ +&1', $out, $rc); + $lintOutput = is_array($out) ? implode("\n", $out) : (string)$out; + if ($rc !== 0) { + $lintOk = false; + } + } else { + $lintOutput = 'PHP executable not found for linting; skipping post-save syntax check.'; + } + + if (!$lintOk) { + // rollback + @copy($bakName, $cfgPath); + $status = 'Syntax error detected in saved config. Changes rolled back. Lint output: ' . h($lintOutput); + } else { + $status = 'Config saved successfully. Backup: ' . basename($bakName) . (strlen($lintOutput) ? ' (lint: '.h($lintOutput).')' : ''); + // reload values + require_once($cfgPath); + } + } + } + } + } + } +} + +$currentText = ''; +if (is_readable($cfgPath)) { + $currentText = file_get_contents($cfgPath); +} + +?> + + + + + Admin — Edit Config + + + + +
+

Edit Site Config

+
+ +
+ +
+ +
+
+ +

Backups are stored in

+
+ + + diff --git a/_website/admin_payments.php b/_website/admin_payments.php new file mode 100644 index 00000000..7fcfa1c7 --- /dev/null +++ b/_website/admin_payments.php @@ -0,0 +1,59 @@ + + + + + + Admin — Payments + + + + + +
+

Payments (webhook)

+ +

No payment records found in

+ + + + + + + + + + + + + + + + + + + + + + + + +
FilenameInvoiceAmountPayerDateView
View
+ +
+ + + diff --git a/_website/adminserverlist.php b/_website/adminserverlist.php index 1126a8a9..290b6468 100644 --- a/_website/adminserverlist.php +++ b/_website/adminserverlist.php @@ -9,19 +9,22 @@ -
".h($m)."
"; ?> +
".h($m)."
"; ?> +
".h($m)."
"; ?>

Enable/Disable Server Locations (Global)

@@ -146,17 +150,18 @@ $services = fetch_all_assoc($db, "SELECT service_id, service_name, `{$locat
-
+
-
+

Current Services

@@ -169,14 +174,14 @@ $services = fetch_all_assoc($db, "SELECT service_id, service_name, `{$locat - - - - - - - - + + + + + + + + @@ -189,57 +194,61 @@ $services = fetch_all_assoc($db, "SELECT service_id, service_name, `{$locat $imgUrl = trim((string)$row['img_url']); $displayUrl = ''; if ($imgUrl !== '') { - $displayUrl = is_abs_url($imgUrl) ? $imgUrl : join_base($SITE_BASE_URL, $imgUrl); + if (is_abs_url($imgUrl)) { + $displayUrl = $imgUrl; + } elseif ($SITE_BASE_URL !== '') { + $displayUrl = join_base($SITE_BASE_URL, $imgUrl); + } else { + // Use relative path (local folder) + $displayUrl = $imgUrl; + } } ?> - - - - - - - - + @@ -252,10 +261,10 @@ $services = fetch_all_assoc($db, "SELECT service_id, service_name, `{$locat $isChecked = isset($selSet[$rid]); $isPrimary = ($primary === $rid); ?> -
EnabledService Name (ID below)Min SlotsMax SlotsPrice (Monthly)Thumbnail URLPreviewUpdate RowEnabledService Name (ID below)Min SlotsMax SlotsPrice (Monthly)Thumbnail URLPreviewUpdate Row
+ > - -
ID:
+
+ +
ID:
- + + - + + + - + + + - preview + preview - (no image) + (no image) - - + +
- - - - - - - - - - - - - - +
Server IDGame NameLocationMax PlayersPrice per PlayerMonthsTotal
+ + + + + + + + + + + + + num_rows > 0) { while ($row = $carts->fetch_assoc()) { ?> - - - - - - - - - + + + + + + + + + + + + + + - + @@ -124,20 +170,20 @@ if ($db){ // Add total row ?> - - + - + - +
-
+
+ + + +

Complete your purchase

+

Amount:

+

Invoice:

+
+
+ + + + + diff --git a/_website/paypal/return.php b/_website/paypal/return.php new file mode 100644 index 00000000..4243a345 --- /dev/null +++ b/_website/paypal/return.php @@ -0,0 +1,4 @@ + true, + 'client_id' => '', + 'client_secret' => '', + 'webhook_id' => '', + 'data_dir' => realpath(__DIR__ . '/..') . DIRECTORY_SEPARATOR . 'data', + 'log_file' => realpath(__DIR__ . '/..') . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'webhook.log', +]; + +// Allow includes/config.inc.php to override SITE_DATA_DIR if set +if (defined('SITE_DATA_DIR') && SITE_DATA_DIR) { + $config['data_dir'] = rtrim(SITE_DATA_DIR, "\\/") . DIRECTORY_SEPARATOR; +} + +@mkdir($config['data_dir'], 0775, true); + +function log_line($m){global $config; @file_put_contents($config['log_file'],'['.date('c')."] $m\n",FILE_APPEND);} +function api_base(){global $config; return $config['sandbox'] ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';} + +http_response_code(200); + +$raw = file_get_contents('php://input'); +$headers = array_change_key_case(getallheaders() ?: [], CASE_UPPER); +log_line("HIT ip=".($_SERVER['REMOTE_ADDR']??'') ." bytes=".strlen($raw)); +if (!$raw) { log_line("NO_BODY"); exit; } + +// 1) OAuth2 +$ch = curl_init(api_base().'/v1/oauth2/token'); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER=>true, + CURLOPT_POST=>true, + CURLOPT_POSTFIELDS=>'grant_type=client_credentials', + CURLOPT_HTTPHEADER=>['Accept: application/json'], + CURLOPT_USERPWD=>$config['client_id'].':'.$config['client_secret'], +]); +$tokenResp = curl_exec($ch); +$http = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); +if ($http!==200){ log_line("OAUTH_FAIL http=$http resp=$tokenResp"); exit; } +$access_token = json_decode($tokenResp, true)['access_token'] ?? null; +if (!$access_token){ log_line("OAUTH_NO_TOKEN"); exit; } + +// 2) Verify webhook signature +$verifyPayload = [ + 'transmission_id' => $headers['PAYPAL-TRANSMISSION-ID'] ?? '', + 'transmission_time' => $headers['PAYPAL-TRANSMISSION-TIME'] ?? '', + 'cert_url' => $headers['PAYPAL-CERT-URL'] ?? '', + 'auth_algo' => $headers['PAYPAL-AUTH-ALGO'] ?? '', + 'transmission_sig' => $headers['PAYPAL-TRANSMISSION-SIG'] ?? '', + 'webhook_id' => $config['webhook_id'], + 'webhook_event' => json_decode($raw, true), +]; +$ch = curl_init(api_base().'/v1/notifications/verify-webhook-signature'); +curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER=>true, + CURLOPT_POST=>true, + CURLOPT_POSTFIELDS=>json_encode($verifyPayload), + CURLOPT_HTTPHEADER=>[ + 'Content-Type: application/json', + 'Authorization: Bearer '.$access_token + ], +]); +$verifyResp = curl_exec($ch); +$http = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); +$verifyJson = json_decode($verifyResp, true); +if ($http!==200 || ($verifyJson['verification_status'] ?? '') !== 'SUCCESS'){ + log_line("VERIFY_FAIL http=$http status=".($verifyJson['verification_status']??'NONE')); + exit; +} +log_line("VERIFY_OK"); + +// 3) Parse and persist (now with items) +$evt = json_decode($raw, true); +$type = $evt['event_type'] ?? ''; +$res = $evt['resource'] ?? []; + +// Extract common fields +$invoice = $res['invoice_id'] ?? ($res['invoice_number'] ?? null); +$custom = $res['custom_id'] ?? ($res['custom'] ?? null); + +// Amounts/payer +$amount = $res['amount']['value'] ?? ($res['amount']['total'] ?? null); +$currency = $res['amount']['currency_code'] ?? ($res['amount']['currency'] ?? null); +$payer = $res['payer']['email_address'] ?? ($res['payer']['payer_info']['email'] ?? null); + +// Try to capture line items if present directly in this event: +$items = []; +if (isset($res['purchase_units'][0]['items']) && is_array($res['purchase_units'][0]['items'])) { + $items = $res['purchase_units'][0]['items']; +} + +// If capture event, try to fetch the parent ORDER to get items +if (!$items && $type === 'PAYMENT.CAPTURE.COMPLETED') { + $orderId = + $res['supplementary_data']['related_ids']['order_id'] // preferred + ?? null; + + if (!$orderId && isset($res['links']) && is_array($res['links'])) { + // Fallback: look for a link to the parent order + foreach ($res['links'] as $lnk) { + if (!empty($lnk['href']) && !empty($lnk['rel']) && stripos($lnk['href'], '/v2/checkout/orders/') !== false) { + $orderId = basename(parse_url($lnk['href'], PHP_URL_PATH)); + break; + } + } + } + + if ($orderId) { + $ch = curl_init(api_base()."/v2/checkout/orders/".urlencode($orderId)); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ + 'Authorization: Bearer '.$access_token, + 'Content-Type: application/json' + ], + ]); + $orderJson = curl_exec($ch); + $httpOrder = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($httpOrder === 200) { + $order = json_decode($orderJson, true); + if (isset($order['purchase_units'][0]['items']) && is_array($order['purchase_units'][0]['items'])) { + $items = $order['purchase_units'][0]['items']; + } + // If the order has invoice/custom (sometimes more reliable), prefer those: + if (!$invoice) { $invoice = $order['purchase_units'][0]['invoice_id'] ?? $invoice; } + if (!$custom) { $custom = $order['purchase_units'][0]['custom_id'] ?? $custom; } + } else { + log_line("ORDER_FETCH_FAIL id=$orderId http=$httpOrder"); + } + } +} + +$status = 'IGNORED'; + +// We persist on payment completed events +if (in_array($type, ['PAYMENT.CAPTURE.COMPLETED','PAYMENT.SALE.COMPLETED'], true)) { + $record = [ + 'event_type' => $type, + 'status' => 'PAID', + 'amount' => $amount, + 'currency' => $currency, + 'payer' => $payer, + 'invoice' => $invoice, + 'custom' => $custom, + 'resource_id' => $res['id'] ?? null, + 'items' => $items, // Persist line items for your return.php/UI + 'ts' => date('c'), + ]; + $name = $invoice ?: 'NO-INVOICE'; + @file_put_contents($config['data_dir']."/$name.json", json_encode($record, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); + $status = 'WROTE_FILE'; +} + +log_line("EVENT $type invoice=".($invoice ?: 'none')." items_count=".count($items)." status=$status"); diff --git a/_website/privacy.php b/_website/privacy.php new file mode 100644 index 00000000..0fbc4b5e --- /dev/null +++ b/_website/privacy.php @@ -0,0 +1,6 @@ + +
+

Privacy

+

This is the privacy page placeholder.

+
+ diff --git a/_website/register.php b/_website/register.php new file mode 100644 index 00000000..ed2c450d --- /dev/null +++ b/_website/register.php @@ -0,0 +1,65 @@ +query("SHOW COLUMNS FROM ogp_users LIKE 'users_pass_hash'"); + if ($res && $res->num_rows > 0) { + $has_shadow = true; + } + + if ($has_shadow) { + $stmt = $db->prepare("INSERT INTO ogp_users (users_login, users_passwd, users_pass_hash, users_email, users_role) VALUES (?, ?, ?, ?, 'user')"); + $stmt->bind_param('ssss', $username, $md5pw, $modern, $email); + } else { + $stmt = $db->prepare("INSERT INTO ogp_users (users_login, users_passwd, users_email, users_role) VALUES (?, ?, ?, 'user')"); + $stmt->bind_param('sss', $username, $md5pw, $email); + } + + if ($stmt->execute()) { + // Redirect to absolute login URL + $script = $_SERVER['SCRIPT_NAME'] ?? ''; + $pos = strpos($script, '/_website'); + $siteRoot = $pos !== false ? substr($script, 0, $pos + strlen('/_website')) : rtrim(dirname($script), '/\\'); + header('Location: ' . $siteRoot . '/login.php?registered=1'); + exit; + } else { + $error = 'Could not create user. Maybe the name is taken.'; + } + } + } +} +?> + + +Register - GameServers.World + + +

Register

+'.htmlspecialchars($error).''; ?> + +
+
+
+ + + + diff --git a/paypal/return.php b/_website/return.php similarity index 81% rename from paypal/return.php rename to _website/return.php index 4c0b1b9e..cdb3f314 100644 --- a/paypal/return.php +++ b/_website/return.php @@ -1,7 +1,7 @@ .json written by webhook.php and shows a receipt with items +require_once(__DIR__ . '/includes/config.inc.php'); -$dataDir = __DIR__ . '/data'; +$dataDir = (isset($SITE_DATA_DIR) && $SITE_DATA_DIR) ? $SITE_DATA_DIR : realpath(__DIR__ . '/') . DIRECTORY_SEPARATOR . 'data'; $invoice = $_GET['invoice'] ?? ''; $cancel = isset($_GET['cancel']); @@ -9,8 +9,8 @@ $status = 'PENDING'; $details = null; $items = []; -if ($invoice && is_file("$dataDir/$invoice.json")) { - $details = json_decode(file_get_contents("$dataDir/$invoice.json"), true); +if ($invoice && is_file($dataDir . DIRECTORY_SEPARATOR . $invoice . '.json')) { + $details = json_decode(file_get_contents($dataDir . DIRECTORY_SEPARATOR . $invoice . '.json'), true); if (!empty($details['status'])) { $status = $details['status']; } @@ -19,7 +19,6 @@ if ($invoice && is_file("$dataDir/$invoice.json")) { } } -// Helpers function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); } function money_fmt($value, $currency) { if ($value === null || $value === '') return ''; @@ -32,16 +31,11 @@ function money_fmt($value, $currency) { Payment Status - + + +

Payment canceled

Invoice:

@@ -67,7 +61,7 @@ function money_fmt($value, $currency) {

Items

-
Server IDGame NameLocationMax PlayersPrice per PlayerMonthsTotal
- - - - $
+
+ +
+
$ +
+ + +
+
  $$
+
Cart Total: - $ - + $ +
No items in your cart.No items in your cart.
+
@@ -83,7 +77,7 @@ function money_fmt($value, $currency) { $grand = 0.00; foreach ($items as $it) { $name = $it['name'] ?? ''; - $sku = $it['sku'] ?? ''; // we sent serverID here + $sku = $it['sku'] ?? ''; $qty = isset($it['quantity']) ? (int)$it['quantity'] : 1; $unit = isset($it['unit_amount']['value']) ? (float)$it['unit_amount']['value'] : 0.00; $line = $qty * $unit; @@ -98,7 +92,7 @@ function money_fmt($value, $currency) { } ?> - + @@ -114,6 +108,7 @@ function money_fmt($value, $currency) {

We’re waiting for PayPal to confirm your payment. This page will show the receipt once we receive the webhook. Try refreshing in a few seconds.

+ + - diff --git a/_website/serverlist.php b/_website/serverlist.php index d18d2dec..21a03f31 100644 --- a/_website/serverlist.php +++ b/_website/serverlist.php @@ -42,15 +42,16 @@ if (!$services) { return; } -// Include menu +// Include top bar and menu +include(__DIR__ . '/includes/top.php'); include(__DIR__ . '/includes/menu.php'); ?> -
+
-
+



-
- - - + Order Server
-
+

@@ -97,7 +95,7 @@ include(__DIR__ . '/includes/menu.php'); -
Server ID
TotalTotal
+
@@ -117,4 +115,5 @@ include(__DIR__ . '/includes/menu.php'); mysqli_close($db); ?> + diff --git a/_website/tools/check_db_user.php b/_website/tools/check_db_user.php new file mode 100644 index 00000000..1d829ece --- /dev/null +++ b/_website/tools/check_db_user.php @@ -0,0 +1,30 @@ + 0) $has_shadow = true; +$select_fields = 'user_id, users_login, users_passwd'; +if ($has_shadow) $select_fields .= ", users_pass_hash"; +$q = "SELECT $select_fields FROM ogp_users WHERE users_login = '$user_safe' LIMIT 1"; +$res = mysqli_query($db, $q); +if (!$res) { + echo "Query error: " . mysqli_error($db) . PHP_EOL; + exit(1); +} +if (mysqli_num_rows($res) === 0) { + echo "No user found for '$user'\n"; +} else { + $row = mysqli_fetch_assoc($res); + echo "Found user: id={$row['user_id']}, login={$row['users_login']}\n"; + echo "passwd(db)=" . ($row['users_passwd'] ?? '') . "\n"; + echo "pass_hash(db)=" . ($row['users_pass_hash'] ?? '') . "\n"; +} +mysqli_close($db); +?> \ No newline at end of file diff --git a/_website/tools/check_invoices_redirect.php b/_website/tools/check_invoices_redirect.php new file mode 100644 index 00000000..69ccd956 --- /dev/null +++ b/_website/tools/check_invoices_redirect.php @@ -0,0 +1,16 @@ +true, CURLOPT_HEADER=>true, CURLOPT_FOLLOWLOCATION=>false]); +$res = curl_exec($ch); +$http = curl_getinfo($ch, CURLINFO_HTTP_CODE); +$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); +$headers = substr($res, 0, $header_size); +$body = substr($res, $header_size); +curl_close($ch); + +echo "Request: $target\n"; +echo "HTTP: $http\n"; +echo "Headers:\n$headers\n"; +echo "Body snippet:\n" . substr($body,0,400) . "\n"; +?> diff --git a/_website/tools/check_logout_redirect.php b/_website/tools/check_logout_redirect.php new file mode 100644 index 00000000..fe7cab7e --- /dev/null +++ b/_website/tools/check_logout_redirect.php @@ -0,0 +1,21 @@ + \ No newline at end of file diff --git a/_website/tools/debug_invoices_redirect.php b/_website/tools/debug_invoices_redirect.php new file mode 100644 index 00000000..e3681f5f --- /dev/null +++ b/_website/tools/debug_invoices_redirect.php @@ -0,0 +1,40 @@ +true, CURLOPT_HEADER=>true, CURLOPT_FOLLOWLOCATION=>false]); +$res = curl_exec($ch); +$http = curl_getinfo($ch, CURLINFO_HTTP_CODE); +$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); +$headers = substr($res, 0, $header_size); +$body = substr($res, $header_size); +curl_close($ch); + +echo "admin.php HTTP: $http\n"; +echo "Headers:\n$headers\n"; +// Find invoices link +if (preg_match('#href="([^"]*invoices\.php)"#i', $body, $m)) { + $link = $m[1]; + echo "Found invoices link: $link\n"; + // Resolve relative link + $linkUrl = (strpos($link, 'http')===0) ? $link : 'http://localhost/GSP/_website/' . ltrim($link, './'); + echo "Resolved invoices URL: $linkUrl\n"; + + // Fetch invoices.php and show headers + $ch = curl_init($linkUrl); + curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_HEADER=>true, CURLOPT_FOLLOWLOCATION=>false]); + $res2 = curl_exec($ch); + $h2 = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $http2 = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $headers2 = substr($res2, 0, $h2); + $body2 = substr($res2, $h2); + curl_close($ch); + + echo "invoices.php HTTP: $http2\n"; + echo "invoices headers:\n$headers2\n"; + echo "invoices body snippet:\n" . substr($body2,0,400) . "\n"; +} else { + echo "No invoices link found in admin.php body.\n"; +} + +?> diff --git a/_website/tools/simulate_webhook.php b/_website/tools/simulate_webhook.php new file mode 100644 index 00000000..1c7ea66c --- /dev/null +++ b/_website/tools/simulate_webhook.php @@ -0,0 +1,39 @@ + true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $raw, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'PayPal-Transmission-Id: SIM-TEST', + 'PayPal-Transmission-Time: ' . gmdate('c'), + 'PayPal-Cert-Url: https://example.com/cert.pem', + 'PayPal-Auth-Algo: SHA256withRSA', + 'PayPal-Transmission-Sig: FAKE', + ], +]); +$res = curl_exec($ch); +$err = curl_error($ch); +$http = curl_getinfo($ch, CURLINFO_HTTP_CODE); +curl_close($ch); + +echo "HTTP: $http\n"; +if ($err) echo "CURL_ERROR: $err\n"; +echo "RESPONSE:\n" . $res . "\n"; + +// show if a new file was written +$dataDir = realpath(__DIR__ . '/../data'); +$files = glob($dataDir . '/*.json'); +echo "Files in data/ after run: \n"; +foreach ($files as $f) echo basename($f) . "\n"; + +?> diff --git a/_website/tos.php b/_website/tos.php new file mode 100644 index 00000000..653d9cfe --- /dev/null +++ b/_website/tos.php @@ -0,0 +1,6 @@ + +
+

Terms of Service

+

This is the terms of service placeholder.

+
+ diff --git a/paypal/webhook.php b/_website/webhook.php similarity index 80% rename from paypal/webhook.php rename to _website/webhook.php index f24bafc8..f3464011 100644 --- a/paypal/webhook.php +++ b/_website/webhook.php @@ -1,15 +1,23 @@ true, // flip to false for Live + 'sandbox' => true, 'client_id' => 'AfvY_C2zA_hTHxHq7TIhtOeub4xBdySYrt_Hjj3d_WYQwjWI9NfOAVOTeResx2rgZ_nP5tOoxQSAHw8c', 'client_secret' => 'EJ216np9cAj9n7KSddez3fLVxGe-zi4oKKKl1YGqPp88XIikr4Qzbxh0XW2as-V6LgdX-upjtQAg9dC0', 'webhook_id' => '6N620673281740730', - 'data_dir' => __DIR__ . '/data', - 'log_file' => __DIR__ . '/webhook.log', + 'data_dir' => rtrim( + (defined('SITE_DATA_DIR') ? SITE_DATA_DIR : '') ?: ($SITE_DATA_DIR ?? ''), + DIRECTORY_SEPARATOR + ), + 'log_file' => __DIR__ . '/data/webhook.log', ]; -function log_line($m){global $config; @file_put_contents($config['log_file'],'['.date('c')."] $m\n",FILE_APPEND);} +if (!$config['data_dir']) { + $config['data_dir'] = realpath(__DIR__ . '/') . DIRECTORY_SEPARATOR . 'data'; +} + +function log_line($m){global $config; @file_put_contents($config['log_file'],'['.date('c')."] $m\n",FILE_APPEND);} function api_base(){global $config; return $config['sandbox'] ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';} http_response_code(200); @@ -66,35 +74,26 @@ if ($http!==200 || ($verifyJson['verification_status'] ?? '') !== 'SUCCESS'){ } log_line("VERIFY_OK"); -// 3) Parse and persist (now with items) +// 3) Parse and persist $evt = json_decode($raw, true); $type = $evt['event_type'] ?? ''; $res = $evt['resource'] ?? []; -// Extract common fields $invoice = $res['invoice_id'] ?? ($res['invoice_number'] ?? null); $custom = $res['custom_id'] ?? ($res['custom'] ?? null); -// Amounts/payer $amount = $res['amount']['value'] ?? ($res['amount']['total'] ?? null); $currency = $res['amount']['currency_code'] ?? ($res['amount']['currency'] ?? null); $payer = $res['payer']['email_address'] ?? ($res['payer']['payer_info']['email'] ?? null); -// Try to capture line items if present directly in this event: -// (Some events—like ORDER.*—include purchase_units; CAPTURE events often don't.) $items = []; if (isset($res['purchase_units'][0]['items']) && is_array($res['purchase_units'][0]['items'])) { $items = $res['purchase_units'][0]['items']; } -// If capture event, try to fetch the parent ORDER to get items if (!$items && $type === 'PAYMENT.CAPTURE.COMPLETED') { - $orderId = - $res['supplementary_data']['related_ids']['order_id'] // preferred - ?? null; - + $orderId = $res['supplementary_data']['related_ids']['order_id'] ?? null; if (!$orderId && isset($res['links']) && is_array($res['links'])) { - // Fallback: look for a link to the parent order foreach ($res['links'] as $lnk) { if (!empty($lnk['href']) && !empty($lnk['rel']) && stripos($lnk['href'], '/v2/checkout/orders/') !== false) { $orderId = basename(parse_url($lnk['href'], PHP_URL_PATH)); @@ -102,15 +101,11 @@ if (!$items && $type === 'PAYMENT.CAPTURE.COMPLETED') { } } } - if ($orderId) { $ch = curl_init(api_base()."/v2/checkout/orders/".urlencode($orderId)); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, - CURLOPT_HTTPHEADER => [ - 'Authorization: Bearer '.$access_token, - 'Content-Type: application/json' - ], + CURLOPT_HTTPHEADER => [ 'Authorization: Bearer '.$access_token, 'Content-Type: application/json' ], ]); $orderJson = curl_exec($ch); $httpOrder = curl_getinfo($ch, CURLINFO_HTTP_CODE); @@ -120,7 +115,6 @@ if (!$items && $type === 'PAYMENT.CAPTURE.COMPLETED') { if (isset($order['purchase_units'][0]['items']) && is_array($order['purchase_units'][0]['items'])) { $items = $order['purchase_units'][0]['items']; } - // If the order has invoice/custom (sometimes more reliable), prefer those: if (!$invoice) { $invoice = $order['purchase_units'][0]['invoice_id'] ?? $invoice; } if (!$custom) { $custom = $order['purchase_units'][0]['custom_id'] ?? $custom; } } else { @@ -130,8 +124,6 @@ if (!$items && $type === 'PAYMENT.CAPTURE.COMPLETED') { } $status = 'IGNORED'; - -// We persist on payment completed events if (in_array($type, ['PAYMENT.CAPTURE.COMPLETED','PAYMENT.SALE.COMPLETED'], true)) { $record = [ 'event_type' => $type, @@ -142,13 +134,14 @@ if (in_array($type, ['PAYMENT.CAPTURE.COMPLETED','PAYMENT.SALE.COMPLETED'], true 'invoice' => $invoice, 'custom' => $custom, 'resource_id' => $res['id'] ?? null, - 'items' => $items, // <— Persist line items for your return.php/UI + 'items' => $items, 'ts' => date('c'), ]; - $name = $invoice ?: 'NO-INVOICE'; - @file_put_contents($config['data_dir']."/$name.json", json_encode($record, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); + $name = $invoice ?: 'NO-INVOICE-'.bin2hex(random_bytes(4)); + @file_put_contents($config['data_dir']."/".$name.".json", json_encode($record, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); $status = 'WROTE_FILE'; } log_line("EVENT $type invoice=".($invoice ?: 'none')." items_count=".count($items)." status=$status"); +?> diff --git a/images/xpgamehost.png b/images/xpgamehost.png deleted file mode 100644 index 4487e9267d13132a5b1a3d18f1b45d637f08a1a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16290 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 diff --git a/paypal/config.php b/paypal/config.php deleted file mode 100644 index 5d20cea2..00000000 --- a/paypal/config.php +++ /dev/null @@ -1,6 +0,0 @@ -Webhook https://panel.iaregamer.com/paypal/webhook.php -Webhook ID 6N620673281740730 -App Gameservers World -Client ID AfvY_C2zA_hTHxHq7TIhtOeub4xBdySYrt_Hjj3d_WYQwjWI9NfOAVOTeResx2rgZ_nP5tOoxQSAHw8c -Secret Key EJ216np9cAj9n7KSddez3fLVxGe-zi4oKKKl1YGqPp88XIikr4Qzbxh0XW2as-V6LgdX-upjtQAg9dC0 - diff --git a/paypal/pay.php b/paypal/pay.php deleted file mode 100644 index 36c98705..00000000 --- a/paypal/pay.php +++ /dev/null @@ -1,102 +0,0 @@ -- - - - - - Checkout - - - - - - -

Complete your purchase

-

Amount:

-

Invoice:

-
-
- - - - - -
Game Server Name