Id()) { header('HTTP/1.1 404 Not Found'); die('Event not found'); } // Per-event ACL: coarse canView('Events') isn't enough — the user may be denied // access to the monitor that owns this event (GHSA-vj5r-pc2v-gfwv). Return the // same 404 as a missing event so the id isn't leaked. if (!$Event->canView()) { ZM\Warning('Event '.$_REQUEST['eid'].' HLS access denied'); header('HTTP/1.1 404 Not Found'); die('Event not found'); } $m3u8_path = $Event->Path() . '/index.m3u8'; if (!file_exists($m3u8_path)) { header('HTTP/1.1 204 No Content'); header('Cache-Control: no-cache'); exit; } $m3u8_content_check = file_get_contents($m3u8_path); if ($m3u8_content_check === false) { header('HTTP/1.1 204 No Content'); header('Cache-Control: no-cache'); ZM\Debug('HLS manifest ' . $m3u8_path . ' is not available yet'); exit; } else if (strpos($m3u8_content_check, '#EXTINF:') === false) { header('HTTP/1.1 204 No Content'); header('Cache-Control: no-cache'); ZM\Debug('HLS manifest ' . $m3u8_path .' has no fragments yet'); exit; } // Build auth query string for segment URLs $auth_query = ''; if (ZM_OPT_USE_AUTH) { if (ZM_AUTH_RELAY == 'hashed') { $auth_query = '&auth=' . generateAuthHash(ZM_AUTH_HASH_IPS); } else if (ZM_AUTH_RELAY == 'plain') { $auth_query = '&user=' . $_SESSION['username'] . '&pass=' . $_SESSION['password']; } else if (ZM_AUTH_RELAY == 'none') { $auth_query = '&user=' . $_SESSION['username']; } } // Read the m3u8 and inject auth tokens into segment URLs $content = file_get_contents($m3u8_path); // The m3u8 has relative URLs like "index.php?view=view_video&eid=123" // We need to make them absolute with the server path and add auth $Server = $Event->Server(); $base_url = $Server->PathToIndex(); // Replace bare relative segment URLs with full paths including auth. // The m3u8 has lines like "index.php?view=view_video&eid=N&file=F" — capture // only the query string (after "index.php?") so the replacement doesn't emit // "/zm/index.php?index.php?view=…". $content = preg_replace( '/^index\.php\?(.+)$/m', $base_url . '?$1' . $auth_query, $content ); // Also fix the EXT-X-MAP URI (initialization segment) the same way. $content = preg_replace( '/URI="index\.php\?([^"]+)"/m', 'URI="' . $base_url . '?$1' . $auth_query . '"', $content ); header('Content-Type: application/vnd.apple.mpegurl'); header('Cache-Control: no-cache'); echo $content; exit;