![]() 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/utils/ |
<?php
// Audio proxy endpoint - hides actual MP3 file paths
// Uses track_id instead of task_id for community pages
// Now includes signed token validation to prevent URL sharing
error_reporting(0);
ini_set('display_errors', 0);
ob_start();
session_start();
// Include token validation
require_once __DIR__ . '/audio_token.php';
// Get track ID and optional variation from URL
$trackId = $_GET['id'] ?? '';
$variationIndex = isset($_GET['variation']) ? (int)$_GET['variation'] : null;
$token = $_GET['token'] ?? '';
$expires = isset($_GET['expires']) ? (int)$_GET['expires'] : 0;
ob_clean();
if (empty($trackId) || !is_numeric($trackId)) {
http_response_code(400);
header('Content-Type: text/plain');
echo "Invalid track ID";
exit;
}
// Validate signed token
if (empty($token) || empty($expires)) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied - missing token";
exit;
}
if (!validateAudioToken($trackId, $variationIndex, $token, $expires)) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied - invalid or expired token";
exit;
}
require_once __DIR__ . '/../config/database.php';
ob_clean();
$pdo = getDBConnection();
if (!$pdo) {
http_response_code(500);
header('Content-Type: text/plain');
echo "Database error";
exit;
}
// Get track and check if it's public
$stmt = $pdo->prepare("SELECT id, task_id, audio_url, is_public, user_id, status, metadata, selected_variation FROM music_tracks WHERE id = ? AND status = 'complete'");
$stmt->execute([$trackId]);
$track = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$track) {
http_response_code(404);
header('Content-Type: text/plain');
echo "Track not found";
exit;
}
// Check access: user must own the track OR track must be public
$user_id = $_SESSION['user_id'] ?? null;
$hasAccess = false;
if ($user_id && $track['user_id'] == $user_id) {
$hasAccess = true;
} elseif ($track['is_public'] == 1 || $track['is_public'] === null) {
$hasAccess = true;
} else {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied";
exit;
}
// If no variation parameter provided, check for selected variation in metadata
if ($variationIndex === null) {
// Check metadata for selected_variation
if (!empty($track['metadata'])) {
$metadata = is_string($track['metadata']) ? json_decode($track['metadata'], true) : $track['metadata'];
if (isset($metadata['selected_variation'])) {
$variationIndex = (int)$metadata['selected_variation'];
}
}
// Also check selected_variation column if it exists
if ($variationIndex === null && isset($track['selected_variation']) && $track['selected_variation'] !== null) {
$variationIndex = (int)$track['selected_variation'];
}
}
// Get audio URL - check for specific variation first, then main track
$audioUrl = '';
if ($variationIndex !== null) {
// Get specific variation
$stmt = $pdo->prepare("SELECT audio_url FROM audio_variations WHERE track_id = ? AND variation_index = ?");
$stmt->execute([$trackId, $variationIndex]);
$variation = $stmt->fetch(PDO::FETCH_ASSOC);
if ($variation) {
$audioUrl = $variation['audio_url'] ?? '';
}
}
// If no variation or variation not found, use main track
if (empty($audioUrl)) {
$audioUrl = $track['audio_url'] ?? '';
// If still empty, try first variation as fallback
if (empty($audioUrl)) {
$stmt = $pdo->prepare("SELECT audio_url FROM audio_variations WHERE track_id = ? ORDER BY variation_index ASC LIMIT 1");
$stmt->execute([$trackId]);
$variation = $stmt->fetch(PDO::FETCH_ASSOC);
if ($variation) {
$audioUrl = $variation['audio_url'] ?? '';
}
}
}
if (empty($audioUrl)) {
http_response_code(404);
header('Content-Type: text/plain');
echo "Audio not available";
exit;
}
// If it's a local file, serve it with Range support for seeking
if (strpos($audioUrl, '/audio_files/') === 0 || strpos($audioUrl, '/uploads/') === 0) {
$localPath = $_SERVER['DOCUMENT_ROOT'] . $audioUrl;
if (file_exists($localPath)) {
$fileSize = filesize($localPath);
$fileType = mime_content_type($localPath) ?: 'audio/mpeg';
while (ob_get_level()) {
ob_end_clean();
}
header('Content-Type: ' . $fileType);
header('Accept-Ranges: bytes');
header('Cache-Control: public, max-age=3600');
// Handle Range requests for seeking support
if (isset($_SERVER['HTTP_RANGE'])) {
// Parse the Range header
$range = $_SERVER['HTTP_RANGE'];
if (preg_match('/bytes=(\d*)-(\d*)/', $range, $matches)) {
$start = $matches[1] === '' ? 0 : intval($matches[1]);
$end = $matches[2] === '' ? $fileSize - 1 : intval($matches[2]);
// Validate range
if ($start > $end || $start >= $fileSize || $end >= $fileSize) {
http_response_code(416); // Range Not Satisfiable
header("Content-Range: bytes */$fileSize");
exit;
}
$length = $end - $start + 1;
http_response_code(206); // Partial Content
header("Content-Range: bytes $start-$end/$fileSize");
header("Content-Length: $length");
// Serve the requested range
$fp = fopen($localPath, 'rb');
fseek($fp, $start);
$remaining = $length;
while ($remaining > 0 && !feof($fp)) {
$chunk = min(8192, $remaining);
echo fread($fp, $chunk);
$remaining -= $chunk;
flush();
}
fclose($fp);
exit;
}
}
// No Range header - serve full file
header('Content-Length: ' . $fileSize);
readfile($localPath);
exit;
}
}
// If it's an external URL, proxy it with Range support
if (strpos($audioUrl, 'http') === 0) {
while (ob_get_level()) {
ob_end_clean();
}
// Build headers to forward to external server
$requestHeaders = [
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
];
// Forward Range header if present (for seeking support)
if (isset($_SERVER['HTTP_RANGE'])) {
$requestHeaders[] = 'Range: ' . $_SERVER['HTTP_RANGE'];
}
$ch = curl_init($audioUrl);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
// Capture response headers to forward them
$responseHeaders = [];
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use (&$responseHeaders) {
$len = strlen($header);
$header = trim($header);
if (empty($header)) return $len;
// Parse header
$parts = explode(':', $header, 2);
if (count($parts) == 2) {
$name = strtolower(trim($parts[0]));
$value = trim($parts[1]);
$responseHeaders[$name] = $value;
} elseif (strpos($header, 'HTTP/') === 0) {
// Status line - extract status code
if (preg_match('/HTTP\/\d\.?\d?\s+(\d+)/', $header, $matches)) {
$responseHeaders['_status'] = intval($matches[1]);
}
}
return $len;
});
// Buffer the response to get headers first, then stream
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
http_response_code(500);
header('Content-Type: text/plain');
echo "Failed to stream audio";
exit;
}
// Set appropriate status code (206 for partial content, 200 for full)
if ($httpCode == 206) {
http_response_code(206);
}
// Forward relevant headers
header('Content-Type: ' . ($responseHeaders['content-type'] ?? 'audio/mpeg'));
header('Accept-Ranges: bytes');
header('Cache-Control: public, max-age=3600');
if (isset($responseHeaders['content-length'])) {
header('Content-Length: ' . $responseHeaders['content-length']);
}
if (isset($responseHeaders['content-range'])) {
header('Content-Range: ' . $responseHeaders['content-range']);
}
// Output the body
echo $body;
exit;
}
http_response_code(404);
header('Content-Type: text/plain');
echo "Audio not available";
exit;
?>