📜 ⬆️ ⬇️

"Finishing" Asterisk CDR Viewer for yourself

image

“I’m a professional because I’m not lazy about looking for information on google,” a colleague told me once.

And I was too lazy and began to “finish” the CDR Viewer for myself, without even looking at this .
And maybe not in a lazy business, it was just interesting ... in general, what came of it can be viewed under the cut :)

')
Disputes about whether it is better to use as an office PBX - asterisk (with or without a web interface, although this is a separate topic for disputes) or some kind of Panasonic box, which has been unmeasured to the market - have not subsided yet, but the topic is not about that, for myself, I have long been determined. I would like to share with the community my own way of giving the interface of viewing statistics an additional functional.

As a “test subject,” I used FreePBX Distro (FreePBX 2.11, Asterisk 11, CentOS 6.5), downloaded from the project’s official website . The choice was dictated by the fact that the developers of FreePBX have already taken care of screwing the database to Asterisk and the structure of the storage of records in general suits me. Although the procedure of “screwing” MySQL or some other database to Asterisk was described more than once or twice, which you can read about, for example, here , in order to save time, I decided not to do it.

The Asterisk CDR Viewer was taken as a basis (if you don’t need some super-wise reports, then you’ll have some pretty useful statistics), you can download it here .

Installing the CDR Viewer does not seem to be a non-trivial task.

Go to the directory we need, download the archive, extract the files from the archive:

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 


We transfer the alias file to the folder with apache2:
 cp /var/www/html/asterisk-cdr-viewer/contrib/httpd/asterisk-cdr-viewer.conf /etc/apache2/conf.d/asterisk-cdr-viewer.conf 


Change the settings for connecting to the database for Asterisk-CDR-viewer

 cd /var/www/asterisk-cdr-viewer/include/ vim config.inc.php 


You need to change the parameters in accordance with the current configuration of your database:

$ db_user = '[MySQL user]';
$ db_pass = '[MySQL password]';
$ db_name = '[Base name]';

We restart the web server:

 service apache2 restart 


Now in the browser typing [address of the asteridk server] / acdr / we get to the statistics page.

The first thing I wanted to do was screw the authorization to view this very statistics, for this we use htpasswd.
If not installed -
 aptitude install apache2-utils 


Go to / etc / apache2 and create a user / password for statistics:
 htpasswd -c passwordfile username 


Enter the password in the dialog that htpasswd offers and get the file “passwordfile” with the username “username” and the generated encrypted password.

Next, in /etc/apache2/conf.d, we modify asterisk-cdr-viewer.conf, uncommenting the authorization lines, as a result we get:

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


Restart apache2 and at the entrance to the page we see the authorization window:

image

The next thing that was done was listening to conversations from the web interface.

1) To listen to calls, add two icons to the / var / www / asterisk-cdr-viewer / templates / images ( play and stop ) directory

2) Add to /var/www/asterisk-cdr-viewer/templates/header.tpl.php declare js-function to optimize performance;

The result is:

 <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)
Modify /var/www/asterisk-cdr-viewer/include/functions.inc.php, modifying the echo constructions: add a small piece of the necessary markup to the speaker icon
 <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('Ymd G:i:s', $row['calldate']); $recorded_file = date_format($record_datetime, 'Ymd/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); } ?> 



four)
We supplement the style file /var/www/asterisk-cdr-viewer/style/screen.css

 /* 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; } 



five)
We supplement the file /var/www/asterisk-cdr-viewer/download.php (processing range requests for audio files)


 <?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(); ?> 




As a result, we are able to listen to conversations in the web interface (you can scroll the scroll slider)



I hope someone will come in handy :)

Source: https://habr.com/ru/post/241622/


All Articles