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/auto_fix_missing_purchases.php
<?php
/**
 * Automated Missing Purchase Fixer
 * 
 * This script automatically detects and fixes missing track purchases.
 * It should be run via cron every 5-15 minutes.
 * 
 * Usage:
 *   php auto_fix_missing_purchases.php [--dry-run] [--verify-stripe]
 * 
 * Options:
 *   --dry-run          : Show what would be fixed without actually fixing
 *   --verify-stripe    : Verify payment status with Stripe before fixing
 * 
 * Created: December 2025
 */

require_once __DIR__ . '/config/database.php';

// Configuration
$STRIPE_SECRET_KEY = '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';
$LOG_FILE = __DIR__ . '/logs/auto_fix_purchases.log';
$MINUTES_TO_WAIT = 5; // Wait 5 minutes after payment intent creation before flagging as missing

// Parse command line arguments
$dry_run = in_array('--dry-run', $argv);
$verify_stripe = in_array('--verify-stripe', $argv);

$pdo = getDBConnection();

// Log function
function logMessage($message, $data = []) {
    global $LOG_FILE;
    $entry = [
        'timestamp' => date('Y-m-d H:i:s'),
        'message' => $message,
        'data' => $data
    ];
    file_put_contents($LOG_FILE, json_encode($entry) . "\n", FILE_APPEND | LOCK_EX);
    echo "[" . date('Y-m-d H:i:s') . "] $message\n";
}

logMessage("Auto-fix script started", ['dry_run' => $dry_run, 'verify_stripe' => $verify_stripe]);

// Parse the cart payment logs
$log_file = __DIR__ . '/logs/cart_payment_detailed.log';
$missing_purchases = [];

if (!file_exists($log_file)) {
    logMessage("Log file not found", ['file' => $log_file]);
    exit(1);
}

$lines = file($log_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$lines = array_reverse($lines); // Most recent first

$seen_intents = [];
$cutoff_time = time() - ($MINUTES_TO_WAIT * 60); // Only check payment intents older than 5 minutes

foreach ($lines as $line) {
    $entry = json_decode($line, true);
    if (!$entry) continue;
    
    // Only look at "after_create_payment_intent" entries
    if (($entry['action'] ?? '') !== 'after_create_payment_intent') continue;
    
    $payment_intent_id = $entry['payment_intent_id'] ?? null;
    if (!$payment_intent_id || isset($seen_intents[$payment_intent_id])) continue;
    
    // Check if payment intent is old enough (wait for webhook to process)
    $entry_timestamp = strtotime($entry['timestamp'] ?? 'now');
    if ($entry_timestamp > $cutoff_time) {
        continue; // Too recent, skip
    }
    
    $seen_intents[$payment_intent_id] = true;
    
    $user_id = $entry['user_id'] ?? null;
    $cart_summary = $entry['cart_summary'] ?? [];
    $timestamp = $entry['timestamp'] ?? 'Unknown';
    
    // Extract track items
    foreach ($cart_summary as $item) {
        if (($item['type'] ?? '') === 'track') {
            $track_id = $item['track_id'] ?? null;
            if ($track_id) {
                // Check if purchased
                $stmt = $pdo->prepare("SELECT id FROM track_purchases WHERE user_id = ? AND track_id = ?");
                $stmt->execute([$user_id, $track_id]);
                $is_purchased = (bool)$stmt->fetch();
                
                if (!$is_purchased) {
                    $missing_purchases[] = [
                        'payment_intent_id' => $payment_intent_id,
                        'user_id' => $user_id,
                        'track_id' => $track_id,
                        'title' => $item['title'] ?? 'Unknown',
                        'artist' => $item['artist'] ?? 'Unknown',
                        'timestamp' => $timestamp,
                        'amount' => ($item['amount'] ?? 0) / 100
                    ];
                }
            }
        }
    }
}

logMessage("Missing purchases detected", ['count' => count($missing_purchases)]);

if (empty($missing_purchases)) {
    logMessage("No missing purchases found. Exiting.");
    exit(0);
}

// Process each missing purchase
$fixed_count = 0;
$skipped_count = 0;
$error_count = 0;

foreach ($missing_purchases as $mp) {
    logMessage("Processing missing purchase", [
        'payment_intent_id' => $mp['payment_intent_id'],
        'user_id' => $mp['user_id'],
        'track_id' => $mp['track_id']
    ]);
    
    // Verify with Stripe if requested
    if ($verify_stripe) {
        $payment_status = verifyPaymentWithStripe($mp['payment_intent_id'], $STRIPE_SECRET_KEY);
        
        if ($payment_status['status'] !== 'succeeded') {
            logMessage("Payment not succeeded in Stripe, skipping", [
                'payment_intent_id' => $mp['payment_intent_id'],
                'status' => $payment_status['status']
            ]);
            $skipped_count++;
            continue;
        }
    }
    
    // Fix the purchase
    if ($dry_run) {
        logMessage("DRY RUN: Would fix purchase", [
            'payment_intent_id' => $mp['payment_intent_id'],
            'user_id' => $mp['user_id'],
            'track_id' => $mp['track_id']
        ]);
        $fixed_count++;
    } else {
        $result = fixMissingPurchase($pdo, $mp['user_id'], $mp['track_id'], $mp['payment_intent_id']);
        
        if ($result['success']) {
            logMessage("Purchase fixed successfully", [
                'payment_intent_id' => $mp['payment_intent_id'],
                'user_id' => $mp['user_id'],
                'track_id' => $mp['track_id'],
                'purchase_id' => $result['purchase_id'] ?? null
            ]);
            $fixed_count++;
        } else {
            logMessage("Failed to fix purchase", [
                'payment_intent_id' => $mp['payment_intent_id'],
                'user_id' => $mp['user_id'],
                'track_id' => $mp['track_id'],
                'error' => $result['message']
            ]);
            $error_count++;
        }
    }
}

// Summary
logMessage("Auto-fix completed", [
    'total_detected' => count($missing_purchases),
    'fixed' => $fixed_count,
    'skipped' => $skipped_count,
    'errors' => $error_count,
    'dry_run' => $dry_run
]);

echo "\n=== Summary ===\n";
echo "Total missing purchases detected: " . count($missing_purchases) . "\n";
echo "Fixed: $fixed_count\n";
echo "Skipped: $skipped_count\n";
echo "Errors: $error_count\n";

exit(0);

/**
 * Verify payment status with Stripe
 */
function verifyPaymentWithStripe($payment_intent_id, $stripe_secret) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://api.stripe.com/v1/payment_intents/' . urlencode($payment_intent_id));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Authorization: Bearer ' . $stripe_secret]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($http_code !== 200) {
        return ['status' => 'error', 'message' => 'Failed to fetch payment intent'];
    }
    
    $data = json_decode($response, true);
    return [
        'status' => $data['status'] ?? 'unknown',
        'amount' => $data['amount'] ?? 0,
        'currency' => $data['currency'] ?? 'usd'
    ];
}

