FreePBX, Asternic CDR Reports и записи звонков
Эта статья на Хабре https://habr.com/ru/post/244321/
Версии ПО
FreePBX 2.11.0.41
Asternic CDR Reports 1.5.1
Введение
Классический CDR Reports, “идущий в комплекте” с FreePBX умеет делать отчёты с проигрыванием аудиозаписи, если она велась, но не умеет разграничивать доступы по Extension`ам (Extension Range, который задаётся при создании новой учётной записи админа).
Модуль Asternic CDR Reports учитывает это, но не выводит аудиофайл.
Исправим это.
Информация о звонках в Asterisk`е хранится в mysql базе данных asteriskcdrdb, таблица cdr.
<?php
$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 = '';
}
...
Из вышеприведённого кода файла page.cdr.php модуля обычного CDR Reports ясно, что всё, что нам нужно - это прочитать значение ячейки recordingfile (там хранится строка “файл.wav”) и добавить к нему полный путь к файлу, выдираемый, кстати, из самого же имени файла
<?php
$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'];
$amp_conf - глобальный массив, из которого берутся пути к записям. Поэтому, если менялся путь по-умолчанию, всё ок.
Практика
В файле functions.inc.php модуля Asternic ищем строку
<?php
$query.= "billsec,duration,duration-billsec as ringtime,src,";
добавляем к запросу recordingfile
<?php
$query.= "billsec,duration,duration-billsec as ringtime,src,recordingfile,";
Затем вместо
<?php
$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";
ставим
<?php
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";
По-умолчанию в ячейке Listen в Asternic выводится запись голосовой почты, но нас-то интересует запись звонка, поэтому меняем содержимое всей ячейки.
В конце файла добавляем ещё функцию, отдающую файл двоичными данными (т.е. никакой apache не имеет доступа к каталогу записи, а отдаётся всё через 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();
}