T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/soundstudiopro.com/private_html/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/private_html/process_credit_payment.php
<?php
session_start();
require_once 'config/database.php';
require_once 'config/email.php';
require_once 'utils/subscription_helpers.php';
require_once 'includes/translations.php';

// Enable error logging
error_log("process_credit_payment.php called at " . date('Y-m-d H:i:s'));

// Set content type to JSON
header('Content-Type: application/json');

// Check if user is logged in
if (!isset($_SESSION['user_id'])) {
    error_log("process_credit_payment.php: User not logged in");
    echo json_encode(['success' => false, 'error' => 'User not logged in']);
    exit;
}

// Get POST data first to check what type of purchase this is
$input = json_decode(file_get_contents('php://input'), true);
$action = $input['action'] ?? '';

// IMPORTANT: Credit purchases require active subscription (minimum Essential $5/month)
// BUT: Track and ticket purchases do NOT require subscription - only credit card payment
// Check if this is a credit purchase before requiring subscription
$requires_subscription_check = false;
if ($action === 'create_payment_intent' || $action === 'process_paypal_payment') {
    // These actions are for credit purchases only
    $requires_subscription_check = true;
} elseif ($action === 'process_cart_payment') {
    // Check cart contents to see if there are credit items
    $cart_data = $input['cart'] ?? [];
    if (!empty($cart_data)) {
        // Check if cart has credit items
        if (isset($cart_data['credits']) && !empty($cart_data['credits'])) {
            $requires_subscription_check = true;
        } elseif (is_array($cart_data) && !empty($cart_data) && isset($cart_data[0]['package'])) {
            // Legacy format - all items are credits
            $requires_subscription_check = true;
        }
        // If cart only has tracks or tickets, no subscription required
    }
}

// Only check subscription if this is a credit purchase
if ($requires_subscription_check) {
    $has_active_subscription = hasActiveSubscription($_SESSION['user_id']);
    if ($has_active_subscription === false) {
        error_log("process_credit_payment.php: User " . $_SESSION['user_id'] . " attempted credit purchase without active subscription");
        echo json_encode([
            'success' => false, 
            'error' => t('checkout.subscription_required_error'),
            'message' => t('checkout.subscription_required_message'),
            'requires_subscription' => true,
            'subscription_url' => '/account_settings.php?tab=subscription'
        ]);
        exit;
    }
}

error_log("process_credit_payment.php: Action = '$action', Input = " . json_encode($input));

// Stripe configuration
$stripe_secret_key = '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';

// Credit package configurations
$credit_packages = [
    'starter' => [
        'name' => 'Starter',
        'credits' => 30,
        'price' => 1999, // $19.99 in cents
        'stripe_price_id' => 'price_starter_credits'
    ],
    'pro' => [
        'name' => 'Pro',
        'credits' => 200,
        'price' => 5900, // $59.00 in cents
        'stripe_price_id' => 'price_pro_credits'
    ],
    'premium' => [
        'name' => 'Premium',
        'credits' => 500,
        'price' => 12900, // $129.00 in cents
        'stripe_price_id' => 'price_premium_credits'
    ]
];

// Add shutdown handler to catch fatal errors and log them
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        $log = date('Y-m-d H:i:s') . " FATAL: {$error['message']} in {$error['file']} on line {$error['line']}\n";
        file_put_contents(__DIR__ . '/payment_errors.log', $log, FILE_APPEND);
        if (!headers_sent()) {
            header('Content-Type: application/json');
        }
        echo json_encode(['success' => false, 'error' => 'Server error: ' . $error['message']]);
        exit;
    }
});

try {
    switch ($action) {
        case 'create_payment_intent':
            handleCreatePaymentIntent($input, $credit_packages, $stripe_secret_key);
            break;
            
        case 'process_cart_payment':
            handleCartPayment($input, $credit_packages, $stripe_secret_key);
            break;
            
        case 'confirm_payment':
            handleConfirmPayment($input, $stripe_secret_key);
            break;
            
        case 'process_paypal_payment':
            handlePayPalPayment($input, $credit_packages);
            break;
            
        default:
            echo json_encode(['success' => false, 'error' => 'Invalid action']);
            break;
    }
} catch (Exception $e) {
    // Log error
    error_log("Credit payment error: " . $e->getMessage());
    echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}

