Portions created by the Initial Developer are Copyright (C) 2008-2024 the Initial Developer. All Rights Reserved. Contributor(s): Mark J Crane */ //includes files require_once dirname(__DIR__, 2) . "/resources/require.php"; require_once "resources/check_auth.php"; //check permissions if (!permission_exists('voicemail_greeting_play') || (!permission_exists('voicemail_greeting_download') && !extension_assigned($_REQUEST["id"]))) { echo "access denied"; return; } //get voicemail id $voicemail_id = trim($_GET['id']); //used (above) to search the array to determine if an extension is assigned to the user /** * Checks if a specific extension has been assigned to the current user. * * @param string $number The extension number or alias to check for assignment. * * @return boolean True if the extension is assigned, false otherwise. */ function extension_assigned($number) { foreach ($_SESSION['user']['extension'] as $row) { if ((is_numeric($row['number_alias']) && $row['number_alias'] == $number) || $row['user'] == $number) { return true; } } return false; } //define name recording directory if (!empty($settings->get('switch', 'storage'))) { $recording_dir = $settings->get('switch', 'storage').'/voicemail/default/'.$_SESSION['domains'][$domain_uuid]['domain_name'].'/'.$voicemail_id; } //download the name recording if (permission_exists('voicemail_greeting_play') || permission_exists('voicemail_greeting_download')) { if (file_exists($recording_dir.'/recorded_name.wav')) { $fd = fopen($recording_dir.'/recorded_name.wav', "rb"); header("Content-Type: audio/x-wav"); header("Content-Disposition: attachment; filename='recorded_name.wav'"); header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past ob_clean(); //content-range if (isset($_SERVER['HTTP_RANGE'])) { range_download($recording_dir.'/recorded_name.wav'); } fpassthru($fd); } } //define the download function (helps safari play audio sources) /** * Downloads a file in range mode. * * This function sends the file to the client in chunks, allowing for partial downloads * and resuming from where the download was left off. * * @param string $file The path to the file being downloaded. */ function range_download($file) { $fp = @fopen($file, 'rb'); $size = filesize($file); // File size $length = $size; // Content length $start = 0; // Start byte $end = $size - 1; // End byte // Now that we've gotten so far without errors we send the accept range header /* At the moment we only support single ranges. * Multiple ranges requires some more work to ensure it works correctly * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 * * Multirange support annouces itself with: * header('Accept-Ranges: bytes'); * * Multirange content must be sent with multipart/byteranges mediatype, * (mediatype = mimetype) * as well as a boundry header to indicate the various chunks of data. */ header("Accept-Ranges: 0-$length"); // header('Accept-Ranges: bytes'); // multipart/byteranges // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2 if (isset($_SERVER['HTTP_RANGE'])) { $c_start = $start; $c_end = $end; // Extract the range string [, $range] = explode('=', $_SERVER['HTTP_RANGE'], 2); // Make sure the client hasn't sent us a multibyte range if (strpos($range, ',') !== false) { // (?) Shoud this be issued here, or should the first // range be used? Or should the header be ignored and // we output the whole content? header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes $start-$end/$size"); // (?) Echo some info to the client? exit; } // If the range starts with an '-' we start from the beginning // If not, we forward the file pointer // And make sure to get the end byte if spesified if (!empty($range0) && $range0 == '-') { // The n-number of the last bytes is requested $c_start = $size - substr($range, 1); } else { $range = explode('-', $range); $c_start = $range[0]; $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; } /* Check the range and make sure it's treated according to the specs. * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html */ // End bytes can not be larger than $end. $c_end = ($c_end > $end) ? $end : $c_end; // Validate the requested range and return an error if it's not correct. if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { header('HTTP/1.1 416 Requested Range Not Satisfiable'); header("Content-Range: bytes $start-$end/$size"); // (?) Echo some info to the client? exit; } $start = $c_start; $end = $c_end; $length = $end - $start + 1; // Calculate new content length fseek($fp, $start); header('HTTP/1.1 206 Partial Content'); } // Notify the client the byte range we'll be outputting header("Content-Range: bytes $start-$end/$size"); header("Content-Length: $length"); // Start buffered download $buffer = 1024 * 8; while(!feof($fp) && ($p = ftell($fp)) <= $end) { if ($p + $buffer > $end) { // In case we're only outputtin a chunk, make sure we don't // read past the length $buffer = $end - $p + 1; } set_time_limit(0); // Reset time limit for big files echo fread($fp, $buffer); flush(); // Free up memory. Otherwise large files will trigger PHP's memory limit. } fclose($fp); } ?>