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/public_html/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/public_html/admin_purchase_tracker.php
<?php
/**
 * Admin Purchase Tracker
 * 
 * This tool helps you:
 * 1. View recent payment attempts from logs
 * 2. Identify missing purchases (paid but not in database)
 * 3. Fix missing purchases with one click
 * 
 * Created: November 29, 2025
 */

session_start();
require_once __DIR__ . '/config/database.php';

// Check if admin
if (!isset($_SESSION['is_admin']) || !$_SESSION['is_admin']) {
    die("Admin access required. Please log in as admin first.");
}

$pdo = getDBConnection();

// Handle actions
$action = $_GET['action'] ?? '';
$message = '';
$message_type = '';

if ($action === 'fix' && isset($_GET['user_id']) && isset($_GET['track_id']) && isset($_GET['payment_intent'])) {
    $result = fixMissingPurchase(
        $pdo,
        (int)$_GET['user_id'],
        (int)$_GET['track_id'],
        $_GET['payment_intent']
    );
    $message = $result['message'];
    $message_type = $result['success'] ? 'success' : 'error';
}

?>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Purchase Tracker - Admin</title>
    <style>
        * { box-sizing: border-box; }
        body { 
            font-family: 'Segoe UI', Arial, sans-serif; 
            padding: 20px; 
            background: #0f0f0f; 
            color: #e0e0e0; 
            line-height: 1.6;
            margin: 0;
        }
        .container { max-width: 1400px; margin: 0 auto; }
        h1 { color: #667eea; margin-bottom: 10px; }
        h2 { color: #a0aec0; font-size: 18px; margin-top: 30px; border-bottom: 1px solid #333; padding-bottom: 10px; }
        h3 { color: #667eea; margin: 0 0 15px 0; }
        
        .header-bar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 20px;
            padding-bottom: 20px;
            border-bottom: 1px solid #333;
        }
        
        .stats-row {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 30px;
        }
        
        .stat-card {
            background: #1a1a2e;
            padding: 20px;
            border-radius: 10px;
            text-align: center;
            border: 1px solid #333;
        }
        
        .stat-card .number {
            font-size: 36px;
            font-weight: bold;
            color: #667eea;
        }
        
        .stat-card.danger .number { color: #e53e3e; }
        .stat-card.success .number { color: #48bb78; }
        .stat-card.warning .number { color: #ffc107; }
        
        .stat-card .label {
            font-size: 14px;
            color: #718096;
            margin-top: 5px;
        }
        
        .section {
            background: #1a1a2e;
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 20px;
            border: 1px solid #333;
        }
        
        .section.alert {
            border-color: #e53e3e;
            background: rgba(229, 62, 62, 0.1);
        }
        
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 15px;
            font-size: 14px;
        }
        
        th, td {
            padding: 12px 10px;
            text-align: left;
            border-bottom: 1px solid #333;
        }
        
        th {
            background: #252542;
            color: #a0aec0;
            font-weight: 600;
            text-transform: uppercase;
            font-size: 12px;
            letter-spacing: 0.5px;
        }
        
        tr:hover { background: rgba(102, 126, 234, 0.1); }
        
        .badge {
            display: inline-block;
            padding: 4px 10px;
            border-radius: 20px;
            font-size: 12px;
            font-weight: 600;
        }
        
        .badge-success { background: rgba(72, 187, 120, 0.2); color: #48bb78; }
        .badge-error { background: rgba(229, 62, 62, 0.2); color: #e53e3e; }
        .badge-warning { background: rgba(255, 193, 7, 0.2); color: #ffc107; }
        .badge-info { background: rgba(102, 126, 234, 0.2); color: #667eea; }
        
        .btn {
            display: inline-block;
            padding: 8px 16px;
            background: #667eea;
            color: white;
            text-decoration: none;
            border-radius: 5px;
            font-size: 13px;
            border: none;
            cursor: pointer;
            transition: background 0.2s;
        }
        
        .btn:hover { background: #5a67d8; }
        .btn-danger { background: #e53e3e; }
        .btn-danger:hover { background: #c53030; }
        .btn-sm { padding: 5px 10px; font-size: 12px; }
        
        .alert-box {
            padding: 15px 20px;
            border-radius: 8px;
            margin-bottom: 20px;
        }
        
        .alert-box.success {
            background: rgba(72, 187, 120, 0.2);
            border: 1px solid #48bb78;
            color: #48bb78;
        }
        
        .alert-box.error {
            background: rgba(229, 62, 62, 0.2);
            border: 1px solid #e53e3e;
            color: #e53e3e;
        }
        
        .user-link {
            color: #667eea;
            text-decoration: none;
        }
        
        .user-link:hover { text-decoration: underline; }
        
        .track-list {
            display: flex;
            flex-wrap: wrap;
            gap: 5px;
        }
        
        .track-chip {
            background: #252542;
            padding: 3px 8px;
            border-radius: 4px;
            font-size: 12px;
        }
        
        .missing-row {
            background: rgba(229, 62, 62, 0.1) !important;
        }
        
        .log-preview {
            background: #0a0a0a;
            padding: 10px;
            border-radius: 5px;
            font-family: monospace;
            font-size: 12px;
            max-height: 200px;
            overflow-y: auto;
            white-space: pre-wrap;
            word-break: break-all;
        }
        
        .tabs {
            display: flex;
            gap: 5px;
            margin-bottom: 20px;
        }
        
        .tab {
            padding: 10px 20px;
            background: #252542;
            color: #a0aec0;
            text-decoration: none;
            border-radius: 5px 5px 0 0;
            border: 1px solid #333;
            border-bottom: none;
        }
        
        .tab.active {
            background: #1a1a2e;
            color: #667eea;
            border-color: #667eea;
        }
        
        .empty-state {
            text-align: center;
            padding: 40px;
            color: #718096;
        }
        
        .empty-state .icon {
            font-size: 48px;
            margin-bottom: 15px;
        }
        
        code {
            background: #252542;
            padding: 2px 6px;
            border-radius: 3px;
            font-family: monospace;
            font-size: 12px;
        }
        
        .refresh-note {
            font-size: 12px;
            color: #718096;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="header-bar">
        <div>
            <h1>🔍 Purchase Tracker</h1>
            <p class="refresh-note">Scans payment logs and compares with database records</p>
        </div>
        <div>
            <a href="?refresh=1" class="btn">🔄 Refresh</a>
            <a href="admin.php" class="btn">← Back to Admin</a>
        </div>
    </div>
    
    <?php if ($message): ?>
    <div class="alert-box <?= $message_type ?>">
        <?= htmlspecialchars($message) ?>
    </div>
    <?php endif; ?>
    
    <?php
    // Parse the cart payment logs
    $log_file = __DIR__ . '/logs/cart_payment_detailed.log';
    $recent_payments = [];
    $missing_purchases = [];
    
    if (file_exists($log_file)) {
        $lines = file($log_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $lines = array_reverse($lines); // Most recent first
        
        $seen_intents = [];
        
        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;
            
            $seen_intents[$payment_intent_id] = true;
            
            $user_id = $entry['user_id'] ?? null;
            $cart_summary = $entry['cart_summary'] ?? [];
            $timestamp = $entry['timestamp'] ?? 'Unknown';
            $amount = ($entry['amount'] ?? 0) / 100;
            
            // Get user info
            $user_name = 'Unknown';
            $user_email = '';
            if ($user_id) {
                $stmt = $pdo->prepare("SELECT name, email FROM users WHERE id = ?");
                $stmt->execute([$user_id]);
                $user = $stmt->fetch(PDO::FETCH_ASSOC);
                if ($user) {
                    $user_name = $user['name'];
                    $user_email = $user['email'];
                }
            }
            
            // Extract track items
            $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();
                        
                        $track_items[] = [
                            'track_id' => $track_id,
                            'title' => $item['title'] ?? 'Unknown',
                            'artist' => $item['artist'] ?? 'Unknown',
                            'is_purchased' => $is_purchased
                        ];
                        
                        if (!$is_purchased) {
                            $missing_purchases[] = [
                                'payment_intent_id' => $payment_intent_id,
                                'user_id' => $user_id,
                                'user_name' => $user_name,
                                'user_email' => $user_email,
                                'track_id' => $track_id,
                                'title' => $item['title'] ?? 'Unknown',
                                'artist' => $item['artist'] ?? 'Unknown',
                                'timestamp' => $timestamp,
                                'amount' => ($item['amount'] ?? 0) / 100
                            ];
                        }
                    }
                }
            }
            
            $recent_payments[] = [
                'payment_intent_id' => $payment_intent_id,
                'user_id' => $user_id,
                'user_name' => $user_name,
                'user_email' => $user_email,
                'timestamp' => $timestamp,
                'amount' => $amount,
                'track_items' => $track_items,
                'has_missing' => count(array_filter($track_items, fn($t) => !$t['is_purchased'])) > 0
            ];
            
            // Limit to last 50 payment attempts
            if (count($recent_payments) >= 50) break;
        }
    }
    
    // Count stats
    $total_payments = count($recent_payments);
    $payments_with_missing = count(array_filter($recent_payments, fn($p) => $p['has_missing']));
    $total_missing_tracks = count($missing_purchases);
    ?>
    
    <!-- Stats Row -->
    <div class="stats-row">
        <div class="stat-card">
            <div class="number"><?= $total_payments ?></div>
            <div class="label">Recent Payment Attempts</div>
        </div>
        <div class="stat-card <?= $payments_with_missing > 0 ? 'danger' : 'success' ?>">
            <div class="number"><?= $payments_with_missing ?></div>
            <div class="label">Payments With Missing Tracks</div>
        </div>
        <div class="stat-card <?= $total_missing_tracks > 0 ? 'danger' : 'success' ?>">
            <div class="number"><?= $total_missing_tracks ?></div>
            <div class="label">Total Missing Track Purchases</div>
        </div>
    </div>
    
    <?php if (!empty($missing_purchases)): ?>
    <!-- Missing Purchases Alert -->
    <div class="section alert">
        <h3>⚠️ Missing Purchases Found!</h3>
        <p>These tracks were in payment attempts but are NOT in the database. The customer may have paid but not received their tracks.</p>
        
        <table>
            <thead>
                <tr>
                    <th>Date</th>
                    <th>Customer</th>
                    <th>Track</th>
                    <th>Artist</th>
                    <th>Price</th>
                    <th>Payment Intent</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($missing_purchases as $mp): ?>
                <tr class="missing-row">
                    <td><?= htmlspecialchars($mp['timestamp']) ?></td>
                    <td>
                        <a href="artist_profile.php?id=<?= $mp['user_id'] ?>" class="user-link">
                            <?= htmlspecialchars($mp['user_name']) ?>
                        </a>
                        <br><small style="color: #718096;"><?= htmlspecialchars($mp['user_email']) ?></small>
                    </td>
                    <td>
                        <a href="track.php?id=<?= $mp['track_id'] ?>" class="user-link">
                            <?= htmlspecialchars($mp['title']) ?>
                        </a>
                        <br><small style="color: #718096;">ID: <?= $mp['track_id'] ?></small>
                    </td>
                    <td><?= htmlspecialchars($mp['artist']) ?></td>
                    <td>$<?= number_format($mp['amount'], 2) ?></td>
                    <td><code><?= substr($mp['payment_intent_id'], 0, 20) ?>...</code></td>
                    <td>
                        <a href="?action=fix&user_id=<?= $mp['user_id'] ?>&track_id=<?= $mp['track_id'] ?>&payment_intent=<?= urlencode($mp['payment_intent_id']) ?>" 
                           class="btn btn-danger btn-sm"
                           onclick="return confirm('Add this purchase to the database?');">
                            🔧 Fix
                        </a>
                    </td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
        
        <p style="margin-top: 20px;">
            <strong>Note:</strong> Before fixing, verify in Stripe Dashboard that the payment actually succeeded.
        </p>
    </div>
    <?php endif; ?>
    
    <!-- Recent Payment Attempts -->
    <div class="section">
        <h3>📋 Recent Payment Attempts (from logs)</h3>
        <p style="color: #718096; font-size: 14px;">
            These are payment intents created in checkout. Green = all tracks purchased. Red = some tracks missing.
        </p>
        
        <?php if (empty($recent_payments)): ?>
        <div class="empty-state">
            <div class="icon">📭</div>
            <p>No payment attempts found in logs.</p>
            <p style="font-size: 13px;">Log file: <code><?= $log_file ?></code></p>
        </div>
        <?php else: ?>
        <table>
            <thead>
                <tr>
                    <th>Date</th>
                    <th>Customer</th>
                    <th>Amount</th>
                    <th>Tracks</th>
                    <th>Status</th>
                    <th>Payment Intent</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ($recent_payments as $payment): ?>
                <tr class="<?= $payment['has_missing'] ? 'missing-row' : '' ?>">
                    <td><?= htmlspecialchars($payment['timestamp']) ?></td>
                    <td>
                        <a href="artist_profile.php?id=<?= $payment['user_id'] ?>" class="user-link">
                            <?= htmlspecialchars($payment['user_name']) ?>
                        </a>
                    </td>
                    <td>$<?= number_format($payment['amount'], 2) ?></td>
                    <td>
                        <div class="track-list">
                            <?php foreach ($payment['track_items'] as $track): ?>
                            <span class="track-chip" style="<?= $track['is_purchased'] ? '' : 'background: rgba(229, 62, 62, 0.3);' ?>">
                                <?= $track['is_purchased'] ? '✓' : '✗' ?> 
                                <?= htmlspecialchars($track['title']) ?>
                            </span>
                            <?php endforeach; ?>
                            <?php if (empty($payment['track_items'])): ?>
                            <span style="color: #718096;">No tracks</span>
                            <?php endif; ?>
                        </div>
                    </td>
                    <td>
                        <?php if ($payment['has_missing']): ?>
                        <span class="badge badge-error">Missing</span>
                        <?php else: ?>
                        <span class="badge badge-success">Complete</span>
                        <?php endif; ?>
                    </td>
                    <td><code><?= substr($payment['payment_intent_id'], 0, 20) ?>...</code></td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
        <?php endif; ?>
    </div>
    
    <!-- Log Files Info -->
    <div class="section">
        <h3>📁 Log Files Reference</h3>
        <table>
            <thead>
                <tr>
                    <th>Log File</th>
                    <th>Purpose</th>
                    <th>Size</th>
                    <th>Last Modified</th>
                </tr>
            </thead>
            <tbody>
                <?php
                $log_files = [
                    'logs/cart_payment_detailed.log' => 'Payment intent creation (cart checkout)',
                    'logs/credit_payments.log' => 'Credit package payments',
                    'logs/stripe_webhooks.log' => 'Stripe webhook events',
                    'logs/track_purchase_errors.log' => 'Track purchase errors',
                    'logs/manual_purchase_fixes.log' => 'Manual fixes applied'
                ];
                
                foreach ($log_files as $file => $purpose):
                    $full_path = __DIR__ . '/' . $file;
                    $exists = file_exists($full_path);
                ?>
                <tr>
                    <td><code><?= $file ?></code></td>
                    <td><?= $purpose ?></td>
                    <td><?= $exists ? number_format(filesize($full_path)) . ' bytes' : '<span style="color: #718096;">Not found</span>' ?></td>
                    <td><?= $exists ? date('Y-m-d H:i:s', filemtime($full_path)) : '-' ?></td>
                </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>
    
    <!-- Quick Links -->
    <div class="section">
        <h3>🔗 Related Tools</h3>
        <div style="display: flex; gap: 10px; flex-wrap: wrap;">
            <a href="investigate_stephane_10_tracks.php" class="btn">🔍 Full Stripe Investigation</a>
            <a href="fix_stephane_3_tracks.php" class="btn">🔧 Auto-Find Missing (Stephane)</a>
            <a href="admin_check_user_5_purchases.php" class="btn">👤 Check User #5</a>
            <a href="reconcile_stripe_purchases.php" class="btn">⚖️ Reconcile All</a>
        </div>
    </div>
</div>
</body>
</html>

<?php
/**
 * Fix a missing purchase
 */
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' => 'admin_purchase_tracker_fix',
            'user_id' => $user_id,
            'track_id' => $track_id,
            'track_title' => $track['title'],
            'payment_intent_id' => $payment_intent_id,
            'purchase_id' => $purchase_id,
            'fixed_by' => $_SESSION['user_id'] ?? 'unknown'
        ];
        $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' => "✓ Fixed! Purchase #{$purchase_id} created for \"{$track['title']}\" (Track #{$track_id})"
        ];
        
    } catch (Exception $e) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }
        return ['success' => false, 'message' => 'Error: ' . $e->getMessage()];
    }
}
?>


CasperSecurity Mini