function handleCreatePaymentIntent($input, $credit_packages, $stripe_secret_key) {
    // IMPORTANT: Credit purchases require active subscription (minimum Essential $5/month)
    $has_active_subscription = hasActiveSubscription($_SESSION['user_id']);
    if ($has_active_subscription === false) {
        error_log("handleCreatePaymentIntent: User " . $_SESSION['user_id'] . " attempted credit purchase without active subscription");
        echo json_encode([
            'success' => false, 
            'error' => t('checkout.subscription_required_error'),
            'message' => t('checkout.subscription_required_message'),
            'requires_subscription' => true,
            'subscription_url' => '/account_settings.php?tab=subscription'
        ]);
        exit;
    }
    
    $package_id = $input['package'] ?? '';
    $quantity = $input['quantity'] ?? 1;
    
    if (!isset($credit_packages[$package_id])) {
        throw new Exception('Invalid package selected');
    }
    
    $package = $credit_packages[$package_id];
    $total_amount = $package['price'] * $quantity;
    $total_credits = $package['credits'] * $quantity;
    
    // Create Stripe payment intent
    $ch = curl_init();
    
    curl_setopt($ch, CURLOPT_URL, 'https://api.stripe.com/v1/payment_intents');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $stripe_secret_key,
        'Content-Type: application/x-www-form-urlencoded'
    ]);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'amount' => $total_amount,
        'currency' => 'usd',
        'metadata' => json_encode([
            'user_id' => $_SESSION['user_id'],
            'package' => $package_id,
            'credits' => $total_credits,
            'quantity' => $quantity,
            'subscription_period' => '30_days'
        ])
    ]));
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curl_error = curl_error($ch);
    
    curl_close($ch);
    
    if ($curl_error) {
        throw new Exception('cURL Error: ' . $curl_error);
    }
    
    if ($http_code !== 200) {
        $error_data = json_decode($response, true);
        $error_message = $error_data['error']['message'] ?? 'HTTP Error: ' . $http_code;
        throw new Exception($error_message);
    }
    
    $payment_intent = json_decode($response, true);
    
    // Log payment intent creation
    logPaymentEvent('payment_intent_created', [
        'user_id' => $_SESSION['user_id'],
        'package' => $package_id,
        'credits' => $total_credits,
        'amount' => $total_amount,
        'payment_intent_id' => $payment_intent['id']
    ]);
    
    echo json_encode([
        'success' => true,
        'client_secret' => $payment_intent['client_secret'],
        'payment_intent_id' => $payment_intent['id'],
        'amount' => $total_amount,
        'credits' => $total_credits
    ]);
}

