Как установить PHP для работы с Asterisk Gateway Interface (AGI)


1. Среда PHP

Первое правило бизнеса – быть осведомленным о среде PHP. Я НЕ говорю, что вы должны изменить нечто, но вы должны быть осведомленными о ней, возможно некоторое отчаяние, особенно когда вы в гуще вещей. На Debian вам сразу возможно надо получить “php4-cli”, так как типичная усиановка PHP4 предназначается только для сети.

CLI версии CGI

Я наконец-то ухитрился найти проблему с моим PHP AGI скриптом! Вероятно, на моей машине было 2 версии установленных PHP. Одна для CGI и другая для CLI. Не зная, как провести тестирование моего скрипта, я вызsвал версию CLI (/usr/local/bin/php), несмотря на то, что PHP вызывал версию CLI (/usr/local/bin/php). Это повернулось так, что мой скрипт не будет запускаться на CLI версии PHP… Интересно, не так ли?

Да, будьте осведомлены, что завися от ваших настроек, Apache может как читать php.ini, так и заместить ваш сетевой php.ini.
Еще: Используя неправильную версию PHP, может вызвать проблемы при попытки чтения канальных/диалплановских переменных в вашем PHP скрипте, также проверка, если вам надо, например, “#!/usr/bin/php-cgi –q” или “#!/usr/bin/php –q” в первой строке.


Посмотрите на ваш php конфиг файл (в /etc/php.ini или /usr/local/etc/php.ini) для следующего:


ob_implicit_flush(false);
set_time_limit(5);
; error_log = filename
error_reporting(0); //добавлено пользователем: демокрит


Первая строка, ob_implicit_flush-, показывает, должен ли php буферизовать выходные данные; в случае Asterisk agi, если вы буфферизуете выходные данные, Астериск АТС не получит ваши команды долгое время, до тех пор пока вы не очистите ваш буфер вручную (смотри ниже)

Второй элемент, set_time_limit, это максимально возможное время для выполнения вашего php скрипта. Большинство Asterisk agi скриптов будут запускаться без разумного времени, но если у вас есть очень длинный скрипт, который производит необычные ошибки, возможно, что ваш скрипт был завершен преждевременно.

Третий элемент – error_log; важен для отладки, но убийца для промышленных систем. Он может быть выключен по умолчанию или вы можете намеренно выключить его и не забыть.

Четвертый элемент, error_repоrting(0), говорит PHP не сообщать об ошибках в течении времени выполнения скрипта. Это важно, потому что любые ошибки (и некоторые предупреждения), которые создал ваш скрипт, будут посланы к STDOUT, тому же самому буферу, к которому посылаются все AGI команды. Поэтому, любые ошибки в вашем скрипте будут посланы к AGI и астреиск будет пытаться прочесть их как AGI команды. В моем эксперименте, это поведение будет выполнять все последующие команды, после того, как ошибка скрипта (неизвестная для вас) вернет “510 invalid command”…
after a script error (unknown to you), return '510 invalid command', although commands like 'EXEC Playback' will actually still play back a sound file. For important AGI commands like 'GET DATA my_file' and 'GET DIGIT my_file', the Asterisk CLI will report "Playing File my_file" but the sound file will not be heard on the channel and no DTMF input can be received by the caller. There is also no way for the script to tell what DTMF keys were pressed since the command returns a "510 invalid' string. An alternative to using error_reporting(0) at the beginning of your script to help you debug would be to prepend your suspected error-generating commands in your script with @, such as

$rst = @mysql_query($strSQL);
--OR--
$fp = @fopen("some non-existant file", "r");

The @ will suppress any errors or warning generated by the statement.
Edit

2.Директория скрипта

Поместите ваши скрипты в диреторию /var/lib/asterisk/agi-bin/ и получите их работу сперва перед тем, как вы что-нибудь вообразите.

3.Выполнение разрешения на файлов скрипта

Помните к chmod ВСЕ ваши скрипты к 733 как ниже показано:

chmod 755 *.php

4. Интерфейс для команды shell

2 первые строки в вашем скрипте должны быть следующие (при условии что ваша php bindery находится в /usr/bin; дважды проверьте это):

