$config = require __DIR__ . '/config.php'; $type = strtolower($config['ServerFiles'] ?? 'louis'); // ✅ Выбор режима $isSandbox = $config['paypal_use_sandbox'] ?? false; $paypalUrl = $isSandbox ? 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr' : 'https://ipnpb.paypal.com/cgi-bin/webscr'; $expectedEmail = $isSandbox ? strtolower($config['paypal_sandbox_email']) : strtolower($config['paypal_live_email']); // ✅ Подключение к MSSQL try { $dsn = "dblib:host={$config['mssql_host']};dbname={$config['mssql_db']}"; $pdo = new PDO($dsn, $config['mssql_user'], $config['mssql_password']); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { file_put_contents("paypal-ipn.log", "❌ MSSQL error: " . $e->getMessage() . "\n", FILE_APPEND); exit; } // ✅ Получение и валидация данных от PayPal $raw_post_data = file_get_contents('php://input'); $req = 'cmd=_notify-validate&' . $raw_post_data; $ch = curl_init($paypalUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $req); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']); $response = curl_exec($ch); curl_close($ch); // 🪵 Лог file_put_contents("paypal-ipn.log", date("Y-m-d H:i:s") . " → $response\n$raw_post_data\n\n", FILE_APPEND); if ($response === "VERIFIED") { parse_str($raw_post_data, $data); $receiver_email = strtolower($data['receiver_email'] ?? ''); $payment_status = $data['payment_status'] ?? ''; $custom = $data['custom'] ?? ''; if ($payment_status !== "Completed") return; if ($receiver_email !== $expectedEmail) return; $parts = explode("|", $custom); if (count($parts) !== 3) return; $character_name = $parts[0]; $currency = $parts[1]; $amount = floatval($parts[2]); if (!in_array($currency, ['WCoinC', 'WCoinP', 'GoblinPoint'])) { file_put_contents("paypal-ipn.log", "❌ Invalid currency: $currency\n", FILE_APPEND); return; } // 🔎 Найти AccountID $stmt = $pdo->prepare("SELECT AccountID FROM Character WHERE Name = ?"); $stmt->execute([$character_name]); $row = $stmt->fetch(PDO::FETCH_ASSOC); if (!$row) { file_put_contents("paypal-ipn.log", "❌ Character not found: $character_name\n", FILE_APPEND); return; } $accountID = $row['AccountID']; // 🧠 Выбор таблицы и поля в зависимости от ServerFiles switch ($type) { case 'ignc': $table = 'T_InGameShop_Point'; $field = $currency === 'GoblinPoint' ? 'GoblinPoint' : 'WCoin'; // У ignc только WCoin break; case 'ssemu': file_put_contents("paypal-ipn.log", "❌ ssemu does not support CashShop\n", FILE_APPEND); return; default: $table = 'CashShopData'; $field = $currency; // WCoinC, WCoinP, GoblinPoint break; } // 💰 Начисление $stmt = $pdo->prepare("UPDATE $table SET $field = ISNULL($field, 0) + ? WHERE AccountID = ?"); $success = $stmt->execute([$amount, $accountID]); if ($success) { file_put_contents("paypal-ipn.log", "✅ $accountID получил $amount $currency (персонаж: $character_name)\n", FILE_APPEND); } else { file_put_contents("paypal-ipn.log", "❌ Failed to update $currency for $accountID\n", FILE_APPEND); } }