function processFreeOrder($track_items, $user_id, $ticket_items = []) {
    try {
        $pdo = getDBConnection();
        $pdo->beginTransaction();
        
        $processed_tracks = [];
        
        foreach ($track_items as $item) {
            $track_id = $item['track_id'];
            $quantity = $item['quantity'] ?? 1;
            
            // Get track details from database
            $stmt = $pdo->prepare("
                SELECT 
                    mt.id,
                    mt.title,
                    mt.price,
                    mt.user_id as artist_id,
                    u.name as artist_name,
                    u.plan as artist_plan
                FROM music_tracks mt
                JOIN users u ON mt.user_id = u.id
                WHERE mt.id = ? AND mt.status = 'complete'
            ");
            $stmt->execute([$track_id]);
            $track = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$track) {
                throw new Exception("Track not found: $track_id");
            }
            
            // Check if user already purchased this track
            $stmt = $pdo->prepare("
                SELECT id FROM track_purchases 
                WHERE user_id = ? AND track_id = ?
            ");
            $stmt->execute([$user_id, $track_id]);
            
            if ($stmt->fetch()) {
                // Track already purchased, skip
                continue;
            }
            
            $track_price = floatval($track['price']);
            $is_free_user_track = (strtolower($track['artist_plan']) === 'free');
            $revenue_recipient = $is_free_user_track ? 'platform' : 'artist';
            $recipient_id = $is_free_user_track ? 1 : $track['artist_id'];
            
            // Record sale
            $stmt = $pdo->prepare("
                INSERT INTO sales (
                    track_id, buyer_id, artist_id, amount, quantity, 
                    revenue_recipient, recipient_id, is_free_user_track, 
                    created_at
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW())
            ");
            $stmt->execute([
                $track_id,
                $user_id,
                $track['artist_id'],
                $track_price,
                $quantity,
                $revenue_recipient,
                $recipient_id,
                $is_free_user_track ? 1 : 0
            ]);
            
            // Record purchase
            $stmt = $pdo->prepare("
                INSERT INTO track_purchases (user_id, track_id, price_paid, credits_used, payment_method)
                VALUES (?, ?, ?, 0, 'free')
            ");
            $stmt->execute([$user_id, $track_id, $track_price]);
            $purchase_id = $pdo->lastInsertId();
            
            // Notify artist of the purchase
            require_once __DIR__ . '/utils/artist_notifications.php';
            notifyArtistOfTrackPurchase(
                $track['artist_id'],
                $track_id,
                $user_id,
                $track_price,
                $purchase_id
            );
            
            // Add to user's library
            $stmt = $pdo->prepare("
                INSERT IGNORE INTO user_library (user_id, track_id, purchase_date)
                VALUES (?, ?, NOW())
            ");
            $stmt->execute([$user_id, $track_id]);
            
            $processed_tracks[] = [
                'track_id' => $track_id,
                'title' => $track['title'],
                'artist_name' => $track['artist_name'],
                'price_paid' => $track_price
            ];
        }
        
        // Process free tickets
        $processed_tickets = [];
        if (!empty($ticket_items)) {
            foreach ($ticket_items as $ticket_item) {
                if (!isset($ticket_item['event_id']) || !$ticket_item['is_free']) {
                    continue; // Skip paid tickets or invalid items
                }
                
                $event_id = $ticket_item['event_id'];
                $quantity = $ticket_item['quantity'] ?? 1;
                
                // Create tickets
                for ($i = 0; $i < $quantity; $i++) {
                    $ticket_code = 'EVT-' . strtoupper(substr(md5($event_id . $user_id . time() . $i), 0, 12));
                    $qr_data = json_encode([
                        'ticket_code' => $ticket_code,
                        'event_id' => $event_id,
                        'user_id' => $user_id,
                        'timestamp' => time()
                    ]);
                    
                    $stmt = $pdo->prepare("
                        INSERT INTO event_tickets (
                            event_id, user_id, ticket_code, qr_code_data, 
                            price_paid, payment_method, status
                        ) VALUES (?, ?, ?, ?, ?, 'free', 'confirmed')
                    ");
                    $stmt->execute([
                        $event_id,
                        $user_id,
                        $ticket_code,
                        $qr_data,
                        0
                    ]);
                    
                    $processed_tickets[] = [
                        'event_id' => $event_id,
                        'ticket_code' => $ticket_code
                    ];
                }
                
                // Update event attendee count
                $stmt = $pdo->prepare("
                    INSERT INTO event_attendees (event_id, user_id, status)
                    VALUES (?, ?, 'attending')
                    ON DUPLICATE KEY UPDATE status = 'attending'
                ");
                $stmt->execute([$event_id, $user_id]);
            }
        }
        
        // Clear cart from session
        if (isset($_SESSION['cart'])) {
            $_SESSION['cart'] = [];
        }
        if (isset($_SESSION['credit_cart'])) {
            $_SESSION['credit_cart'] = [];
        }
        if (isset($_SESSION['ticket_cart'])) {
            $_SESSION['ticket_cart'] = [];
        }
        
        $pdo->commit();
        
        // Log free order processing
        logPaymentEvent('free_order_processed', [
            'user_id' => $user_id,
            'tracks_processed' => count($processed_tracks),
            'track_ids' => array_column($processed_tracks, 'track_id'),
            'tickets_processed' => count($processed_tickets),
            'ticket_event_ids' => array_unique(array_column($processed_tickets, 'event_id'))
        ]);
        
        // Return success response indicating free order
        echo json_encode([
            'success' => true,
            'is_free_order' => true,
            'message' => 'Free order processed successfully!',
            'tracks' => $processed_tracks,
            'tickets' => $processed_tickets,
            'client_secret' => null // No payment needed
        ]);
        
    } catch (Exception $e) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }
        error_log("processFreeOrder: Exception: " . $e->getMessage());
        echo json_encode(['success' => false, 'error' => 'Error processing free order: ' . $e->getMessage()]);
    }
}

function handleCartPayment($input, $credit_packages, $stripe_secret_key) {
    try {
        error_log("handleCartPayment called with input: " . json_encode($input));
        
        $cart_data = $input['cart'] ?? [];
        
        if (empty($cart_data)) {
            error_log("handleCartPayment: Cart is empty");
            echo json_encode(['success' => false, 'error' => 'Cart is empty']);
            return;
        }
        
        // Handle different cart formats
        $credit_items = [];
        $track_items = [];
        $ticket_items = [];
        
        if (isset($cart_data['credits']) || isset($cart_data['tracks']) || isset($cart_data['tickets'])) {
            // New mixed cart format with credits, tracks, and tickets properties
            $credit_items = $cart_data['credits'] ?? [];
            $track_items = $cart_data['tracks'] ?? [];
            $ticket_items = $cart_data['tickets'] ?? [];
        } elseif (is_array($cart_data) && !empty($cart_data) && isset($cart_data[0]['package'])) {
            // Frontend is sending credit items array directly
            $credit_items = $cart_data;
            $track_items = [];
            $ticket_items = [];
        } else {
            // Legacy format - assume all items are credits
            $credit_items = $cart_data;
            $track_items = [];
            $ticket_items = [];
        }
        
        error_log("handleCartPayment: Credit items = " . json_encode($credit_items));
        error_log("handleCartPayment: Track items = " . json_encode($track_items));
        error_log("handleCartPayment: Ticket items = " . json_encode($ticket_items));
        
        // IMPORTANT: If cart contains credit items, subscription is required
        // Track and ticket purchases do NOT require subscription - only credit card payment
        if (!empty($credit_items)) {
            $has_active_subscription = hasActiveSubscription($_SESSION['user_id']);
            if ($has_active_subscription === false) {
                error_log("handleCartPayment: User " . $_SESSION['user_id'] . " attempted credit purchase without active subscription");
                echo json_encode([
                    'success' => false, 
                    'error' => t('checkout.subscription_required_error'),
                    'message' => t('checkout.subscription_required_message'),
                    'requires_subscription' => true,
                    'subscription_url' => '/account_settings.php?tab=subscription'
                ]);
                return;
            }
        }
        
        // Calculate total amount and credits
        $total_amount = 0;
        $total_credits = 0;
        $cart_summary = [];
        
        // Process credit items
        foreach ($credit_items as $item) {
            if (!isset($item['package']) || !isset($item['quantity'])) {
                error_log("handleCartPayment: Missing package or quantity in credit item: " . json_encode($item));
                echo json_encode(['success' => false, 'error' => 'Malformed credit item in cart']);
                return;
            }
            $package_id = $item['package'];
            $quantity = $item['quantity'];
            
            if (!isset($credit_packages[$package_id])) {
                error_log("handleCartPayment: Invalid package in cart: $package_id");
                echo json_encode(['success' => false, 'error' => 'Invalid package in cart: ' . $package_id]);
                return;
            }
            
            $package = $credit_packages[$package_id];
            $item_total = $package['price'] * $quantity;
            $item_credits = $package['credits'] * $quantity;
            
            $total_amount += $item_total;
            $total_credits += $item_credits;
            
            $cart_summary[] = [
                'type' => 'credit',
                'package' => $package_id,
                'name' => $package['name'],
                'credits' => $item_credits,
                'quantity' => $quantity,
                'amount' => $item_total
            ];
        }
        
        // Process track items
        foreach ($track_items as $item) {
            if (!isset($item['track_id']) || !isset($item['title']) || !isset($item['price'])) {
                error_log("handleCartPayment: Missing fields in track item: " . json_encode($item));
                echo json_encode(['success' => false, 'error' => 'Malformed track item in cart']);
                return;
            }
            $track_price = $item['price'] * 100; // Convert to cents
            $quantity = $item['quantity'] ?? 1;
            $item_total = $track_price * $quantity;
            
            $total_amount += $item_total;
            
            $cart_summary[] = [
                'type' => 'track',
                'track_id' => $item['track_id'],
                'title' => $item['title'],
                'artist' => $item['artist_name'] ?? $item['artist'] ?? 'Unknown Artist',
                'quantity' => $quantity,
                'amount' => $item_total
            ];
        }
        
        // Process ticket items
        foreach ($ticket_items as $item) {
            if (!isset($item['event_id']) || !isset($item['ticket_price'])) {
                error_log("handleCartPayment: Missing fields in ticket item: " . json_encode($item));
                echo json_encode(['success' => false, 'error' => 'Malformed ticket item in cart']);
                return;
            }
            $ticket_price = $item['ticket_price'] * 100; // Convert to cents
            $quantity = $item['quantity'] ?? 1;
            $item_total = $ticket_price * $quantity;
            
            // Only add to total if not free
            if (!$item['is_free']) {
                $total_amount += $item_total;
            }
            
            $cart_summary[] = [
                'type' => 'ticket',
                'event_id' => $item['event_id'],
                'event_title' => $item['event_title'] ?? 'Event Ticket',
                'ticket_price' => $item['ticket_price'],
                'is_free' => $item['is_free'] ?? false,
                'quantity' => $quantity,
                'amount' => $item_total
            ];
        }
        
        // Get billing address data
        $billing_address = $input['billing_address'] ?? [];
        
        // Check if this is a free order (total amount is 0 and there are track items or free tickets)
        if ($total_amount == 0 && (!empty($track_items) || !empty($ticket_items))) {
            // Process free order directly without Stripe
            processFreeOrder($track_items, $_SESSION['user_id'], $ticket_items);
            return; // Exit after processing free order
        }
        
        // If total is 0 but no track/ticket items, something is wrong
        if ($total_amount == 0 && empty($track_items) && empty($credit_items) && empty($ticket_items)) {
            error_log("handleCartPayment: Cart total is 0 with no items");
            echo json_encode(['success' => false, 'error' => 'Invalid cart: total is 0 with no items']);
            return;
        }
        
        // Create Stripe payment intent for cart
        $ch = curl_init();
        
        curl_setopt($ch, CURLOPT_URL, 'https://api.stripe.com/v1/payment_intents');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Authorization: Bearer ' . $stripe_secret_key,
            'Content-Type: application/x-www-form-urlencoded'
        ]);
        
        // Prepare payment intent data
        // Stripe metadata has a 500 character limit per field
        // Store minimal cart data (IDs, quantities, amounts only) to stay under limit
        // Full cart details are stored in database via storeCartSnapshot()
        $minimal_cart = [];
        foreach ($cart_summary as $item) {
            $minimal_cart[] = [
                't' => $item['type'], // 'track', 'credit', or 'ticket'
                'i' => $item['type'] === 'track' ? $item['track_id'] : ($item['type'] === 'ticket' ? $item['event_id'] : $item['package']),
                'q' => $item['quantity'],
                'a' => $item['amount']
            ];
        }
        $cart_items_json = json_encode($minimal_cart);
        
        // If still too long, split into multiple fields
        $payment_intent_data = [
            'amount' => $total_amount,
            'currency' => 'usd',
            'metadata[user_id]' => $_SESSION['user_id'],
            'metadata[total_credits]' => $total_credits,
            'metadata[has_tracks]' => !empty($track_items) ? 'true' : 'false',
            'metadata[has_tickets]' => !empty($ticket_items) ? 'true' : 'false',
            'metadata[subscription_period]' => '30_days',
            'metadata[payment_type]' => 'mixed_cart_checkout'
        ];
        
        // Handle cart_items metadata - split if too long
        if (strlen($cart_items_json) <= 500) {
            // Fits in one field
            $payment_intent_data['metadata[cart_items]'] = $cart_items_json;
        } else {
            // Still too long - split into chunks
            $chunks = str_split($cart_items_json, 450); // Leave room for field name
            for ($i = 0; $i < count($chunks); $i++) {
                $payment_intent_data["metadata[cart_items_" . ($i + 1) . "]"] = $chunks[$i];
            }
            $payment_intent_data['metadata[cart_items_count]'] = count($chunks);
        }
        
        // Add billing address if provided
        if (!empty($billing_address)) {
            $payment_intent_data['metadata[billing_name]'] = ($billing_address['billing_first_name'] ?? '') . ' ' . ($billing_address['billing_last_name'] ?? '');
            $payment_intent_data['metadata[billing_email]'] = $billing_address['billing_email'] ?? '';
            $payment_intent_data['metadata[billing_address]'] = $billing_address['billing_address'] ?? '';
            $payment_intent_data['metadata[billing_city]'] = $billing_address['billing_city'] ?? '';
            $payment_intent_data['metadata[billing_state]'] = $billing_address['billing_state'] ?? '';
            $payment_intent_data['metadata[billing_zip]'] = $billing_address['billing_zip'] ?? '';
            $payment_intent_data['metadata[billing_country]'] = $billing_address['billing_country'] ?? '';
        }
        
        // Log BEFORE creating payment intent
        $before_pi_log = [
            'timestamp' => date('Y-m-d H:i:s'),
            'action' => 'before_create_payment_intent',
            'user_id' => $_SESSION['user_id'],
            'total_amount' => $total_amount,
            'total_credits' => $total_credits,
            'cart_items_count' => count($cart_summary),
                'track_items_count' => count($track_items),
                'credit_items_count' => count($credit_items),
                'ticket_items_count' => count($ticket_items),
            'cart_summary' => $cart_summary,
            'track_items' => $track_items,
            'credit_items' => $credit_items
        ];
        $before_pi_log_file = __DIR__ . '/logs/cart_payment_detailed.log';
        if (!is_dir(__DIR__ . '/logs')) {
            mkdir(__DIR__ . '/logs', 0755, true);
        }
        file_put_contents($before_pi_log_file, json_encode($before_pi_log) . "\n", FILE_APPEND | LOCK_EX);
        
        // Store cart snapshot BEFORE creating payment intent (for validation)
        // We'll store it after we get the payment_intent_id
        
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($payment_intent_data));
        
        $response = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curl_error = curl_error($ch);
        
        curl_close($ch);
        
        if ($curl_error) {
            $error_log = [
                'timestamp' => date('Y-m-d H:i:s'),
                'action' => 'create_payment_intent_curl_error',
                'user_id' => $_SESSION['user_id'],
                'error' => $curl_error,
                'cart_summary' => $cart_summary
            ];
            file_put_contents($before_pi_log_file, json_encode($error_log) . "\n", FILE_APPEND | LOCK_EX);
            error_log("handleCartPayment: cURL error: $curl_error");
            echo json_encode(['success' => false, 'error' => 'cURL Error: ' . $curl_error]);
            return;
        }
        
        if ($http_code !== 200) {
            $error_data = json_decode($response, true);
            $error_message = $error_data['error']['message'] ?? 'HTTP Error: ' . $http_code;
            
            $error_log = [
                'timestamp' => date('Y-m-d H:i:s'),
                'action' => 'create_payment_intent_stripe_error',
                'user_id' => $_SESSION['user_id'],
                'http_code' => $http_code,
                'error' => $error_message,
                'stripe_response' => $error_data,
                'cart_summary' => $cart_summary
            ];
            file_put_contents($before_pi_log_file, json_encode($error_log) . "\n", FILE_APPEND | LOCK_EX);
            
            error_log("handleCartPayment: Stripe API error: $error_message");
            echo json_encode(['success' => false, 'error' => $error_message]);
            return;
        }
        
        $payment_intent = json_decode($response, true);
        
        // Store cart snapshot NOW that we have payment_intent_id
        if (isset($payment_intent['id'])) {
            try {
                require_once __DIR__ . '/webhooks/purchase_validation.php';
                storeCartSnapshot($_SESSION['user_id'], $cart_summary, $payment_intent['id']);
            } catch (Exception $e) {
                error_log("Failed to store cart snapshot: " . $e->getMessage());
            }
        }
        
        // Log AFTER creating payment intent
        $after_pi_log = [
            'timestamp' => date('Y-m-d H:i:s'),
            'action' => 'after_create_payment_intent',
            'user_id' => $_SESSION['user_id'],
            'payment_intent_id' => $payment_intent['id'],
            'client_secret' => $payment_intent['client_secret'] ?? null,
            'amount' => $total_amount,
            'status' => $payment_intent['status'] ?? 'unknown',
            'cart_summary' => $cart_summary,
            'metadata_sent' => [
                'user_id' => $_SESSION['user_id'],
                'cart_items' => $cart_summary,
                'total_credits' => $total_credits,
                'has_tracks' => !empty($track_items) ? 'true' : 'false',
                'payment_type' => 'mixed_cart_checkout'
            ]
        ];
        file_put_contents($before_pi_log_file, json_encode($after_pi_log) . "\n", FILE_APPEND | LOCK_EX);
        
        // Log cart payment intent creation
        logPaymentEvent('cart_payment_intent_created', [
            'user_id' => $_SESSION['user_id'],
            'cart_items' => $cart_summary,
            'total_credits' => $total_credits,
            'amount' => $total_amount,
            'payment_intent_id' => $payment_intent['id']
        ]);
        
        // Store payment data in session for email confirmation
        $_SESSION['last_payment_data'] = [
            'order_details' => [
                'total_amount' => $total_amount,
                'cart_summary' => $cart_summary,
                'payment_intent_id' => $payment_intent['id']
            ],
            'billing_address' => $billing_address
        ];
        
        $response_data = [
            'success' => true,
            'client_secret' => $payment_intent['client_secret'],
            'payment_intent_id' => $payment_intent['id'],
            'amount' => $total_amount,
            'credits' => $total_credits,
            'cart_summary' => $cart_summary
        ];
        
        error_log("handleCartPayment: Returning success response: " . json_encode($response_data));
        echo json_encode($response_data);
    } catch (Exception $e) {
        error_log("handleCartPayment: Exception: " . $e->getMessage());
        echo json_encode(['success' => false, 'error' => 'Server error: ' . $e->getMessage()]);
    }
}

function handleConfirmPayment($input, $stripe_secret_key) {
    $payment_intent_id = $input['payment_intent_id'] ?? '';
    
    if (empty($payment_intent_id)) {
        throw new Exception('Payment intent ID is required');
    }
    
    // Retrieve payment intent from Stripe
    $ch = curl_init();
    
    curl_setopt($ch, CURLOPT_URL, 'https://api.stripe.com/v1/payment_intents/' . $payment_intent_id);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $stripe_secret_key
    ]);
    
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curl_error = curl_error($ch);
    
    curl_close($ch);
    
    if ($curl_error) {
        throw new Exception('cURL Error: ' . $curl_error);
    }
    
    if ($http_code !== 200) {
        $error_data = json_decode($response, true);
        $error_message = $error_data['error']['message'] ?? 'HTTP Error: ' . $http_code;
        throw new Exception($error_message);
    }
    
    $payment_intent = json_decode($response, true);
    
    // Check if payment was successful
    if ($payment_intent['status'] !== 'succeeded') {
        throw new Exception('Payment not completed. Status: ' . $payment_intent['status']);
    }
    
    // Extract metadata
    $metadata = json_decode($payment_intent['metadata']['metadata'] ?? '{}', true);
    $user_id = $metadata['user_id'] ?? $_SESSION['user_id'];
    $credits = $metadata['credits'] ?? $metadata['total_credits'] ?? 0;
    $package = $metadata['package'] ?? 'unknown';
    
    // Add credits to user account
    $current_credits = $_SESSION['credits'] ?? 0;
    $new_credits = $current_credits + $credits;
    $_SESSION['credits'] = $new_credits;
    
    // Update user credits in database (you'll need to implement this)
    updateUserCredits($user_id, $new_credits);
    
    // Log successful payment
    logPaymentEvent('payment_succeeded', [
        'user_id' => $user_id,
        'payment_intent_id' => $payment_intent_id,
        'credits_added' => $credits,
        'total_credits' => $new_credits,
        'amount' => $payment_intent['amount'],
        'package' => $package
    ]);
    
    echo json_encode([
        'success' => true,
        'credits_added' => $credits,
        'total_credits' => $new_credits,
        'payment_intent_id' => $payment_intent_id
    ]);
}

