JezK
Edit File: application-payment-api.php
<?php // application-payment-api.php // Save this file to: /wp-content/plugins/zoho-crm-api/application-payment-api.php // Disable error display in production ini_set('display_errors', 0); ini_set('log_errors', 1); error_reporting(E_ALL); error_log("Application Payment API started"); // Secure session handling if (!session_id() && !headers_sent()) { ini_set('session.cookie_httponly', 1); if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') { ini_set('session.cookie_secure', 1); } ini_set('session.use_only_cookies', 1); ini_set('session.cookie_samesite', 'Strict'); session_start(); } // Ensure this file is accessed within WordPress if (!defined('ABSPATH')) { define('ABSPATH', '/home/authentica.com/public_html/'); require_once(ABSPATH . 'wp-load.php'); } // Force use Stripe Test keys for testing - use variables instead of constants $stripe_secret_key = 'sk_test_elYDKbrycT1RHRKOU0I3Rfuv00xpZFAJTX'; // Replace with your actual test secret key $stripe_publishable_key = 'pk_test_UVDCVj9ewbGrZ9gAa36cJqzU000O89GtZ4'; // Replace with your actual test publishable key // Allowed Origins $allowed_origins = ['https://authentica.com']; // Enable CORS $origin = $_SERVER['HTTP_ORIGIN'] ?? ''; if (in_array($origin, $allowed_origins)) { header("Access-Control-Allow-Origin: $origin"); } header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); header("Access-Control-Allow-Headers: Content-Type"); // Handle preflight OPTIONS request if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } // Validate request origin if (isset($_SERVER['HTTP_ORIGIN']) && !in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)) { header('Content-Type: application/json'); http_response_code(403); echo json_encode(['error' => 'Origin not allowed']); exit; } // CSRF Token Handling if (isset($_GET['action']) && $_GET['action'] === 'get_token') { ob_clean(); $token = bin2hex(random_bytes(32)); $_SESSION['csrf_token'] = $token; $_SESSION['csrf_token_time'] = time(); $_SESSION['csrf_token_hash'] = hash('sha256', $token . $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR']); header('Content-Type: application/json'); header('X-Content-Type-Options: nosniff'); header('X-Frame-Options: DENY'); echo json_encode(['csrf_token' => $token]); error_log("CSRF token generated for application payment"); exit; } // Rate limiting $rate_limit_key = 'app_payment_rate_' . md5($_SERVER['REMOTE_ADDR']); $rate_limit_time = 'app_payment_time_' . md5($_SERVER['REMOTE_ADDR']); $max_requests = 5; $time_period = 900; // 15 minutes if (isset($_SESSION[$rate_limit_key])) { if (time() - $_SESSION[$rate_limit_time] > $time_period) { $_SESSION[$rate_limit_key] = 1; $_SESSION[$rate_limit_time] = time(); } else { $_SESSION[$rate_limit_key]++; if ($_SESSION[$rate_limit_key] > $max_requests) { header('Content-Type: application/json'); http_response_code(429); echo json_encode(['error' => 'Too many payment requests. Try again later.']); exit; } } } else { $_SESSION[$rate_limit_key] = 1; $_SESSION[$rate_limit_time] = time(); } // Get request data $request_body = file_get_contents("php://input"); $decoded_input = json_decode($request_body, true); // Input sanitization function sanitizeInput($input) { if (is_array($input)) { $sanitized = []; foreach ($input as $key => $value) { $sanitizedKey = preg_replace('/[^a-zA-Z0-9_]/', '', $key); $sanitized[$sanitizedKey] = is_array($value) ? sanitizeInput($value) : filter_var(trim($value), FILTER_SANITIZE_STRING); } return $sanitized; } return filter_var($input, FILTER_SANITIZE_STRING); } // Sanitize input data if ($decoded_input) { $decoded_input = sanitizeInput($decoded_input); error_log("Application payment request: " . json_encode($decoded_input)); } // Check for Stripe webhook $is_stripe_webhook = false; $headers = getallheaders(); if (isset($headers['Stripe-Signature'])) { $is_stripe_webhook = true; } // Validate CSRF token (if not a webhook) if (!$is_stripe_webhook) { if (!isset($decoded_input['csrf_token']) || !isset($_SESSION['csrf_token']) || !isset($_SESSION['csrf_token_hash']) || $decoded_input['csrf_token'] !== $_SESSION['csrf_token'] || $_SESSION['csrf_token_hash'] !== hash('sha256', $_SESSION['csrf_token'] . $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR']) || (time() - $_SESSION['csrf_token_time'] > 1800)) { error_log("CSRF token validation failed for application payment"); header('Content-Type: application/json'); http_response_code(403); echo json_encode(['error' => 'Invalid or expired CSRF token']); exit; } } // Handle Stripe webhook for payment confirmation if ($is_stripe_webhook) { // Include Stripe library using the same path as your working code require_once(__DIR__ . '/../authentica-prgrm-r2r/stripe-lib/stripe-php-master/init.php'); \Stripe\Stripe::setApiKey($stripe_secret_key); try { $event = \Stripe\Webhook::constructEvent( $request_body, $headers['Stripe-Signature'], STRIPE_WEBHOOK_SECRET ); if ($event->type == 'checkout.session.completed') { $session = $event->data->object; // Update payment status in your system error_log('Application payment completed: ' . $session->id); // You can add logic here to update the lead status in Zoho CRM // indicating payment was successful http_response_code(200); echo json_encode(['status' => 'payment_success']); exit; } else { http_response_code(200); echo json_encode(['status' => 'event_received']); exit; } } catch (\Exception $e) { error_log("Webhook error: " . $e->getMessage()); http_response_code(500); echo json_encode(['error' => $e->getMessage()]); exit; } } // Handle payment processing if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($decoded_input['payment_type']) && $decoded_input['payment_type'] === 'application_fee') { error_log("Processing application fee payment"); // Validate required fields if (empty($decoded_input['First_Name']) || empty($decoded_input['Last_Name']) || empty($decoded_input['Email'])) { header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Missing required customer information']); exit; } // Validate email if (!filter_var($decoded_input['Email'], FILTER_VALIDATE_EMAIL)) { header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Invalid email address']); exit; } // Validate amount (should be $50) $amount = isset($decoded_input['amount']) ? intval($decoded_input['amount']) : 50; if ($amount !== 50) { header('Content-Type: application/json'); echo json_encode(['success' => false, 'error' => 'Invalid payment amount']); exit; } // Include Stripe library using the same path as your working code require_once(__DIR__ . '/../authentica-prgrm-r2r/stripe-lib/stripe-php-master/init.php'); \Stripe\Stripe::setApiKey($stripe_secret_key); try { error_log("Creating Stripe customer for application payment"); // Create Stripe Customer $customer = \Stripe\Customer::create([ 'name' => $decoded_input['First_Name'] . ' ' . $decoded_input['Last_Name'], 'email' => $decoded_input['Email'], 'metadata' => [ 'lead_id' => $decoded_input['lead_id'] ?? '', 'application_type' => 'study_abroad', ] ]); error_log("Creating checkout session for application fee"); // Create Checkout Session $session = \Stripe\Checkout\Session::create([ 'customer' => $customer->id, 'payment_method_types' => ['card'], 'line_items' => [[ 'price_data' => [ 'currency' => 'usd', 'unit_amount' => $amount * 100, // Convert to cents 'product_data' => [ 'name' => 'Study Abroad Application Fee', 'description' => 'Processing fee for study abroad program application', ], ], 'quantity' => 1, ]], 'mode' => 'payment', 'success_url' => 'https://authentica.com/payment-confirmation/?session_id={CHECKOUT_SESSION_ID}', 'cancel_url' => 'https://authentica.com/apply-now-test/?payment_status=cancelled', 'metadata' => [ 'customer_name' => $decoded_input['First_Name'] . ' ' . $decoded_input['Last_Name'], 'customer_email' => $decoded_input['Email'], 'lead_id' => $decoded_input['lead_id'] ?? '', 'payment_type' => 'application_fee', 'program_location' => $decoded_input['Program_Location'] ?? '', 'program_name' => $decoded_input['Program_Name'] ?? '', ], ]); error_log("Application payment session created: " . $session->id); // Return success response header('Content-Type: application/json'); echo json_encode([ 'success' => true, 'payment_url' => $session->url, 'session_id' => $session->id ]); exit; // Add exit to prevent further execution } catch (\Stripe\Exception\ApiErrorException $e) { error_log("Stripe API error for application payment: " . $e->getMessage()); header('Content-Type: application/json'); http_response_code(500); echo json_encode(['success' => false, 'error' => 'Payment system error: ' . $e->getMessage()]); exit; } catch (\Exception $e) { error_log("General error in application payment: " . $e->getMessage()); header('Content-Type: application/json'); http_response_code(500); echo json_encode(['success' => false, 'error' => 'Error processing payment: ' . $e->getMessage()]); exit; } } // Invalid request header('Content-Type: application/json'); http_response_code(400); echo json_encode(['error' => 'Invalid request']); exit; ?>