/**
 * Fix a missing purchase (same logic as admin_purchase_tracker.php)
 */
function fixMissingPurchase($pdo, $user_id, $track_id, $payment_intent_id) {
    try {
        // Check if already purchased
        $stmt = $pdo->prepare("SELECT id FROM track_purchases WHERE user_id = ? AND track_id = ?");
        $stmt->execute([$user_id, $track_id]);
        if ($stmt->fetch()) {
            return ['success' => false, 'message' => 'This track is already purchased by this user.'];
        }
        
        // Get track info
        $stmt = $pdo->prepare("SELECT id, title, price, user_id as artist_id FROM music_tracks WHERE id = ?");
        $stmt->execute([$track_id]);
        $track = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$track) {
            return ['success' => false, 'message' => 'Track not found in database.'];
        }
        
        $pdo->beginTransaction();
        
        // Determine revenue recipient
        $artist_stmt = $pdo->prepare("SELECT plan FROM users WHERE id = ?");
        $artist_stmt->execute([$track['artist_id']]);
        $artist = $artist_stmt->fetch(PDO::FETCH_ASSOC);
        $is_free_user_track = ($artist && strtolower($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 (?, ?, ?, ?, 1, ?, ?, ?, NOW())
        ");
        $stmt->execute([
            $track_id,
            $user_id,
            $track['artist_id'],
            $track['price'],
            $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, stripe_payment_intent_id, purchase_date) 
            VALUES (?, ?, ?, 0, 'stripe', ?, NOW())
        ");
        $stmt->execute([$user_id, $track_id, $track['price'], $payment_intent_id]);
        $purchase_id = $pdo->lastInsertId();
        
        // Add to library
        $stmt = $pdo->prepare("INSERT IGNORE INTO user_library (user_id, track_id, purchase_date) VALUES (?, ?, NOW())");
        $stmt->execute([$user_id, $track_id]);
        
        $pdo->commit();
        
        // Log the fix
        $log_entry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'action' => 'auto_fix_missing_purchase',
            'user_id' => $user_id,
            'track_id' => $track_id,
            'track_title' => $track['title'],
            'payment_intent_id' => $payment_intent_id,
            'purchase_id' => $purchase_id
        ];
        $log_file = __DIR__ . '/logs/manual_purchase_fixes.log';
        file_put_contents($log_file, json_encode($log_entry) . "\n", FILE_APPEND | LOCK_EX);
        
        return [
            'success' => true, 
            'message' => "Purchase #{$purchase_id} created for \"{$track['title']}\"",
            'purchase_id' => $purchase_id
        ];
        
    } catch (Exception $e) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }
        return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
    }
}

CasperSecurity Mini