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

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/soundstudiopro.com/public_html/api/save_audio_analysis.php
<?php
/**
 * API Endpoint: Save Audio Analysis Results
 * Stores BPM, key (with Camelot notation), and energy data from client-side analysis
 */

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

header('Content-Type: application/json');

// Only accept POST requests
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(['success' => false, 'error' => 'Method not allowed']);
    exit;
}

// Get JSON input
$input = json_decode(file_get_contents('php://input'), true);

if (!$input) {
    echo json_encode(['success' => false, 'error' => 'Invalid JSON input']);
    exit;
}

$track_id = intval($input['track_id'] ?? 0);
$bpm = floatval($input['bpm'] ?? 0); // Allow decimal BPM values (e.g., 104.2)
$key = $input['key'] ?? null;
$camelot = $input['camelot'] ?? null;
$energy = $input['energy'] ?? null;
$confidence = intval($input['confidence'] ?? 0);

// Validate required fields
if (!$track_id || $bpm <= 0 || !$key) {
    echo json_encode(['success' => false, 'error' => 'Missing required fields']);
    exit;
}

// CRITICAL: Real-world music BPM is 60-140 max. Anything above 140 is definitely a harmonic (double).
// Normalize to match client-side logic
$originalBpm = $bpm;

// Safety: Check for invalid values (NaN, Infinity) that could cause infinite loops
if (!is_finite($bpm) || is_nan($bpm)) {
    echo json_encode(['success' => false, 'error' => 'Invalid BPM value (NaN or Infinity)']);
    exit;
}

// CRITICAL: Values > 140 NEVER happen in real music - halve immediately
if ($bpm > 140) {
    $bpm = $bpm / 2;
    error_log("šŸŽµ SERVER: Forced BPM halve $originalBpm → $bpm (140+ never happens) for track $track_id");
    
    // If still > 140 after halving, halve again (safety)
    if ($bpm > 140) {
        $bpm = $bpm / 2;
        error_log("šŸŽµ SERVER: Second BPM halve → $bpm for track $track_id");
    }
}
// 188 is a common error (94*2) - fix it specifically
elseif (abs($bpm - 188) < 2) {
    $bpm = 94;
    error_log("šŸŽµ SERVER: Fixed common error 188 → 94 for track $track_id");
}
// Values < 50: Very low, likely wrong, double them
elseif ($bpm < 50 && $bpm > 0) {
    $doubled = $bpm * 2;
    if ($doubled <= 140) {
        $bpm = $doubled;
        error_log("šŸŽµ SERVER: Normalized very low BPM $originalBpm → $bpm for track $track_id");
    }
}

// Validate BPM range (60-140 is realistic for music)
if ($bpm < 40 || $bpm > 140) {
    // If somehow still out of range, clamp it
    if ($bpm > 140) {
        $bpm = 140;
        error_log("šŸŽµ SERVER: Clamped BPM to 140 for track $track_id");
    } elseif ($bpm < 40) {
        $bpm = 60;
        error_log("šŸŽµ SERVER: Clamped BPM to 60 for track $track_id");
    }
}

// Round to 1 decimal place for consistency
$bpm = round($bpm, 1);

try {
    $pdo = getDBConnection();
    
    // Get current track metadata
    $stmt = $pdo->prepare("SELECT metadata, user_id FROM music_tracks WHERE id = ?");
    $stmt->execute([$track_id]);
    $track = $stmt->fetch(PDO::FETCH_ASSOC);
    
    if (!$track) {
        echo json_encode(['success' => false, 'error' => 'Track not found']);
        exit;
    }
    
    // Parse existing metadata
    $metadata = json_decode($track['metadata'] ?? '{}', true) ?: [];
    
    // Check if already analyzed with good confidence (don't overwrite with lower quality analysis)
    // BUT: Always allow user corrections (confidence = 100) to overwrite
    $existingConfidence = $metadata['analysis_confidence'] ?? 0;
    $isUserCorrection = ($confidence >= 100);
    $hasExistingAnalysis = isset($metadata['bpm']) && isset($metadata['analysis_source']);
    
    if (!$isUserCorrection && $hasExistingAnalysis && $existingConfidence >= $confidence) {
        echo json_encode([
            'success' => true, 
            'message' => 'Existing analysis has equal or higher confidence, keeping it',
            'existing' => true
        ]);
        exit;
    }
    
    // SINGLE SOURCE OF TRUTH: Store analyzed values in main fields
    // This is the ONLY place we store BPM/key - no duplicate fields
    $oldBpm = $metadata['bpm'] ?? 'none';
    $oldKey = $metadata['key'] ?? 'none';
    
    // Force overwrite - these are the authoritative values
    $metadata['bpm'] = $bpm;
    $metadata['key'] = $key;
    $metadata['numerical_key'] = $camelot; // Camelot notation for DJ compatibility
    $metadata['energy'] = $energy;
    
    // Store analysis metadata (when/how it was analyzed)
    $metadata['analysis_confidence'] = $confidence;
    $metadata['analysis_date'] = date('Y-m-d H:i:s');
    $metadata['analysis_source'] = 'client_web_audio';
    
    // Remove old duplicate fields if they exist (cleanup)
    unset($metadata['analyzed_bpm'], $metadata['analyzed_key'], $metadata['analyzed_camelot'], $metadata['analyzed_energy']);
    
    // Encode metadata to JSON
    $metadataJson = json_encode($metadata, JSON_UNESCAPED_UNICODE);
    
    // Update database - store in metadata JSON
    $stmt = $pdo->prepare("UPDATE music_tracks SET metadata = ?, updated_at = NOW() WHERE id = ?");
    $result = $stmt->execute([$metadataJson, $track_id]);
    
    if ($result) {
        // Verify the update by reading it back
        $verifyStmt = $pdo->prepare("SELECT metadata FROM music_tracks WHERE id = ?");
        $verifyStmt->execute([$track_id]);
        $verifyTrack = $verifyStmt->fetch(PDO::FETCH_ASSOC);
        $verifyMetadata = json_decode($verifyTrack['metadata'] ?? '{}', true) ?: [];
        $savedBpm = $verifyMetadata['bpm'] ?? null;
        $savedKey = $verifyMetadata['key'] ?? null;
        
        echo json_encode([
            'success' => true,
            'message' => 'Analysis saved successfully',
            'data' => [
                'bpm' => $bpm,
                'key' => $key,
                'camelot' => $camelot,
                'energy' => $energy,
                'confidence' => $confidence
            ],
            'verified' => [
                'bpm' => $savedBpm,
                'key' => $savedKey
            ]
        ]);
        
        // Log the analysis with before/after
        error_log("šŸŽµ Audio analysis saved for track $track_id: BPM=$oldBpm→$bpm (verified: $savedBpm), Key=$oldKey→$key (verified: $savedKey), Camelot=$camelot, Energy=$energy, Confidence=$confidence%");
        
        if ($savedBpm != $bpm || $savedKey != $key) {
            error_log("āš ļø WARNING: Saved values don't match! Expected BPM=$bpm, got $savedBpm. Expected Key=$key, got $savedKey");
        }
    } else {
        $errorInfo = $stmt->errorInfo();
        error_log("āŒ Database update failed for track $track_id: " . json_encode($errorInfo));
        echo json_encode(['success' => false, 'error' => 'Database update failed', 'details' => $errorInfo]);
    }
    
} catch (Exception $e) {
    error_log("Audio analysis save error: " . $e->getMessage());
    echo json_encode(['success' => false, 'error' => 'Server error']);
}


CasperSecurity Mini