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

Реализация подрузки информации о клиенте через API

Давно хотел, чтобы мои операторы выдели информацию о клиенте и знали уже перед самим входящим звонком — кто звонит. Но покупать готовые модуля за басновловные деньги не хотелось.

Вариант нашелся сам…

Так как у нас звёздочка в мир не смотрит, то очевидно что все выполняется на сервере с астериском.

Итак, нашел библиотеку PHP Tail, спасибо автору Тошио Такигучи.

Задумка такова, php грепать логи звездочки на предмет входящего звонка, смотреть номер телефона входящего звонка, далее скармливать номер, в нашем случае самописному биллингу.
Полученный ответ, то ли это инфа о клиенте, то ли что номер не найден ни в одной карточке клиента выводить на экран, приостановить выполнение до нажатия оператором кнопки Далее (для того чтобы он успел поработать с информацией).

Итак выполнение:

1. В библиотеке от Тошио Такигучи в файле Log.php необходимо заменить строку

$tail = new PHPTail("/path/to/log");

на

$tail = new PHPTail("/var/log/asterisk/full");

ну или другой адрес если у Вас лог пишется в другой файл.

2. Основные телодвижения будут происходить с файлом PHPTail.php.

В function updateLog() необходимо задать четкое понимание входящего звонка и номера телефона этого звонка.

Реализовано так:


if (value.includes('macro-user-callerid') && value.includes('Local/'+grep) && value.includes('CALLERID(name)=')) {
    var str = value.split('CALLERID(name)=');
    var num = str[1].replace(/\D+/g, '')
......
}

Далее ajax-ом передаем полученный номер телефона на другой php-файл где и происходит обращение к api биллинга.


