[Asterisk-Users] AGI and PHP

hkirrc.patrick hkirrc.patrick at ptl.net
Mon Nov 10 22:48:47 MST 2003


i've just spent the pass 2 days trying to get AGI to work with PHP;

i made a lot of silly mistakes along the way which could have been
avoided if only there were some kinda howto or samples.  at the risk
of looking stupid, i decided to shared my experience in hopes that
it might help some newbie get going with PHP.

1. first order of business is to be aware of your php environment; i m
   NOT saying you should change anything but you should be aware
   of it as it may spare you some frustration along the way especially
   when you are in the thick of things.  look in your php config file
   (usually in  /etc/php.ini) for the following:

    ob_implicit_flush(false);
    set_time_limit(5);
    ; error_log = filename

   the first item shows whether php should buffer output; in the case
   of * agi, if you buffer your output, * will not get your instruction 
for a
   long time unless you flush the buffer manually (see below)

   the second item is the max. allowable time to run your php script.  most
   * agi script will run within a reasonable time but if you have a very
   lengthy script that is producing strange errors, it is possible that your
   script was terminated prematurely.

   the third item is Log; great for debug but a killer for production 
system.
   it might have been turned off by default or you may have turn it off
   on purpose and don't remember.

2. put your scripts in the following directory and get it working first
   before you do anything fancy

    /var/lib/asterisk/agi-bin/

3. remember to chmod ALL your script to 755 as follows:

   chmod 755 *.php

4. the very first 2 lines in your script should be as follows: 
   (assuming that your php bindery is in /usr/bin; double check now)

   #!/usr/bin/php -q
   <?php

   notice: there are no gaps and no white space char (except a single \n)
   between lines 1 and 2.  otherwise strange things will be sent to stdout
   and ruin your day!

5. next, you should use fopen() to create all your needed handles.  i know
   different versions of php have varying features to deal with stdio 
streams
   but fopen() will work with most new and old versions making your scripts
   more portable and you don't have to fidget with the php.ini file. 
 besides,
    fopen() does not pose any inconvenience for use with * agi, so use it.

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

6. * always sends a bunch of info each time agi is called as follows:

     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
                  .
                  .
   if you need the info, save it; otherwise throw them away as follows:

      while(($data = fgets($stdin,1024)) != "\n")
        {
              //   codes to save the info goes here
              //   or do nothing
        }

7. this is the point where you can start talking with *.  use fputs to
   send * agi commands; some people use echo but i prefer fputs:

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

7a. use fflush() regardless of php.ini setting just to be safe, does hurt
    if you don't fflush() (auto or manual), * will not receive the command
    and your app will be stuck there until timeout.

7b. use of quotes;
       * agi command options are not optional
            i.e.  they must appear on the command string
       * some options MUST be enclosed in quotes
            e.g. <escape digits> of SAY NUMBER and SAY DIGITS
       * some options MUST NOT be enclosed in quotes
            e.g. <digit string> of SAY NUMBER and SAY DIGITS
       * some options can go either way.
       * you can use single quote where quote is needed e.g. as above
       * as a reminder, escape char such as \n in a strings within sigle 
quotes
         will not be resolved !!!!  but i'm sure you already know that.

8. next, you'll have to pick up responses from * which is pretty 
straight forward:

      $msg  = fgets($stdin,1024);
      fputs($stdlog,$msg . "\n");

9.  if your script failed for some reason (especially if you forget to 
fflush()), the process
   is actually hung in limbo;  REMEMBER to killproc your script process 
before you
   test again:

      killproc my_script.php

10. the purpose of this is to show the PHP aspects of * agi and not agi 
in general;
    there are many excellent documentation on * agi such as the following,
    you should read that as well:

       http://home.cogeco.ca/~camstuff/agi.html

11. sample.php

#!/usr/bin/php -q
<?php

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

while(($abc  = fgets($stdin,1024)) != "\n")
  {
   fputs($stdlog,$abc);
   // or parse the data for use
  }

fputs($stdout,"ANSWER\n");
fflush($stdout);
$abc  = fgets($stdin,1024);
fputs($stdlog,$abc . "\n");

fputs($stdout,"GET DATA aa-welcome '1' 1\n");
fflush($stdout);
$abc  = fgets($stdin,1024);
fputs($stdlog,$abc . "\n");

fputs($stdout,"EXEC Meetme 1234|p \n");  // <=- notice the |p in 1234|p 
being the option for meetme
fflush($stdout);
$abc  = fgets($stdin,1024);
fputs($stdlog,$abc . "\n");

exit();

?>






More information about the asterisk-users mailing list