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

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/private_html/api/get_crate_tracks.php
<?php
session_start();
header('Content-Type: application/json');

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

$crate_id = isset($_GET['crate_id']) ? (int)$_GET['crate_id'] : null;
$is_public_request = isset($_GET['public']) && $_GET['public'] == '1';

if (!$crate_id) {
    echo json_encode(['success' => false, 'error' => 'Crate ID is required']);
    exit;
}

// Helper function to convert external URLs to proxy endpoint
function convertToProxyUrl($audioUrl, $taskId) {
    if (empty($audioUrl)) return $audioUrl;
    
    // If URL is external, convert to proxy
    if (strpos($audioUrl, 'http') === 0 || 
        strpos($audioUrl, 'api.box') !== false || 
        strpos($audioUrl, 'apiboxfiles.erweima.ai') !== false) {
        if (!empty($taskId)) {
            return '/utils/audiofiles.php?id=' . urlencode($taskId);
        }
    }
    return $audioUrl;
}

try {
    $pdo = getDBConnection();
    
    // Check if is_description_public column exists
    $checkDescCol = $pdo->query("SHOW COLUMNS FROM artist_playlists LIKE 'is_description_public'");
    $hasDescPublicColumn = $checkDescCol->rowCount() > 0;
    $descPublicField = $hasDescPublicColumn ? ", is_description_public" : "";
    
    // Check if this is a public crate request (for artist profile viewing)
    if ($is_public_request) {
        // For public requests, only allow access to public crates
        $stmt = $pdo->prepare("SELECT id, name, description, user_id, is_public $descPublicField FROM artist_playlists WHERE id = ? AND is_public = 1");
        $stmt->execute([$crate_id]);
        $crate = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$crate) {
            echo json_encode(['success' => false, 'error' => 'Crate not found or is private']);
            exit;
        }
        
        // Hide description if not public
        if (!$hasDescPublicColumn || $crate['is_description_public'] == 0) {
            $crate['description'] = null;
        }
    } else {
        // For authenticated requests, verify crate belongs to user
        if (!isset($_SESSION['user_id'])) {
            echo json_encode(['success' => false, 'error' => 'Not authenticated']);
            exit;
        }
        
        $stmt = $pdo->prepare("
            SELECT 
                ap.id, 
                ap.name, 
                ap.description, 
                ap.user_id, 
                ap.is_public $descPublicField,
                u.name as artist_name
            FROM artist_playlists ap
            JOIN users u ON ap.user_id = u.id
            WHERE ap.id = ? AND ap.user_id = ?
        ");
        $stmt->execute([$crate_id, $_SESSION['user_id']]);
        $crate = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$crate) {
            echo json_encode(['success' => false, 'error' => 'Crate not found or access denied']);
            exit;
        }
        
        // Set default if column doesn't exist
        if (!$hasDescPublicColumn) {
            $crate['is_description_public'] = 1;
        }
    }
    
    // Check if is_public column exists in playlist_tracks
    $checkColumn = $pdo->query("SHOW COLUMNS FROM playlist_tracks LIKE 'is_public'");
    $hasIsPublicColumn = $checkColumn->rowCount() > 0;
    
    // Get tracks in crate (use LEFT JOIN to handle empty crates)
    // For public requests, only show tracks marked as public in the crate
    $publicFilter = "";
    if ($is_public_request && $hasIsPublicColumn) {
        $publicFilter = "AND (pt.is_public = 1 OR pt.is_public IS NULL)";
    }
    
    // Check if user is authenticated (for purchase check)
    $current_user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : null;
    
    $query = "
        SELECT 
            mt.id,
            mt.title,
            mt.prompt,
            mt.audio_url,
            mt.task_id,
            mt.duration,
            mt.created_at,
            mt.user_id,
            mt.metadata,
            mt.price,
            mt.is_public as track_is_public,
            " . ($hasIsPublicColumn ? "COALESCE(pt.is_public, 1)" : "1") . " as crate_track_public,
            u.name as artist_name,
            pt.position,
            CASE 
                WHEN mt.duration >= 300 THEN 2.5 
                WHEN mt.duration IS NULL OR mt.duration = 0 THEN 0
                ELSE mt.duration * 0.5 / 60 
            END as set_duration_minutes" . 
            ($current_user_id ? ", 
            CASE WHEN mt.user_id = ? THEN 1 ELSE 0 END as user_owns_track,
            CASE WHEN EXISTS(SELECT 1 FROM track_purchases WHERE user_id = ? AND track_id = mt.id) THEN 1 ELSE 0 END as user_purchased_track" : ", 
            0 as user_owns_track,
            0 as user_purchased_track") . "
        FROM playlist_tracks pt
        LEFT JOIN music_tracks mt ON pt.track_id = mt.id
        LEFT JOIN users u ON mt.user_id = u.id
        WHERE pt.playlist_id = ?
        AND (mt.status = 'complete' OR mt.status IS NULL)
        $publicFilter
        ORDER BY pt.position ASC, pt.added_at ASC
    ";
    
    $stmt = $pdo->prepare($query);
    if ($current_user_id) {
        $stmt->execute([$current_user_id, $current_user_id, $crate_id]);
    } else {
        $stmt->execute([$crate_id]);
    }
    $tracks = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
    // Filter out any null tracks (in case of orphaned playlist_tracks)
    $tracks = array_filter($tracks, function($track) {
        return !empty($track['id']);
    });
    $tracks = array_values($tracks); // Re-index array
    
    // SECURITY: For PUBLIC requests, NEVER expose audio URLs or task IDs
    // Client must use get_audio_token.php to get signed URLs for playback
    if ($is_public_request) {
        foreach ($tracks as &$track) {
            // Remove sensitive audio data - only keep metadata for display
            unset($track['audio_url']);
            unset($track['task_id']);
            unset($track['prompt']);
            unset($track['metadata']);
            $track['variations'] = []; // No variations for public view
        }
        unset($track);
    } else {
        // For authenticated owner requests, convert URLs to proxy endpoint
        foreach ($tracks as &$track) {
            $track['audio_url'] = convertToProxyUrl($track['audio_url'], $track['task_id'] ?? '');
        }
        unset($track);
        
        // Get variations for each track (only for owner)
        $checkTable = $pdo->query("SHOW TABLES LIKE 'audio_variations'");
        $hasVariationsTable = $checkTable->rowCount() > 0;
        
        foreach ($tracks as &$track) {
            $track['variations'] = [];
            
            if ($hasVariationsTable) {
                $varStmt = $pdo->prepare("
                    SELECT 
                        variation_index,
                        audio_url,
                        duration,
                        title,
                        tags
                    FROM audio_variations 
                    WHERE track_id = ? 
                    ORDER BY variation_index ASC
                ");
                $varStmt->execute([$track['id']]);
                $variations = $varStmt->fetchAll(PDO::FETCH_ASSOC);
                
                // Convert variation audio URLs to proxy format
                foreach ($variations as &$var) {
                    $var['audio_url'] = convertToProxyUrl($var['audio_url'], $track['task_id'] ?? '');
                }
                unset($var);
                $track['variations'] = $variations;
            }
        }
        unset($track);
    }
    
    // Calculate total set duration
    $total_set_duration = 0;
    foreach ($tracks as $track) {
        $duration = floatval($track['set_duration_minutes'] ?? 0);
        $total_set_duration += $duration;
    }
    
    echo json_encode([
        'success' => true,
        'crate' => $crate,
        'tracks' => $tracks,
        'total_set_duration_minutes' => round($total_set_duration, 1),
        'is_2_hour_set' => $total_set_duration >= 120,
        'set_progress_percent' => min(100, round(($total_set_duration / 120) * 100, 1))
    ], JSON_PRETTY_PRINT);
    
} catch (Exception $e) {
    error_log("Error getting crate tracks: " . $e->getMessage());
    echo json_encode(['success' => false, 'error' => 'Failed to get crate tracks: ' . $e->getMessage()]);
}


CasperSecurity Mini