// updateUserCredits function is already defined in config/database.php

function logPaymentEvent($event_type, $data) {
    $log_entry = [
        'timestamp' => date('Y-m-d H:i:s'),
        'event_type' => $event_type,
        'data' => $data
    ];
    
    $log_file = __DIR__ . '/logs/credit_payments.log';
    file_put_contents($log_file, json_encode($log_entry) . "\n", FILE_APPEND | LOCK_EX);
}

function handlePayPalPayment($input, $credit_packages) {
    // IMPORTANT: Credit purchases require active subscription (minimum Essential $5/month)
    $has_active_subscription = hasActiveSubscription($_SESSION['user_id']);
    if ($has_active_subscription === false) {
        error_log("handlePayPalPayment: User " . $_SESSION['user_id'] . " attempted credit purchase without active subscription");
        echo json_encode([
            'success' => false, 
            'error' => t('checkout.subscription_required_error'),
            'message' => t('checkout.subscription_required_message'),
            'requires_subscription' => true,
            'subscription_url' => '/account_settings.php?tab=subscription'
        ]);
        exit;
    }
    
    $cart_data = $input['cart'] ?? [];
    
    if (empty($cart_data)) {
        throw new Exception('Cart is empty');
    }
    
    // Handle different cart formats (same as handleCartPayment)
    $credit_items = [];
    $track_items = [];
    
    if (isset($cart_data['credits']) && isset($cart_data['tracks'])) {
        // New mixed cart format with credits and tracks properties
        $credit_items = $cart_data['credits'] ?? [];
        $track_items = $cart_data['tracks'] ?? [];
    } elseif (is_array($cart_data) && !empty($cart_data) && isset($cart_data[0]['package'])) {
        // Frontend is sending credit items array directly
        $credit_items = $cart_data;
        $track_items = [];
    } else {
        // Legacy format - assume all items are credits
        $credit_items = $cart_data;
        $track_items = [];
    }
    
    // Double-check subscription for credit items
    if (!empty($credit_items) && $has_active_subscription === false) {
        error_log("handlePayPalPayment: Credit items in cart but no active subscription");
        echo json_encode([
            'success' => false, 
            'error' => t('checkout.subscription_required_error'),
            'message' => t('checkout.subscription_required_for_credits'),
            'requires_subscription' => true,
            'subscription_url' => '/account_settings.php?tab=subscription'
        ]);
        exit;
    }
    
    error_log("handlePayPalPayment: Credit items = " . json_encode($credit_items));
    error_log("handlePayPalPayment: Track items = " . json_encode($track_items));
    
    // Calculate total amount and credits
    $total_amount = 0;
    $total_credits = 0;
    $cart_summary = [];
    
    // Process credit items
    foreach ($credit_items as $item) {
        if (!isset($item['package']) || !isset($item['quantity'])) {
            error_log("handlePayPalPayment: Missing package or quantity in credit item: " . json_encode($item));
            throw new Exception('Malformed credit item in cart');
        }
        
        $package_id = $item['package'];
        $quantity = $item['quantity'];
        
        if (!isset($credit_packages[$package_id])) {
            throw new Exception('Invalid package in cart: ' . $package_id);
        }
        
        $package = $credit_packages[$package_id];
        $item_total = $package['price'] * $quantity;
        $item_credits = $package['credits'] * $quantity;
        
        $total_amount += $item_total;
        $total_credits += $item_credits;
        
        $cart_summary[] = [
            'type' => 'credit',
            'package' => $package_id,
            'name' => $package['name'],
            'credits' => $item_credits,
            'quantity' => $quantity,
            'amount' => $item_total
        ];
    }
    
    // Process track items
    foreach ($track_items as $item) {
        if (!isset($item['track_id']) || !isset($item['title']) || !isset($item['price'])) {
            error_log("handlePayPalPayment: Missing fields in track item: " . json_encode($item));
            throw new Exception('Malformed track item in cart');
        }
        
        $track_price = $item['price'] * 100; // Convert to cents
        $quantity = $item['quantity'] ?? 1;
        $item_total = $track_price * $quantity;
        
        $total_amount += $item_total;
        
        $cart_summary[] = [
            'type' => 'track',
            'track_id' => $item['track_id'],
            'title' => $item['title'],
            'artist' => $item['artist'] ?? $item['artist_name'] ?? 'Unknown Artist',
            'quantity' => $quantity,
            'amount' => $item_total
        ];
    }
    
    // For now, redirect to a PayPal checkout page
    // In a real implementation, you would create a PayPal order here
    $paypal_url = "https://www.paypal.com/checkoutnow?token=" . generatePayPalToken($total_amount, $cart_summary);
    
    // Log PayPal payment attempt
    logPaymentEvent('paypal_payment_attempt', [
        'user_id' => $_SESSION['user_id'],
        'cart_items' => $cart_summary,
        'total_credits' => $total_credits,
        'amount' => $total_amount,
        'paypal_url' => $paypal_url
    ]);
    
    echo json_encode([
        'success' => true,
        'paypal_url' => $paypal_url,
        'amount' => $total_amount,
        'credits' => $total_credits,
        'cart_summary' => $cart_summary
    ]);
}

function generatePayPalToken($amount, $cart_summary) {
    // This is a placeholder function
    // In a real implementation, you would:
    // 1. Create a PayPal order via PayPal API
    // 2. Return the PayPal order ID/token
    // 3. Handle the payment completion via webhook
    
    // For now, return a dummy token
    return 'PAYPAL_' . uniqid() . '_' . time();
}
?> 

CasperSecurity Mini