- Статьи из других ресурсов
- «Допиливаем» Asterisk CDR Viewer под себя
«Я профессионал, потому что не ленюсь искать информацию в google» — сказал мне однажды коллега.
А я поленился и начал «допиливать» CDR Viewer под себя, даже не посмотрев хотя бы вот это.
А может и не в лени дело, просто было интересно… в общем, что из этого вышло можно посмотреть под катом:)
Споры о том, что лучше использовать в качестве офисной АТС — asterisk (с веб-интерфейсом или без, хотя это отдельная тема для споров) или какую-то коробку типа Panasonic, которых на рынок выкинуто немеренное количество — не утихают до сих пор, но топик не об этом, лично для себя я уже давно определился. Хотелось бы поделиться с сообществом своим вариантом придания интерфейсу просмотра статистики дополнительного фунционала.
В качестве «подопытного» я использовал FreePBX Distro (FreePBX 2.11, Asterisk 11, CentOS 6.5), скачанный с официального сайтапроекта. Выбор был продиктован тем, что разработчики FreePBX уже позаботились о прикручивании БД к Asterisk и структура хранения записей в общем-то меня устраивает. Хотя процедура «прикручивания» MySQL или какой-либо другой базы к Asterisk была описана ни раз и ни два, о чем можно почитать например здесь, все же в целях экономии времени я решил этого не делать.
За основу был взят Asterisk CDR Viewer (если не нужно каких-то сверхмудреных отчетов — то вполне себе пригодная и простенькая статистика), скачать можно тут.
Установка CDR Viewer не представляется какой-то нетривиальной задачей.
Переходим в нужную нам директорию, качаем архив, извлекаем файлы из архива:
cd /var/www
wget https://asterisk-cdr-viewer.googlecode.com/files/asterisk-cdr-viewer-1.0.2.tgz
tar -xzvf asterisk-cdr-viewer-1.0.2.tgz
Переносим файлик алиаса в папку с apache2:
cp /var/www/html/asterisk-cdr-viewer/contrib/httpd/asterisk-cdr-viewer.conf /etc/apache2/conf.d/asterisk-cdr-viewer.conf
Изменяем настройки подключения к БД для Asterisk-CDR-viewer
cd /var/www/asterisk-cdr-viewer/include/
vim config.inc.php
Нужно поменять параметры в соответствии с текущей конфигурацией вашей базы:
$db_user = '[MySQL пользователь]';
$db_pass = '[MySQL пароль]';
$db_name = '[Имя базы]';
Делаем рестарт веб-сервера:
service apache2 restart
Теперь в браузере набирая [адрес asteridk-сервера]/acdr/ попадаем на страницу статистики.
Первое, что мне захотелось сделать — прикрутить авторизацию для просмотра этой самой статистики, для этого воспользуемся htpasswd.
Если не установлена —
aptitude install apache2-utils
Переходим в /etc/apache2 и созадем юзер/пароль для статистики:
htpasswd -c passwordfile username
Вводим пароль в диалоге, который предлагает htpasswd и получаем файл «passwordfile» с юзером «username» и сгенерированным зашифрованным паролем.
Далее в /etc/apache2/conf.d изменяем asterisk-cdr-viewer.conf, раскомментрировав строки авторизации, в результате получаем:
Alias /acdr/ "/var/www/asterisk-cdr-viewer/"
<Location "/acdr/">
<------>AuthName «Asterisk-CDR-Stat»
<------>AuthType Basic
<------>AuthUserFile /etc/apache2/passwordfile
<------>AuthGroupFile /dev/null
<------>require valid-user
Рестартуем apache2 и при входе на страницу видим окно авторизации:
Следующее, что был сделано — это прослушивание разговоров из веб-интерфейса.
1) Для прослушивания звонков добавляем две иконки в каталог /var/www/asterisk-cdr-viewer/templates/images (play и stop)
2) Добавляем в /var/www/asterisk-cdr-viewer/templates/header.tpl.php объявление js-функции для оптимизации производительности;
<head>
<title>Asterisk Call Detail Records</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
<link rel="stylesheet" href="style/screen.css" type="text/css" media="screen" />
<link rel="shortcut icon" href="templates/images/favicon.ico" />
<script type="text/javascript"/>
function audioPreview(e,cnc) {
var uri = e.attributes.getNamedItem('data-uri').value;
var audioElement;
// 1 if not exists audio control, then create it:
if (!(audioElement = document.getElementById('au_preview'))) {
audioElement = document.createElement('audio');
audioElement.id = 'au_preview';
audioElement.controls = true;
audioElement.style.display = 'none';
document.body.appendChild(audioElement);
}
else {
// 2 need to stop and hide if playing:
var prevIcon = audioElement.parentNode.previousSibling;
prevIcon.src = 'templates/images/play.png';
prevIcon.onclick = function(){ return audioPreview(prevIcon,false);};
}
if (('undefined'===typeof cnc)||(!cnc)) {
//1. to show
e.nextSibling.appendChild(audioElement);
audioElement.src = uri;
audioElement.style.display = 'block';
audioElement.play();
e.onclick = function(){ return audioPreview(e,true); };
e.src = 'templates/images/stop.png';
}
else {
//2. to hide
audioElement.pause();
audioElement.style.display = 'none';
e.onclick = function(){ return audioPreview(e,false); };
e.src = 'templates/images/play.png';
}
}</script>
</head>
<body>
<table id="header">
<tr>
<td id="header_logo" rowspan="2" align="left"><a href="/" title="Home"><img src="" alt="Asterisk CDR Viewer" /></a></td>
<td id="header_title">Asterisk CDR Viewer</td>
<td align='right'>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=XVUVZY5D922JJ&lc=RU&item_name=i%2eo%2e&item_number=asterisk%2dcdr¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted"><img src="http://habrastorage.org/getpro/habr/post_images/92a/7cd/b91/92a7cdb914a8e942ca23d0ec49367cc3.gif" align="center"/></a>
</td>
</tr>
<tr>
<td id="header_subtitle"> </td>
<td align='right'>
<?php
if ( strlen(getenv('REMOTE_USER')) ) {
echo "<a href='/acdr/index.php?action=logout'>logout: ". getenv('REMOTE_USER') ."</a>";
}
?>
</td>
</tr>
</table>
3)
<head>
<title>Asterisk Call Detail Records</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8" />
<link rel="stylesheet" href="style/screen.css" type="text/css" media="screen" />
<link rel="shortcut icon" href="templates/images/favicon.ico" />
<script type="text/javascript"/>
function audioPreview(e,cnc) {
var uri = e.attributes.getNamedItem('data-uri').value;
var audioElement;
// 1 if not exists audio control, then create it:
if (!(audioElement = document.getElementById('au_preview'))) {
audioElement = document.createElement('audio');
audioElement.id = 'au_preview';
audioElement.controls = true;
audioElement.style.display = 'none';
document.body.appendChild(audioElement);
}
else {
// 2 need to stop and hide if playing:
var prevIcon = audioElement.parentNode.previousSibling;
prevIcon.src = 'templates/images/play.png';
prevIcon.onclick = function(){ return audioPreview(prevIcon,false);};
}
if (('undefined'===typeof cnc)||(!cnc)) {
//1. to show
e.nextSibling.appendChild(audioElement);
audioElement.src = uri;
audioElement.style.display = 'block';
audioElement.play();
e.onclick = function(){ return audioPreview(e,true); };
e.src = 'templates/images/stop.png';
}
else {
//2. to hide
audioElement.pause();
audioElement.style.display = 'none';
e.onclick = function(){ return audioPreview(e,false); };
e.src = 'templates/images/play.png';
}
}</script>
</head>
<body>
<table id="header">
<tr>
<td id="header_logo" rowspan="2" align="left"><a href="/" title="Home"><img src="" alt="Asterisk CDR Viewer" /></a></td>
<td id="header_title">Asterisk CDR Viewer</td>
<td align='right'>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=XVUVZY5D922JJ&lc=RU&item_name=i%2eo%2e&item_number=asterisk%2dcdr¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted"><img src="" align="center"/></a>
</td>
</tr>
<tr>
<td id="header_subtitle"> </td>
<td align='right'>
<?php
if ( strlen(getenv('REMOTE_USER')) ) {
echo "<a href='/acdr/index.php?action=logout'>logout: ". getenv('REMOTE_USER') ."</a>";
}
?>
</td>
</tr>
</table>
root@sip:/var/www/asterisk-cdr-viewer/templates#
root@sip:/var/www/asterisk-cdr-viewer/include# cat functions.inc.php
<?php
/* Recorded file */
function formatFiles($row) {
global $system_monitor_dir, $system_fax_archive_dir, $system_audio_format, $system_arch_audio_format;
/* File name formats, please specify: */
/*
caller-called-timestamp.wav
*/
/*
$recorded_file = $row['src'] .'-'. $row['dst'] .'-'. $row['call_timestamp']
*/
/* ============================================================================ */
/*
ends at the uniqueid.wav, for example:
date-time-uniqueid.wav
thanks to Beto Reyes
*/
/*
$recorded_file = glob($system_monitor_dir . '/*' . $row['uniqueid'] . '.' . $system_audio_format);
if (count($recorded_file)>0) {
$recorded_file = basename($recorded_file[0],".$system_audio_format");
} else {
$recorded_file = $row['uniqueid'];
}
*/
/* ============================================================================ */
/* This example for multi-directory archive without uniqueid, named by format:
<date>/<time>_<caller>-<destination>.<filetype>
example: (tree /var/spool/asterisk/monitor)
|-- 2012.09.12
| |-- 10-37_4952704601-763245.ogg
| `-- 10-43_106-79236522173.ogg
`-- 2012.09.13
|-- 11-42_101-79016410692.ogg
|-- 12-43_104-671554.ogg
`-- 15-49_109-279710.ogg
Added by BAXMAH (pcm@ritm.omsk.ru)
*/
/*
$record_datetime = DateTime::createFromFormat('Y-m-d G:i:s', $row['calldate']);
$recorded_file = date_format($record_datetime, 'Y.m.d/G-i') .'_'. $row['src'] .'-'. $row['dst'];
*/
/* ============================================================================ */
/*
This is a multi-dir search script for filenames like "/var/spool/asterisk/monitor/dir1/dir2/dir3/*uniqueid*.*"
Doesn't matter, WAV, MP3 or other file format, only UNIQID is required at the end of the filename
;---------------------------------------------------------------------------
example: (tree /var/spool/asterisk/monitor)
|-- in
| |-- 4951234567
| | `-- 20120101_234231_4956401234_to_74951234567_1307542950.0.wav
| `-- 4997654321
| `-- 20120202_234231_4956401234_to_74997654321_1303542950.0.wav
`-- out
|-- msk
| `-- 20120125_211231_4956401234_to_74951234567_1307542950.0.wav
`-- region
`-- 20120112_211231_4956405570_to_74952210533_1307542950.0.wav
6 directories, 4 files
;----------------------------------------------------------------------------
added by Dein admin@sadmin.ru
*/
//************ Get a list of subdirectories as array to search by glob function **************
if (!function_exists('get_dir_list')) {
function get_dir_list($dir){
global $dirlist;
$dirlist=array();
if (!function_exists('find_dirs_recursive')) {
function find_dirs_recursive($sdir) {
global $dirlist;
foreach(glob($sdir) as $filename) {
//echo $filename;
if(is_dir($filename)) {
$dirlist[]=$filename;
find_dirs_recursive($filename."/*");
};//endif
};//endforeach
}; //endfunc
};//endif exists
find_dirs_recursive($dir."/*");
};//endfunc
}
//*************** Main function ************
if (!function_exists('find_record_by_uniqid')) {
function find_record_by_uniqid($path,$uniqid){
global $dirlist;
if (sizeof($dirlist) == 0 ){
get_dir_list($path);
};//endif size==0
if (sizeof($dirlist) == 0 ) {return "SOME ERROR, dirlist is empty";};
$found = "NOTHING FOUND";
foreach ($dirlist as $curdir) {
$res=glob($curdir."/*".$uniqid.".*");
if ($res) {$found=$res[0]; break;};
};//endforeach
$res=str_replace($path,"",$found); //cut $path from full filename
return $res; //to be compartable with func. formatFiles($row)
};//endfunc
}
$recorded_file = find_record_by_uniqid($system_monitor_dir,$row['uniqueid']);
/* ============================================================================ */
/*
uniqueid.wav
*/
// $recorded_file = $row['filename'];
/* ============================================================================ */
if (file_exists("$system_monitor_dir/$recorded_file.$system_audio_format")) {
// insert here:
echo " <td class=\"record_col\"><div class=\"record_ctrl\"><a href=\"download.php?audio=$recorded_file.$system_audio_format\" title=\"Listen to call recording\"><img src= recording\" /></a><img class=\"record_preview_icon\" src= onclick=\"audioPreview(this,false);\"/><div class=\"record_preview_lt\"></div></div></td>\n";
} elseif ( isset($system_arch_audio_format) and file_exists("$system_monitor_dir/$recorded_file.$system_audio_format.$system_arch_audio_format")) {
echo " <td class=\"record_col\"><a href=\"download.php?arch=$recorded_file.$system_audio_format.$system_arch_audio_format\" title=\"Download archive\"><img src= recording\" /></a></td>\n";
} elseif (file_exists("$system_fax_archive_dir/$recorded_file.tif")) {
echo " <td class=\"record_col\"><a href=\"download.php?fax=$recorded_file.tif\" title=\"View FAX image\"><img src= image\" /></a></td>\n";
} elseif (file_exists("$system_monitor_dir/$recorded_file"))
{ // insert here:
echo " <td class=\"record_col\"><div class=\"record_ctrl\"><a href=\"download.php?audio=$recorded_file\" title=\"Listen to call recording\"><img src= recording\" /></a><img class=\"record_preview_icon\" src= onclick=\"audioPreview(this,false);\"/><div class=\"record_preview_lt\"></div></div></td>\n";
} else {
echo " <td class=\"record_col\"></td>\n";
}
}
/* CDR Table Display Functions */
function formatCallDate($calldate,$uniqueid) {
echo " <td class=\"record_col\"><abbr title=\"UniqueID: $uniqueid\">$calldate</abbr></td>\n";
}
function formatChannel($channel) {
$trunk_name = preg_replace('/(.*)-[^-]+$/','$1',$channel);
echo " <td class=\"record_col\"><abbr title=\"Channel: $channel\">$trunk_name</abbr></td>\n";
}
function formatClid($clid) {
$clid_only = explode(' <', $clid, 2);
$clid = htmlspecialchars($clid_only[0]);
echo " <td class=\"record_col\">$clid</td>\n";
}
function formatSrc($src,$clid) {
if (empty($src)) {
echo " <td class=\"record_col\">UNKNOWN</td>\n";
} else {
$src = htmlspecialchars($src);
$clid = htmlspecialchars($clid);
echo " <td class=\"record_col\"><abbr title=\"Caller*ID: $clid\">$src</abbr></td>\n";
}
}
function formatApp($app, $lastdata) {
echo " <td class=\"record_col\"><abbr title=\"Application: $app($lastdata)\">$app</abbr></td>\n";
}
function formatDst($dst, $dcontext) {
global $rev_lookup_url;
if (strlen($dst) == 11 and strlen($rev_lookup_url) > 0 ) {
$rev = str_replace('%n', $dst, $rev_lookup_url);
echo " <td class=\"record_col\"><abbr title=\"Destination Context: $dcontext\"><a href=\"$rev\" target=\"reverse\">$dst</a></abbr></td>\n";
} else {
echo " <td class=\"record_col\"><abbr title=\"Destination Context: $dcontext\">$dst</abbr></td>\n";
}
}
function formatDisposition($disposition, $amaflags) {
switch ($amaflags) {
case 0:
$amaflags = 'DOCUMENTATION';
break;
case 1:
$amaflags = 'IGNORE';
break;
case 2:
$amaflags = 'BILLING';
break;
case 3:
default:
$amaflags = 'DEFAULT';
}
echo " <td class=\"record_col\"><abbr title=\"AMA Flag: $amaflags\">$disposition</abbr></td>\n";
}
function formatDuration($duration, $billsec) {
$duration = sprintf('%02d', intval($duration/60)).':'.sprintf('%02d', intval($duration%60));
$billduration = sprintf('%02d', intval($billsec/60)).':'.sprintf('%02d', intval($billsec%60));
echo " <td class=\"record_col\"><abbr title=\"Billing Duration: $billduration\">$duration</abbr></td>\n";
}
function formatUserField($userfield) {
echo " <td class=\"record_col\">$userfield</td>\n";
}
function formatAccountCode($accountcode) {
echo " <td class=\"record_col\">$accountcode</td>\n";
}
/* Asterisk RegExp parser */
function asteriskregexp2sqllike( $source_data, $user_num ) {
$number = $user_num;
if ( strlen($number) < 1 ) {
$number = $_REQUEST[$source_data];
}
if ( '__' == substr($number,0,2) ) {
$number = substr($number,1);
} elseif ( '_' == substr($number,0,1) ) {
$number_chars = preg_split('//', substr($number,1), -1, PREG_SPLIT_NO_EMPTY);
$number = '';
foreach ($number_chars as $chr) {
if ( $chr == 'X' ) {
$number .= '[0-9]';
} elseif ( $chr == 'Z' ) {
$number .= '[1-9]';
} elseif ( $chr == 'N' ) {
$number .= '[2-9]';
} elseif ( $chr == '.' ) {
$number .= '.+';
} elseif ( $chr == '!' ) {
$_REQUEST[ $source_data .'_neg' ] = 'true';
} else {
$number .= $chr;
}
}
$_REQUEST[ $source_data .'_mod' ] = 'asterisk-regexp';
}
return $number;
}
/* empty() wrapper. Thanks to Mikael Carlsson. */
function is_blank($value) {
return empty($value) && !is_numeric($value);
}
/*
Money format
thanks to Shiena Tadeo
*/
function formatMoney($number, $cents = 2) { // cents: 0=never, 1=if needed, 2=always
global $callrate_currency;
if (is_numeric($number)) { // a number
if (!$number) { // zero
$money = ($cents == 2 ? '0.00' : '0'); // output zero
} else { // value
if (floor($number) == $number) { // whole number
$money = number_format($number, ($cents == 2 ? 2 : 0)); // format
} else { // cents
$money = number_format(round($number, 2), ($cents == 0 ? 0 : 2)); // format
} // integer or decimal
} // value
echo "<td class=\"chart_data\">$callrate_currency<span>$money</span></td>\n";
} else {
echo "<td class=\"chart_data\"> </td>\n";
}
} // formatMoney
/*
CallRate
return callrate array [ areacode, rate, description, bill type, total_rate]
*/
function callrates($dst,$duration,$file) {
global $callrate_csv_file, $callrate_cache;
if ( strlen($file) == 0 ) {
$file = $callrate_csv_file;
if ( strlen($file) == 0 ) {
return array('','','','','');
}
}
if ( ! array_key_exists( $file, $callrate_cache ) ) {
$callrate_cache[$file] = array();
$fr = fopen($file, "r") or die("Can not open callrate file ($file).");
while(($fr_data = fgetcsv($fr, 1000, ",")) !== false) {
$callrate_cache[$file]["$fr_data[0]"] = array( $fr_data[1], $fr_data[2], $fr_data[3] );
}
fclose($fr);
}
for ( $i = strlen($dst); $i > 0; $i-- ) {
if ( array_key_exists( substr($dst,0,$i), $callrate_cache[$file] ) ) {
$call_rate = 0;
if ( $callrate_cache[$file][substr($dst,0,$i)][2] == 's' ) {
// per second
$call_rate = $duration * ($callrate_cache[$file][substr($dst,0,$i)][0] / 60);
} elseif ( $callrate_cache[$file][substr($dst,0,$i)][2] == 'c' ) {
// per call
$call_rate = $callrate_cache[$file][substr($dst,0,$i)][0];
} elseif ( $callrate_cache[$file][substr($dst,0,$i)][2] == '1m+s' ) {
// 1 minute + per second
if ( $duration < 60) {
$call_rate = $callrate_cache[$file][substr($dst,0,$i)][0];
} else {
$call_rate = $callrate_cache[$file][substr($dst,0,$i)][0] + ( ($duration-60) * ($callrate_cache[$file][substr($dst,0,$i)][0] / 60) );
}
} else {
//( $callrate_cache[substr($dst,0,$i)][2] == 'm' ) {
// per minute
$call_rate = intval($duration/60);
if ( $duration%60 > 0 ) {
$call_rate++;
}
$call_rate = $call_rate*$callrate_cache[$file][substr($dst,0,$i)][0];
}
return array(substr($dst,0,$i),$callrate_cache[$file][substr($dst,0,$i)][0],$callrate_cache[$file][substr($dst,0,$i)][1],$callrate_cache[$file][substr($dst,0,$i)][2],$call_rate);
}
}
return array (0,0,'unknown','unknown',0);
}
?>
4)
/* HTML tag styles */
a {
cursor : pointer;
}
abbr[title] {
border-style : none none dashed;
border-width : medium medium 1px;
border-bottom-color : #000000;
cursor : help;
white-space : nowrap;
}
body {
background-color : #fff;
/* Fix for M$ IE < 7 CSS hover */ behavior : url('style/csshover.htc');
color : #000;
font : 65% Verdana, Arial, Helvetica, sans-serif;
margin : 0;
padding : 0;
}
img {
border-width : 0;
}
/* ID styles */
#header {
background-image : url('../templates/images/header_gradient.png');
background-repeat : repeat-x;
margin : 0;
padding-left : 5%;
padding-right : 10%;
position : fixed;
width : 100%;
z-index : 50;
}
#header_logo {
height: 105px;
width: 121px;
vertical-align: top;
}
#header_title {
color: #000000;
font-family: serif;
font-size: 32pt;
font-variant: small-caps;
font-weight: bold;
height: 60px;
}
#header_subtitle {
color: #68878a;
font-family: Verdana,Arial,'Bitstream Vera Sans',Helvetica,sans-serif;
font-size: 12pt;
font-weight: bold;
height: 60px;
padding-left: 10px;
vertical-align: top;
}
#main {
margin : 0;
padding-top : 115px;
}
#footer {
padding : 5px;
border-width : 0;
text-align : center;
}
/* Class styles */
.bar_calls {
background-color : #aaf5d0;
float : none;
padding : 0 0 0 2px;
}
.bar_duration {
background-color : #e5edf9;
float : none;
padding : 0 0 0 2px;
}
.cdr {
margin : 0 2%;
border-width : 0;
white-space : nowrap;
width : 96%;
}
.cdr th {
background-color : #5ebeff;
border-color : #000;
border-width : 2px;
text-align : center;
}
.cdr .center_col {
width : 78%;
padding : 2px;
}
.cdr .end_col {
width : 11%;
padding : 1px;
}
.cdr .chart_data {
padding : 0px;
text-align : right;
}
.cdr .img_col {
width : 16px;
height : 16px;
}
.form legend, .title, .title a {
color: #777;
font-size: 2em;
font-weight: bold;
}
.record {
background-color : #fff;
empty-cells : hide;
}
.record:hover {
background : #ffdca8;
color : #000;
empty-cells : hide;
}
.record_col {
padding-left : 2px;
padding-right : 2px;
border-width : 0;
}
.center {
text-align : center;
}
.right {
padding-right : 80px;
text-align : right;
font-size: 9pt;
}
.record_ctrl {
position:relative
}
.record_preview_icon {
width:16px;
height:16px;
cursor:pointer;
margin-left:3px;
}
.record_preview_lt {
position:absolute;
top:0;
left:38px;
z-index:99;
}
5)
<?php
require_once 'include/config.inc.php';
header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
header('Pragma: no-cache');
function partial_download($range_header, $request_file, $mime) {
$file_size = filesize($request_file);
list($b, $range) = explode('=', $range_header);
list($first_range) = explode(',', $range);
list($part_start,$part_end) = explode('-', $first_range);
$start = intval($part_start);
if ($part_end)
$end = intval($part_end);
else
$end = $file_size - 1;
$chunksize = ($end-$start)+1;
header('HTTP/1.1 206 Partial Content');
header("Content-Type: $mime");
header('Content-Transfer-Encoding: binary');
header("Content-Range: bytes $start-$end/$file_size");
header('Content-Length: '.$chunksize);
# header("Content-Disposition: attachment; filename=\"$_REQUEST[audio]\"");
$fp = fopen($request_file, 'r');
fseek($fp, $start, SEEK_SET);
echo fread($fp, $chunksize);
fclose($fp);
}
if (isset($_REQUEST['audio'])) {
$extension = strtolower(substr(strrchr($_REQUEST['audio'],"."),1));
$ctype ='';
switch( $extension ) {
case "wav16":
$ctype="audio/x-wav";
break;
case "wav":
$ctype="audio/x-wav";
break;
case "ulaw":
$ctype="audio/basic";
break;
case "alaw":
$ctype="audio/x-alaw-basic";
break;
case "sln":
$ctype="audio/x-wav";
break;
case "gsm":
$ctype="audio/x-gsm";
break;
case "g729":
$ctype="audio/x-g729";
break;
default:
$ctype="application/$system_audio_format";
break ;
}
header("Accept-Ranges: bytes");
if (!isset($_SERVER['HTTP_RANGE'])) {
header("Content-Type: $ctype");
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize("$system_monitor_dir/$_REQUEST[audio]"));
header("Content-Disposition: attachment; filename=\"$_REQUEST[audio]\"");
readfile("$system_monitor_dir/$_REQUEST[audio]");
}
else {
partial_download($_SERVER['HTTP_RANGE'], "$system_monitor_dir/$_REQUEST[audio]", $ctype);
}
} elseif (isset($_REQUEST['fax'])) {
header('Content-Type: image/tiff');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize("$system_fax_archive_dir/$_REQUEST[fax]"));
header("Content-Disposition: attachment; filename=\"$_REQUEST[fax]\"");
readfile("$system_fax_archive_dir/$_REQUEST[fax]");
} elseif (isset($_REQUEST['csv'])) {
header('Content-Type: text/csv');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize("/tmp/$_REQUEST[csv]"));
header("Content-Disposition: attachment; filename=\"$_REQUEST[csv]\"");
readfile("$system_tmp_dir/$_REQUEST[csv]");
} elseif (isset($_REQUEST['arch'])) {
header('Content-Type: application/x-download');
header('Content-Transfer-Encoding: binary');
header('Content-Length: '.filesize("$system_monitor_dir/$_REQUEST[arch]"));
header("Content-Disposition: attachment; filename=\"$_REQUEST[arch]\"");
readfile("$system_monitor_dir/$_REQUEST[arch]");
}
exit();
?>
В результате получаем возможность прослушивания разговоров в веб-интерфейсе (мотать по бегунку прокрутки можно)
Надеюсь кому-нибудь пригодится:)