#!/usr/bin/php -q
  • Замечание: нет промежутков и нет пробельного символа (кроме одиночного /n) между линиями 1 и 2. Иначе странные вещи будут посылаться к stdout и разрушат ваш день!
  • Замечание: Если у вас возникают проблемы с чтением диалплановских переменных, вам надо использовать “#!/usr/bin/php-cgi –q” вместо
  • Флаг -q НЕОБХОДИМ для хорошего выполнения AGI скриптов. Это говорит PHP запрещать HTML заголовки и другие ненужные данные (используется только в конъюнкции с web сервером), которые будут серьезно наводить беспорядок в вашем скрипте! Заголовки интерпретируются астериском AGI как команды, т.к. они появляются на буфере STDOUT , and will make all successive AGI commands return "510 Invalid Command", выполняя AGI команды подобные GET DATA бесполезный, потом DTMF цифры вызова typed не могут быть прочитаны из строки возврата.

5. Открытие входящие и исходящие каналы

Далее, вы должны использовать fopen() для создания всех необходимых дескрипторов. Я знаю, что много версий php имеют измененные признаки для того, чтобы обращаться с потоками stdio, но fopen() будет работать с большинством новых и старых версий, делающими ваши скрипты более портативными, и файл php.ini не доставляет вам неприятности. Кроме того, fopen() не представляет неудобства для использования с * agi, поэтому используйте его.

$stdin = fopen('php://stdin', 'r');
$stdout = fopen('php://stdout', 'w');
$stdlog = fopen('my_agi.log', 'w');

Замечание: STDOUT уже открыт внутри php 4.3.0 и выше, поэтому можно делать fwrite(STDOUT,"blah");

6. Handle ввод среды Астериска

Asterisk всегда отсылает пучок в каждый момент времени к agi, вызываемый как показано ниже:

agi_request: test.php
agi_channel: Zap/1-1
agi_language: en
agi_type: Zap
agi_callerid:
agi_dnid:
agi_context: default
agi_extension: 1000
agi_priority: 1

Сохраните инфу с этой функцией (или пример ниже):


while (!feof($stdin)) {
$temp = fgets($stdin);
$temp = str_replace("\n","",$temp);
$s = explode(":",$temp);
$agivar[$s[0]] = trim($s[1]);
if (($temp == "") || ($temp == "\n")) {
break;
}
}


У вас будет массив переменных, названный $agivar. Возможные опции…
• agi_request - Имя файла agi
• agi_channel – Порождающий канал (Ваш телефон)
• agi_language - Типичный “en”
• agi_type – Порождающий канал типа, например, “sip” или “zap”
• agi_uniqueid – Уникальный ID для вызова
• agi_callerid - ID вызывающего, например, Joe Soap <1234>
• agi_context – Иточник контекста
• agi_extension – Номер вызывающего
• agi_priority – Приоритет, он может выполняться в dial plan
• agi_accountcode – Учетный код канала источника, например, joesoap1

Для использования простого вызова переменной и ключа… например. Если вы хотите, чтобы вызывающий номер просто использовал переменную $agivar[agi_extension] в вашем PHP коде…

Другие AGI заголовки, прермещенные Астериском (входы среды)

• agi_calleridname – Имя вызывающего, например, Joe Soap
• agi_callingpres - Представление для callerid в ZAP канале
• agi_callingani2 - неизвестно
• agi_callington - неизвестно
• agi_callingtns - неизвестно
• agi_dnid – id номер dialed
• agi_rdnis - Посланное DNIS число
• agi_enhanced – Значение флага – 1.0, если стартует как EAGI скрипт

Замечание: если id номер вызывающего не установлен в sip.conf, agi_callerid будет иметь то же значение, что и agi_calleridname.

7. Начало использования AGI канала

Это точка, где вы можете начать разговор с астериском. Используйте fputs для того, чтобы отправить * agi команды. Вы можете также использовать echo команду.

fputs($stdout,"SAY NUMBER 1234567 '79#' \n");
fflush($stdout);

• Замечание: Используйте fflush() regardless of php.ini setting just to be safe. If you don't fflush() (авто или вручную), Asterisk не будет принимать команду и ваша прога будет stuck там до таймаута.