$.ajax({
   type: "POST",
    url: "curl.php?num="+num,
    success: function(data) {
        if (data!=''){
           var res = JSON.parse(data);
           // далее работаем с полученными данными
           ...
           clearInterval(intervalID); //останавливаем и ждем действия от оператора
          }
         else {
             clearInterval(intervalID); //останавливаем и ждем действия от оператора
             // Для того чтобы оператор мог подвязать этот номер телефона к карточке клиента
          }                                          

Полный код PHPTail.php


<?php

class PHPTail {
        private $log = "";
        private $updateTime;
        private $maxSizeToLoad;
        public function __construct($log, $defaultUpdateTime = 2000, $maxSizeToLoad = 2097152) {
                $this->log = $log;
                $this->updateTime = $defaultUpdateTime;
                $this->maxSizeToLoad = $maxSizeToLoad;
        }
        public function getNewLines($lastFetchedSize, $grepKeyword, $invert) {
                clearstatcache();
                $fsize = filesize($this->log);
                $maxLength = ($fsize - $lastFetchedSize);
                if($maxLength > $this->maxSizeToLoad) {
                  return json_encode(array("size" => $fsize, "data" => array("ERROR: PHPTail attempted to load more (".round(($maxLength / 1048576), 2)."MB) then the maximum size (".round(($this->maxSizeToLoad / 1048576), 2)."MB) of bytes into memory. You should lower the defaultUpdateTime to prevent this from happening. ")));
                }
                $data = array();
                if($maxLength > 0) {
                    $fp = fopen($this->log, 'r');
                    fseek($fp, -$maxLength , SEEK_END);
                    $data = explode("\n", fread($fp, $maxLength));
                }
                if($invert == 0) {
                    $data = preg_grep("/$grepKeyword/",$data);
                }
                else {
                    $data = preg_grep("/$grepKeyword/",$data, PREG_GREP_INVERT);
                }
                if(end($data) == "") {
                    array_pop($data);
                }
                return json_encode(array("size" => $fsize, "data" => $data));
        }
        public function generateGUI() {
                ?>
                <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
                <html xmlns="http://www.w3.org/1999/xhtml">
                        <head>
                                <title>Info about called</title>
                                <link rel="shortcut icon" href="/admin/images/favicon.ico">
                                <meta http-equiv="content-type" content="text/html;charset=utf-8" />
                                <link type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/flick/jquery-ui.css" rel="stylesheet"></link>
                                <style type="text/css">
                                   #grepKeyword, #settings {font-size: 80%;}
                                   .float {background: #f5f5f5;z-index: 9999;border-bottom: 1px solid black;padding: 10px 0 10px 0;margin: 0px;height: 30px;width: 100%;text-align: left;}
                                </style>
                                <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
                                <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js"></script>
                                <script type="text/javascript">
                                        /* <![CDATA[ */
                                        lastSize = <?php echo filesize($this->log); ?>;
                                        grep = "";
                                        invert = 0;
                                        documentHeight = 0;
                                        scrollPosition = 0;
                                        scroll = true;
                                        $(document).ready(function(){
                                                $( "#settings" ).dialog({
                                                        modal: true,
                                                        resizable: false,
                                                        draggable: false,
                                                        autoOpen: false,
                                                        width: 590,
                                                        height: 270,
                                                        buttons: {
                                                                Close: function() {
                                                                        $( this ).dialog( "close" );
                                                                }
                                                        },
                                                        close: function(event, ui) {
                                                                grep = $("#grep").val();
                                                                invert = $('#invert input:radio:checked').val();
                                                                $("#grepspan").html("Ваш номер телефона: \"" + grep + "\"");
                                                                $("#invertspan").html("Inverted: " + (invert == 1 ? 'true' : 'false'));
                                                        }
                                                });
                                                $('#grep').keyup(function(e) {
                                                        if(e.keyCode == 13) {
                                                                $( "#settings" ).dialog('close');
                                                        }
                                                });
                                                $("#grep").focus();
                                                $("#grepKeyword").button();
                                                $("#grepKeyword").click(function(){
                                                        $( "#settings" ).dialog('open');
                                                        $("#grepKeyword").removeClass('ui-state-focus');
                                                });
                                                $(window).scroll(function(e) {
                                                    if ($(window).scrollTop() > 0) {
                                                        $('.float').css({
                                                            position: 'fixed',
                                                            top: '0',
                                                            left: 'auto'
                                                        });
                                                    } else {
                                                        $('.float').css({
                                                            position: 'static'
                                                        });
                                                    }
                                                });
                                                $(window).resize(function(){
                                                        if(scroll) {
                                                                scrollToBottom();
                                                        }
                                                });
                                                $(window).scroll(function(){
                                                        documentHeight = $(document).height();
                                                        scrollPosition = $(window).height() + $(window).scrollTop();
                                                        if(documentHeight <= scrollPosition) {
                                                            scroll = true;
                                                        }
                                                        else {
                                                            scroll = false;
                                                        }
                                                });
                                                scrollToBottom();

                                        });
                                        function scrollToBottom() {
                                            $('.ui-widget-overlay').width($(document).width());
                                            $('.ui-widget-overlay').height($(document).height());
                                            $("html, body").scrollTop($(document).height());
                                            if($( "#settings" ).dialog("isOpen")) {
                                                 $('.ui-widget-overlay').width($(document).width());
                                                 $('.ui-widget-overlay').height($(document).height());
                                                 $( "#settings" ).dialog("option", "position", "center");
                                            }
                                        }
                                        function updateLog() {
                                          $('#start').css('opacity','0.2');
                                          $('#start').css('pointer-events','none');
                                          $("#results").empty();
                                          $.getJSON('?ajax=1&lastsize='+lastSize + '&grep='+grep + '&invert='+invert, function(data) {
                                            lastSize = data.size;
                                            $.each(data.data, function(key, value) {
                                              if (value.includes('macro-user-callerid') && value.includes('Local/'+grep) && value.includes('CALLERID(name)=')) {
                                                var str = value.split('CALLERID(name)=');
                                                var num = str[1].replace(/\D+/g, '');
                                                $.ajax({
                                                  type: "POST",
                                                  url: "curl.php?num="+num,
                                                  success: function(data) {
                                                    if (data!=''){
                                                      var res = JSON.parse(data);
                                                      var text='<form><h2>Информация о входящем звонке</h2><h3><a href="'+res.contract_url+'" target="_blank" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" style="font-size:80%;"><span class="ui-button-text">Открыть в биллинге</span></a></h3><fieldset id="user-details"><label for="tel">Телефон:</label><input type="text" name="tel" value="'+num+'"/><label for="addres">Адрес:</label><input type="text" name="addres" value="'+res.adress.replace("'", "")+'"/><label for="fio">ФИО:</label><input type="text" name="fio" value="'+res.fio+'"  /><label for="lc">Счёт:</label><input type="text" name="lc" value="'+res.lc+'"  /><label for="balance">Баланс:</label><input type="text" name="balance" value="'+res.balance+'"  /></fieldset>';
                                                      text+='<div style="width: 100%;text-align: right;float: left;"><a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" onclick=\'intervalID = setInterval("updateLog()", 1000)\'><span class="ui-button-text">Далее</span></a></div></form>';
                                                      $("#results").html(text);
                                                      clearInterval(intervalID);
                                                    }
                                                    else {
                                                      clearInterval(intervalID);
                                                      text='<form id="add_new"><h2>Информация о входящем звонке</h2> <h3 id="add_new_result">Клиент не найден</h3> <div id="add_cont"><label for="tel">Телефон:</label><input type="text" id="tel_update_tel" name="tel" value="'+num+'"/><label for="lc">Счёт:</label><input type="text" id="tel_update_lc" name="lc"/><a id="addnum_to_contract" onclick="update_num()" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only"><span class="ui-button-text">Добавить телефон к учетной записи</span></a></div><a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" onclick=\'intervalID = setInterval("updateLog()", 1000)\'><span class="ui-button-text">Далее</span></a></form>';
                                                      $("#results").html(text);
                                                    }
                                                  }
                                                });
                                              }
                                            });
                                            if(scroll) {
                                              scrollToBottom();
                                            }
                                          });
                                        }
                                        /* ]]> */
                                </script>
                                <script type="text/javascript">
                                  function update_num(){
                                    var tel=$("#tel_update_tel").val();
                                    var lc=$("#tel_update_lc").val();
                                      $.ajax({
                                        type: "POST",
                                        url: "curl_send_phone.php?tel="+tel+"&lc="+lc,
                                        success: function(response){
                                          var res2 = JSON.parse(response);
                                          if (res2.result) {
                                            if (res2.result==true) {
                                              $("#add_cont").fadeOut();
                                              $("#add_new_result").html('Номер успешно добавлен к карточке абонента');
                                            }
                                            else {
                                              $("#add_cont").fadeOut();
                                              $("#add_new_result").html('Произошла ошибка, попробуйте позже');
                                            }
                                          }
                                        }
                                      });
                                  }
                                </script>
                                <link href='//fonts.googleapis.com/css?family=Yanone+Kaffeesatz' rel='stylesheet' type='text/css' />
                                <style>
                                  body {margin: 0 auto;background: #f5f5f5;color: #555;width: 800px;font-family: 'Yanone Kaffeesatz', arial, sans-serif;}
                                  h1 {color: #555;margin: 0 0 20px 0;}
                                  label {font-size: 20px;color: #666;}
                                  fieldset {border: none;}
                                  #user-details {float: left;width: 40%;}
                                  #requests-message {float: left;width: 45%;}
                                  #user-message {float: left;width: 100%;}
                                  textarea {width: 390px;height: 175px;}
                                  form {float: left;border: 1px solid #ddd;padding: 30px 40px 20px 40px;margin: 75px 0 0 0;width: 715px;background: #fff;-webkit-border-radius: 10px;-moz-border-radius: 10px;border-radius: 10px;background: -webkit-gradient(linear, 0% 0%, 0% 40%, from(#EEE), to(#FFF));background: -moz-linear-gradient(0% 40% 90deg,#FFF, #EEE); -webkit-box-shadow:0px 0 50px #ccc;-moz-box-shadow:0px 0 50px #ccc;box-shadow:0px 0 50px #ccc;}
                                  input, textarea {padding: 8px;margin: 4px 0 20px 0;background: #fff;width: 220px;display:block;font-size: 14px;color: #555;border: 1px #ddd solid;-webkit-box-shadow: 0px 0px 4px #aaa;-moz-box-shadow: 0px 0px 4px #aaa;box-shadow: 0px 0px 4px #aaa;-webkit-transition: background 0.3s linear;}
                                  input{width:90%}
                                  input:hover, textarea:hover {background: #eee;}
                                  #user-message>label {display: block;}
                                  </style>
                        </head>
                        <body>
                          <div id="settings" title="Введите Ваш внутренний номер телефона">
                            <input id="grep" type="text" value=""/>
                              <div id="invert" style="display:none">
                                <input type="radio" value="1" id="invert1" name="invert" /><label for="invert1">Yes</label>
                                <input type="radio" value="0" id="invert2" name="invert" checked="checked" /><label for="invert2">No</label>
                              </div>
                            </div>
                            <div class="float" >
                              <button id="grepKeyword">Внутренний номер</button>
                              <span style="display:none">Tailing file: <?php echo $this->log; ?></span>  <span id="grepspan" >Ваш номер телефона: ""</span> <span style="display:none" id="invertspan">Inverted: false</span>
                              <a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" style="font-size:80%;float:right" onclick='intervalID = setInterval("updateLog()", 1000)' id="start"><span class="ui-button-text">Начать</span></a>
                            </div>
                            <div id="results">

                            </div>
                            <script type="text/javascript">
                              function update_num(){
                                var tel=$("#tel_update_tel").val();
                                var lc=$("#tel_update_lc").val();
                                  $.ajax({
                                    type: "POST",
                                    url: "curl_send_phone.php?tel="+tel+"&lc="+lc,
                                    success: function(response){
                                      var res2 = JSON.parse(response);
                                      if (res2.result) {
                                        if (res2.result==true) {
                                          $("#add_cont").fadeOut();
                                          $("#add_new_result").html('Номер успешно добавлен к карточке абонента');
                                        }
                                        else {
                                          $("#add_cont").fadeOut();
                                          $("#add_new_result").html('Произошла ошибка, попробуйте позже');
                                        }
                                      }
                                    }
                                  });
                              }
                            </script>
                        </body>



                </html>
                <?php
        }
}

3. Создаем файлы которые и будут отправлять запросы api
curl.php — получает инфу о клиенте


<?php
$num = $_REQUEST['num'];
if ($_REQUEST['num']!='')
{
  $url = "адрес к api";
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  $result = curl_exec($ch);
  curl_close($ch);
  print($result);
}
 ?>

curl_send_phone.php — записывает номер телефона в карточку клиента


<?php

if ( ($_REQUEST['tel']!='') && ($_REQUEST['uid']!='') )
{
  $tel = $_REQUEST['tel'];
  $uid = $_REQUEST['uid'];

  $url = "адрес к api";
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  $result = curl_exec($ch);
  curl_close($ch);
  print($result);
}
 ?>

4. Кладем эти 4-ре файла в /var/www/html/ (ну или в другое место, в зависимости от Вашей конфигурации Asterisk-а)

P.S. Не пишите, что мол есть AMI, оно не столь гибкое.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.