![]() 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/.cursor-server/data/User/History/-63864ae4/ |
<?php
/**
* HLS Playlist Generator - Creates .m3u8 playlists for HLS streaming
* Includes encryption and authentication
*/
error_reporting(0);
ini_set('display_errors', 0);
ob_start();
session_start();
require_once __DIR__ . '/audio_token.php';
require_once __DIR__ . '/../config/database.php';
// Get parameters
$trackId = $_GET['id'] ?? '';
$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 token
if (empty($token) || empty($expires)) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied - missing token";
exit;
}
$user_id = $_SESSION['user_id'] ?? null;
$session_id = session_id();
if (!validateAudioToken($trackId, null, $token, $expires, $user_id, $session_id)) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied - invalid token";
exit;
}
// Get database connection
$pdo = getDBConnection();
if (!$pdo) {
http_response_code(500);
header('Content-Type: text/plain');
echo "Database error";
exit;
}
// Verify track access
$stmt = $pdo->prepare("SELECT id, task_id, audio_url, is_public, user_id, status 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
$isOwner = ($user_id && $track['user_id'] == $user_id);
$isPublic = ($track['is_public'] == 1);
if (!$isOwner && !$isPublic) {
http_response_code(403);
header('Content-Type: text/plain');
echo "Access denied";
exit;
}
// Get or create encryption key
function getEncryptionKeyId($trackId, $pdo) {
try {
$pdo->exec("
CREATE TABLE IF NOT EXISTS hls_encryption_keys (
id INT AUTO_INCREMENT PRIMARY KEY,
track_id INT NOT NULL,
key_id VARCHAR(64) NOT NULL,
encryption_key BINARY(16) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NULL,
INDEX idx_track_key (track_id, key_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
");
} catch (Exception $e) {}
$stmt = $pdo->prepare("
SELECT key_id FROM hls_encryption_keys
WHERE track_id = ?
AND (expires_at IS NULL OR expires_at > NOW())
ORDER BY created_at DESC LIMIT 1
");
$stmt->execute([$trackId]);
$key = $stmt->fetch(PDO::FETCH_ASSOC);
if ($key) {
return $key['key_id'];
}
// Generate new key
$newKey = random_bytes(16);
$newKeyId = bin2hex(random_bytes(16));
$stmt = $pdo->prepare("
INSERT INTO hls_encryption_keys (track_id, key_id, encryption_key, expires_at)
VALUES (?, ?, ?, DATE_ADD(NOW(), INTERVAL 24 HOUR))
");
$stmt->execute([$trackId, $newKeyId, $newKey]);
return $newKeyId;
}
$keyId = getEncryptionKeyId($trackId, $pdo);
// Check if HLS segments exist
$hlsBasePath = $_SERVER['DOCUMENT_ROOT'] . '/hls/' . $trackId;
$playlistPath = $hlsBasePath . '/playlist.m3u8';
// If HLS not available, fallback to regular audio
if (!file_exists($playlistPath)) {
// Redirect to regular audio playback (backward compatibility)
$audioUrl = '/utils/play_audio.php?id=' . $trackId . '&token=' . urlencode($token) . '&expires=' . $expires;
header('Location: ' . $audioUrl);
exit;
}
// Generate authenticated URLs
$keyUrl = '/utils/hls_key_server.php?key_id=' . urlencode($keyId) .
'&track_id=' . $trackId .
'&token=' . urlencode($token) .
'&expires=' . $expires;
// Read the master playlist
$playlistContent = file_get_contents($playlistPath);
// Replace segment URLs with authenticated endpoints
// Pattern: segment_000.ts or /path/segment_000.ts -> authenticated URL
$playlistContent = preg_replace_callback(
'/(?:^|\/)(segment_\d+\.ts)/m',
function($matches) use ($trackId, $token, $expires) {
$segmentName = $matches[1];
return '/utils/hls_segment.php?track_id=' . $trackId .
'&segment=' . urlencode($segmentName) .
'&token=' . urlencode($token) .
'&expires=' . $expires;
},
$playlistContent
);
// Inject or update encryption key URI
$encryptionLine = '#EXT-X-KEY:METHOD=AES-128,URI="' . $keyUrl . '"';
if (strpos($playlistContent, '#EXT-X-KEY') === false) {
// Add encryption before first segment
$playlistContent = preg_replace(
'/(#EXTINF)/',
$encryptionLine . "\n" . '$1',
$playlistContent,
1
);
} else {
// Replace existing key URI (including placeholder)
$playlistContent = preg_replace(
'/#EXT-X-KEY:METHOD=AES-128,URI="[^"]*"/',
'#EXT-X-KEY:METHOD=AES-128,URI="' . $keyUrl . '"',
$playlistContent
);
}
// Serve the playlist
header('Content-Type: application/vnd.apple.mpegurl');
header('Cache-Control: private, no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
echo $playlistContent;
exit;
?>