Как стать автором
Обновить

Asternic CDR Reports. Прослушивание звонков в FreePBX с ограничением по доступу

Время на прочтение5 мин
Количество просмотров21K

Версии ПО


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!


Все довольны и счастливы — ведь теперь можно легко скачать запись разговора и прослушать её локально в аудиоплеере.
Теги:
Хабы:
Всего голосов 3: ↑3 и ↓0+3
Комментарии2

Публикации

Истории

Ближайшие события

15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань