'video/mp4', 'mkv' => 'video/x-matroska', 'avi' => 'video/x-msvideo', 'mov' => 'video/quicktime', 'wmv' => 'video/x-ms-wmv', 'flv' => 'video/x-flv', 'webm' => 'video/webm', 'm4v' => 'video/x-m4v', // Audio 'mp3' => 'audio/mpeg', 'wav' => 'audio/wav', 'ogg' => 'audio/ogg', 'flac' => 'audio/flac', 'm4a' => 'audio/mp4', 'aac' => 'audio/aac', 'wma' => 'audio/x-ms-wma', 'opus' => 'audio/opus' ]; $contentType = isset($mimeTypes[$fileExtension]) ? $mimeTypes[$fileExtension] : 'application/octet-stream'; // Handle range requests for seeking $range = isset($_SERVER['HTTP_RANGE']) ? $_SERVER['HTTP_RANGE'] : ''; if (!empty($range)) { // Parse range header list($unit, $range) = explode('=', $range, 2); if ($unit === 'bytes') { // Parse range values list($start, $end) = explode('-', $range, 2); $start = intval($start); $end = !empty($end) ? intval($end) : $fileSize - 1; // Validate range if ($start > $end || $start < 0 || $end >= $fileSize) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes */$fileSize"); exit; } $length = $end - $start + 1; // Set headers for partial content header('HTTP/1.1 206 Partial Content'); header("Content-Range: bytes $start-$end/$fileSize"); header("Content-Length: $length"); header("Content-Type: $contentType"); header('Accept-Ranges: bytes'); // Open file and seek to start position $file = fopen($filePath, 'rb'); if ($file === false) { header('HTTP/1.1 500 Internal Server Error'); echo 'Failed to open file'; exit; } fseek($file, $start); // Output the requested range $buffer = 8192; // 8KB chunks $bytesRemaining = $length; while ($bytesRemaining > 0 && !feof($file)) { $bytesToRead = min($buffer, $bytesRemaining); $data = fread($file, $bytesToRead); if ($data === false) { break; } echo $data; $bytesRemaining -= strlen($data); if (connection_aborted()) { break; } } fclose($file); exit; // Important: exit after streaming } } else { // Normal full file response header('HTTP/1.1 200 OK'); header("Content-Type: $contentType"); header("Content-Length: $fileSize"); header('Accept-Ranges: bytes'); header('Cache-Control: public, max-age=3600'); // Stream file in chunks to avoid memory issues $file = fopen($filePath, 'rb'); if ($file === false) { header('HTTP/1.1 500 Internal Server Error'); echo 'Failed to open file'; exit; } $buffer = 8192; // 8KB chunks while (!feof($file) && !connection_aborted()) { echo fread($file, $buffer); } fclose($file); exit; // Important: exit after streaming } ?>