Версии ПО
FreePBX 2.11.0.41
Asternic CDR Reports 1.5.1
Введение
Задача: необходимо дать человеку возможность прослушивать записи разговоров, но строго на определённом диапазоне внутренних экстеншенов. Мы пытаемся создать нового администратора и даже прописываем ему Extension Range, надеясь таким образом дать ему ограниченный доступ к прослушиванию
Но потом, заходя под созданной учётной записью и направляясь в отчёты по звонкам, понимаем, что потерпели фиаско — CDR Reports игнорирует заданный диапазон Extension Range и выводит информацию по всем номерам.
Почесав в затылке, ищем альтернативный модуль отчётов — и, о чудо, находим его: Asternic CDR Reports. Он замечательный и работает только с теми номерами, диапазон которых ограничен для авторизовавшегося администратора.
Но что это? Нет прослушивания звонков? В столбце Listen выводится голосовая почта? Нет, так дело не пойдёт…
Исправляем
Информация о звонках в Asterisk`е хранится в Mysql в базе «asteriskcdrdb», таблица cdr. Это видно из следующего кода, взятого из файла page.cdr.php обычного CDR Reports
$resultscdr = $dbcdr->getAll($query, DB_FETCHMODE_ASSOC);
...
foreach($resultscdr as $row)
...
if ($row['recordingfile']) {
$rec_parts = explode('-',$row['recordingfile']);
$fyear = substr($rec_parts[3],0,4);
$fmonth = substr($rec_parts[3],4,2);
$fday = substr($rec_parts[3],6,2);
$monitor_base = $amp_conf['MIXMON_DIR'] ? $amp_conf['MIXMON_DIR'] : $amp_conf['ASTSPOOLDIR'] . '/monitor';
$recordingfile = "$monitor_base/$fyear/$fmonth/$fday/" . $row['recordingfile'];
if (!file_exists($recordingfile)) {
$recordingfile = '';
}
} else {
$recordingfile = '';
}
Значит, всё, что нам нужно — это прочитать значение ячейки recordingfile, где хранится строка «имя_файла.wav» и добавить к нему полный путь к этому файлу, который берётся, кстати, из самого же имени файла (год, месяц, день).
Открываем файл /var/www/html/admin/modules/asternic_cdr/functions.inc.php модуля Asternic.
Ищем строку 154
$query.= "billsec,duration,duration-billsec as ringtime,src,";
и заменяем на
$query.= "billsec,duration,duration-billsec as ringtime,src,recordingfile,";
Так в запрос к базе мы добавили поле recordingfile, значение которого, соответственно, теперь будет и в результирующем массиве, из которого мы его потом возьмём для формирования ссылки на файл.
Ищем строку 208
$detail[$row['chan1']].= "\n<td>";
$uni = $row['uniqueid'];
$uni = str_replace(".","",$uni);
if($row['userfield']<>"") {
$detail[$row['chan1']].="<a href=\"javascript:void(0);\" onclick='javascript:playVmail(\"".$row['userfield']."\",\"play".$uni."\");'>";
$detail[$row['chan1']].="<div class='playicon' title='Play' id='play".$uni."' style='float:left;'>";
$detail[$row['chan1']].="<img src='images/blank.gif' alt='pixel' height='16' width='16' border='0'>";
$detail[$row['chan1']].="</div></a>";
$detail[$row['chan1']].="<a href=\"javascript:void(0); return false;\" onclick='javascript:downloadVmail(\"".$row['userfield']."\",\"play".$uni."\",\"$ftype\",\"$fdisplay\",\"$ftab\"); return false;'>";
$detail[$row['chan1']].="<div class='downicon' title='Download' id='dload".$uni."' style='float:left;'>";
$detail[$row['chan1']].="<img src='images/blank.gif' alt='pixel' height='16' width='16' border='0'>";
$detail[$row['chan1']].="</div></a>";
} else {
$detail[$row['chan1']].= " ";
}
$detail[$row['chan1']].= "</td>\n";
заменяем на
if ($row['recordingfile']) {
$rec_parts = explode('-',$row['recordingfile']);
$fyear = substr($rec_parts[3],0,4);
$fmonth = substr($rec_parts[3],4,2);
$fday = substr($rec_parts[3],6,2);
$monitor_base = $amp_conf['MIXMON_DIR'] ? $amp_conf['MIXMON_DIR'] : $amp_conf['ASTSPOOLDIR'] . '/monitor';
$recordingfile = "$monitor_base/$fyear/$fmonth/$fday/" . $row['recordingfile'];
if (!file_exists($recordingfile)) {
$recordingfile = '';
$detail[$row['chan1']].= "\n<td>";
}
else {
$detail[$row['chan1']].= "\n<td style='text-align: center;' title=\"$row[recordingfile]\"><a href=\"".$PHP_SELF."?getRec=".base64_encode($recordingfile)."\" target=\"_blank\"><img src=\"images/asternic_playicon.png\" alt=\"Call recording\" /></a>";
}
} else {
$recordingfile = '';
$detail[$row['chan1']].= "\n<td>";
}
$detail[$row['chan1']].= "</td>\n";
Таким образом, в ячейке таблицы вместо вывода голосовой почты мы сделали проверку на наличие записи данного звонка и в случае её нахождения вывод небольшой иконки «Play» с ссылкой, закодированной в base64, на сам файл аудиозаписи.
Внимательный читатель заметил, что в формируемой ссылке есть переменная GET-запроса под названием getRec. Так как веб-сервер не имеет доступа к каталогу с аудиозаписями, мы отдаём файл через php, а для этого в конце файла functions.inc.php мы делаем проверку на наличие переменной getRec, в случае наличия которой мы обращаемся к функции, отдающей файл
Добавляем код в самый конец файла до, само собой, закрывающего php-тега "?>"
function recordfile_uri($path) {
$size = filesize($path);
$name = basename($path);
$extension = strtolower(substr(strrchr($name,"."),1));
// This will set the Content-Type to the appropriate setting for the file
$ctype ='';
switch( $extension ) {
case "WAV":
$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: //not downloadable
// echo ("<b>404 File not found! foo</b>");
// TODO: what to do if none of the above work?
break ;
}
$fp=fopen($path, "rb");
if ($size && $ctype && $fp) {
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: audio file");
header("Content-Type: " . $ctype);
header("Content-Disposition: attachment; filename=" . $name);
header("Content-Transfer-Encoding: binary");
header("Content-length: " . $size);
$chunksize = 1*(1024*1024);
while (!feof($fp)) {
$buffer = fread($fp, $chunksize);
echo $buffer;
ob_flush();
flush();
}
fclose($fp);
}
}
if(isset($_GET['getRec'])){
recordfile_uri(base64_decode($_GET['getRec']));
die();
}
Done!
Все довольны и счастливы — ведь теперь можно легко скачать запись разговора и прослушать её локально в аудиоплеере.