Все слышали про мини-АТС нового поколения имя которой Asterisk. Так уж случилось что я заинтересовался этой системой и даже успел сделать пару коммерческих проектов.
В этой статье я хочу немного расказать об интеграции звездочки с языком программирования php. При этом мы будем использовать класс phpagi.
Под катом я приведу примеры использования нескольких методов этого класса которые помогли мне.
Первым делом качаем последнюю версию phpagi и подключаем его в наш проект, а так же правим файл /etc/asterisk/manager.conf
;
; Asterisk Call Management support
;
[general]
enabled = yes ; Включаем asterisk manager interface (AMI)
port = 5038
bindaddr = 127.0.0.1 ; Доступ только с локалхоста для безопастности
webenabled = no
; Each user has a section labeled with the username
; so this is the section for the user named "mark"
[user] ; имя пользователя для конекта
secret = qwerty ; пароль
deny=0.0.0.0/0.0.0.0 ; еще запреты на коннект
permit=127.0.0.1/255.255.255.0
read = system,call,log,verbose,command,agent,user,originate ; Права пользователя на выполнение комманд
write = system,call,log,verbose,command,agent,user,originate
В архиве с phpagi есть файл phpagi.conf, его нужно скопировать в /etc/asterisk и естественно исправить логин и пароль.
Теперь мы можем смело подключатся к AMI из php скрипта, например так:
include('phpagi.php');
$manager = new AGI_AsteriskManager();
$manager->connect(); // если нет файла phpagi.conf то тут можно указать хост, логин, пароль.
Первым делом я хотел бы расказать о написании простейшего монитора событий asterisk на php.
Как мне кажется это самая полезная функция класса phpagi.
Вот такой у меня вышел монитор событий:
function dump_events($ecode,$data,$server,$port) {
$date_now = date('Y-m-d');
$time_now = date('H:i:s');
echo "$time_now : received event '$ecode' from $server:$portn";
print_r($data);
}
include('phpagi.php');
$manager = new AGI_AsteriskManager();
$manager->connect();
$manager->add_event_handler('*', 'dump_events'); // цепляем хендлер на все события которые
// поступают из AMI и передаем управление
// функции описанной выше
$manager->wait_response(); // очень полезная вещь, благодаря этой функции скрипт будет
// ждать событий и не стопится в отличии от sleep()
$manager->disconnect();
Используя этот хендлер можно выполнять какие нибудь действия в зависимости от полученного эвента, например проверять баланс на sim-карте вставленной в модем huawei и подключенной через chan_dongle.
Приведу пример своей реализации используя метод Command:
Первый скрипт ловит событие newussd
function donglenewussd($ecode, $data) {
if($model = Trunk::model()->find('value = :value', array(
':value' => $data['Device']))){
if(!empty($data['MessageLine0'])){
$balance = explode(' ', $data['MessageLine0']);
switch($model->carrier){
case '0':
break;
case '1':
$model->balance = $balance[0];
$model->save();
echo $balance[0]."n";
break;
case '2':
$model->balance = $balance[2];
$model->save();
echo $balance[2]."n";
break;
case '3':
preg_match('/[+-]?d+.?d*/', $balance[1], $match);
$model->balance = $match[0];
$model->save();
echo $match[0]."n";
break;
}
}
}
}
$manager = new AGI_AsteriskManager();
$manager->connect();
$manager->add_event_handler('donglenewussd', 'donglenewussd');
$manager->wait_response();
$manager->disconnect();
Этот скрипт получает событие donglenewussd в котором нам приходит ответ от оператора на основе которого мы заносим в базу информацию о состоянии баланса.
Следующий скрипт будет по крону скажем раз в час отправлять ussd запрос по сотоянию баланса.
$manager = new AGI_AsteriskManager();
$manager->connect();
$trunks =Trunk::model()->findAll();
foreach($trunks as $trunk){
switch($trunk->carrier){
case '1':
$manager->Command('dongle ussd '.$trunk->value.' *101#');
break;
case '2':
$manager->Command('dongle ussd '.$trunk->value.' *111#');
break;
case '3':
$manager->Command('dongle ussd '.$trunk->value.' *111#');
break;
}
}
$manager->disconnect();
Как вы могли заметить я испоьзую yii framework для своих проектов, у меня есть модель в которой хранятся настройки модема (системное имя, оператор, баланс, состояние и т.д.)
Данный пример работает с Украинскими операторами (МТС, Киевстар и Life)
И на десерт я хочу Вам расказать про метод Originate. Вы еще используете call файлы? тогда мы идем к Вам.
Очень полезная функция которая инициирует звонок используя AMI, а не старый дедовский способ путем копирования call файла в директорию /var/spool/asterisk/outgoing
Все параметры передаваемые в функцию почти такие же как и параметры call файла:
$manager->Originate(
'Канал для вызова, например SIP/1001',
'Экстеншн для диалплана',
'Контекст диалплана',
'Приоритет контекста диалплана',
'Или приложение астериска для запуска, например playback',
'параметры приложения, например пусть к аудиофайлу',
'таймаут',
'Номер абонента от которого идет вызов или имя',
'переменные для диалплана',
'account - незнаю зачем, не использовал еще',
'Синхронный или асинхронный запрос (ждет или не ждет ответа о состоянии запроса)',
'actionid - тоже пока не использовал'
);
Ну а что делать с этой функцией я думаю Вы придумаете сами, а если совместить ее с менеджером событий то можно еще и получить очет о выполнении исходящего звонка.
Надеюсь моя статья окажется кому нибудь полезной, так как я не нашел упоминание phpagi на хабре, да и вообще с трудом нашел хоть какие нибудь примеры использования кроме тех что идут в архиве с библиотекой.
Если у кого то есть другие методы работы с этой библиотекой очень буду рад почитать о них в коментариях.
Автор: MrZaYaC